mikoto-wordpress-nginxの調査で、type: ClusterIP + kube-vipアノテーション による手動VIP付与構成では、kube-vip自体がTCP接続をプロキシするため externalTrafficPolicyを設定しても実クライアントIPが失われることが判明。 共有Ingress Controller(Cilium組み込み等)へ移行する場合の具体的な values設定とhelm upgradeコマンド例をREADMEに追加。 クラスタ構成の調査結果をCLAUDE.mdに記録。
8.7 KiB
CLAUDE.md — WordPress Helm Chart
リポジトリ概要
Raspberry Pi などのベアメタルで稼働することを想定した、Kubernetes 上で動作する Alpine Nginx + WordPress (PHP-FPM) の Helm チャート。
- Gitea リポジトリ:
ssh://git@192.168.9.65/helmchart/wordpress - Helm リポジトリ:
https://git.cafepieters.com/api/packages/helmchart/helm
実行環境について
WordPress本体はイメージ内蔵のもの(docker.io/wordpress:<tag>-fpm-alpine)をemptyDirにコピーして使い捨てで起動し、wp-contentのみPVCで永続化する(bitnami方式)。PHPの実行環境はこのイメージに依存し、本リポジトリにPHPコードは含まれない。
Git コミット情報
| 項目 | 値 |
|---|---|
| 名前 | Claude |
| メール | claude@cafepieters.com |
| SSH キー | P:\Claude\.ssh\id_claude |
作業完了のルール(重要)
- 機能を追加・変更した場合は、必ず README.md を更新すること。 追加・変更した機能の説明を反映してから作業完了とする。
- 変更は必ず Git Commit / Push まで行うこと。 作業単位ごとにコミットし、origin(main) へ push するまでが作業完了。
- Commit メッセージに Claude クレジット(Co-Authored-By 等)を追記することは禁止。
user.name = Claudeでコミットされるため、ユーザー名で判別可能。 git pullで取り込まれた変更は必ず尊重し、revert して push することは禁止(既存の共通ルールと同じ)。
クラスタ構成メモ(実運用環境)
- ノード:
cpi11(control-plane, 192.168.9.9/物理IF)、wpi21/wpi22/wpi23(worker)。全てRaspberry Pi(Ubuntu 25.04)。 - CNI: Cilium(kube-proxyなし、eBPFベース)。
cilium-envoyPodが動作しており、Cilium組み込みIngress Controller(Envoyベース)が利用可能。 - Pod CIDR:
10.0.0.0/8系、ノードごとに/24を割り当て(例: cpi11→10.0.0.0/24、wpi22→10.0.1.0/24、wpi21→10.0.2.0/24、wpi23→10.0.3.0/24)。 - 外部公開: kube-vip(ARP方式、静的Pod
kube-vip-cpi11)。物理ルーターのグローバルIP配下、192.168.9.0/24セグメント内でVIPを払い出す。このセグメントはルーターがLAN機器(スマホ/PC等)にDHCP払い出しする範囲と重複しないよう、ルーター側で範囲を絞って共存させている。IPが希少なため濫用できない。 - 各WordPress/PHPFPMリリースは現状、
service.type: ClusterIP+kube-vip.io/loadbalancerIPs/kube-vip.io/vipHostアノテーションをHelm管理外で手動付与し、リリースごとに個別のVIPを得る運用になっている(本チャートのtemplates/service.yamlにはannotationsのテンプレート化自体が存在しないため)。- 既知の問題: この構成では、kube-vipがL2 ARP応答に加えて自前でTCPコネクションをプロキシしてしまうため、
externalTrafficPolicy(LoadBalancer/NodePort専用でありClusterIPには無効という制約とは別に、そもそもkube-vipの時点で)実クライアントIPが失われる。詳細はREADME.mdの「kube-vip等でグローバルIP/VIPが限られている環境での実IP取得(共有Ingress Controller構成)」を参照。 - 今後、実IP取得のためCilium組み込みIngress Controller(またはingress-nginx)へ移行する方針で合意済み(2026-08-08時点、ユーザーが選択)。ただし全リリース(wordpress-nginx系だけでなくphpfpm系も含む)の移行が必要な大掛かりな作業のため、本セッションではWordPressチャート側の対応(
ingress.yaml/forwardRealIPは既存機能で対応済み、README migration手順を追記)のみ実施。実際のCilium Ingress有効化・各リリースのhelm upgradeはユーザー側の作業。
- 既知の問題: この構成では、kube-vipがL2 ARP応答に加えて自前でTCPコネクションをプロキシしてしまうため、
チャート改修履歴
実IP取得の修正 + SMTP経由メール送信の追加(2026-08-08, v7.0.2-a)
背景: ルーター(グローバルIP)配下の 192.168.9.x セグメントにコントロールプレーン/ワーカーノードがあり、その上のPodでWordPressが稼働する構成において、(1) 訪問者の実IPアドレスが正しく取得できない、(2) wp_mail() によるメール送信が失敗する、という2つの不具合が報告された。
(1) 実IPアドレス取得の不具合
原因は2つ複合していた:
- Service(
LoadBalancer/MetalLB想定)はデフォルトのexternalTrafficPolicy: Clusterのため、kube-proxyが送信元IPをノード内部IPにSNATしてしまい、Nginxの$remote_addrが実IPではなくノードIPになっていた。 - 本チャートの
nginx.forwardRealIP(X-Forwarded-Forを信頼するreal_ipモジュール設定)は、Ingress ControllerやCDNなどXFFヘッダーを付与するリバースプロキシが前段にある場合にのみ機能する設計だが、このベアメタル構成ではService直下にPodがぶら下がるだけでXFFを付与する層が存在せず、機能していなかった(trustedProxiesに192.168.0.0/16が含まれるためSNAT後のノードIPを「信頼済みプロキシ」とみなしてしまうが、そのIPがXFFを付与するわけではないので$real_ipは結局SNAT後のIPのままになる)。
さらに、wp-config.php 生成テンプレート内でPHP側が生のX-Forwarded-Forヘッダーを無条件に信頼してREMOTE_ADDRを上書きする処理があり、Nginxのreal_ip信頼境界を迂回してクライアントがIPを詐称できる状態だった(副次的なセキュリティ上の問題)。
修正内容:
values.yaml:service.externalTrafficPolicy: Localをデフォルト追加(SNATを回避し実IPをそのまま透過させる。MetalLB L2モード等と組み合わせる想定。ClusterIPでは無視される)。templates/service.yaml:externalTrafficPolicyを条件付きで出力するよう変更。templates/deployment.yaml:wp-config.php内のPHP側REMOTE_ADDR再判定処理を削除(NginxのfastcgiパラメータでREMOTE_ADDRは既に正しく渡っているため不要かつ危険だった)。values.yaml/README.md:nginx.forwardRealIPは本当にXFFを付与するリバースプロキシが前段にある場合のみ有効化する旨を明記。
(2) メール送信の不具合
原因: 使用しているAlpineベースのWordPressイメージには、PHPの mail()(wp_mail() が内部的に利用)を実際に配送するMTA(sendmail相当)が同梱されておらず、sendmail_path の送信先が存在しなかった。
修正内容(helmchart/phpfpm チャートと同一の手法を採用。ユーザー指定によりphpfpmの実装パターンをそのまま踏襲):
values.yamlにsmtp.*セクションを追加(enabled/host/protocol/port/auth.*/from/tls.*)。templates/configmap-smtp.yaml(新規):/etc/msmtprcを生成するConfigMap。templates/secret-smtp.yaml(新規): SMTPパスワードを格納するSecret。templates/deployment.yaml:smtp.enabled: trueの場合のみ、wordpressコンテナの起動コマンドをシェルラッパーに変更し、apk add msmtp ca-certificates→/etc/msmtprc配置(chmod 644、www-dataから読めるように) → PHPのsendmail_pathをmsmtp -tに向ける99-smtp.iniを生成 →exec php-fpmという順で起動する。apk addにrootが必要なため、SMTP有効時のみ既存のsecurityContext: runAsUser/runAsGroup: 82を外している(PHP-FPMワーカー自体はイメージ標準のwww.confによりuid82で動作するため、実際のPHPコード実行権限は変わらない)。smtp.enabled: false(デフォルト)では従来どおり非rootで起動する。- msmtpのパスワードはmsmtprcに直書きせず
passwordeval "cat /etc/smtp-secrets/password"で別ファイル参照(phpfpmのCHANGELOG-8.5.6-f/g.mdで判明した「Secret/ConfigMapの権限が0600だとwww-dataから読めない」問題を踏まえ、最初から0644で実装済み)。
- WordPress本体は
wp_mail()が自動的にmail()/sendmail_pathを経由するため、phpfpmと異なりPHPコード側の変更(ヘルパークラスの読み込み等)は不要。
対象ファイル: values.yaml, templates/service.yaml, templates/deployment.yaml, templates/configmap-smtp.yaml(新規), templates/secret-smtp.yaml(新規), README.md, Chart.yaml