# CLAUDE.md — phpfpm Helm Chart > **共通ルール(要約)** — 詳細は `P:\Claude\CLAUDE.md`(全体共通)と `P:\Claude\HelmChart\CLAUDE.md`(Helm チャート共通: リリースフロー・ワークフロー・Gitea Secrets・クラスタ構成)を参照。 > 作業前に pull / 機能変更時は README 更新 / 作業単位ごとに commit → push まで / コミットに AI クレジットを付けない / pull で入った変更を revert しない / Helm・PHP はローカル実行不可(Python のみ可)。 ## リポジトリ概要 Raspberry Pi などのベアメタルで稼働することを想定した、Kubernetes 上で動作する Nginx + PHP-FPM の Helm チャート。 Websites 組織の各サイト(e-learn.jp / fcdomain.com / hotels / tskholding.com など)はこのチャートでデプロイされる。 - **Gitea リポジトリ**: `ssh://git@192.168.9.65/helmchart/phpfpm` - **Helm リポジトリ**: `https://git.cafepieters.com/api/packages/helmchart/helm` - **主アプリ**: PHP(`docker.io/php:-fpm-alpine`)。サブアプリ: nginx ## 実行環境について **PHP の実行環境(インタープリタ)はこのリポジトリには含まれていない。** チャートは `docker.io/php:-fpm-alpine` の公式イメージを Kubernetes 上で起動するものであり、PHP コードそのものは PVC(`/var/www/html`)に別途配置する必要がある。 ## 設計上の注意(既知の落とし穴) - `templates/configmap.yaml` が実際に使われている nginx 設定。`templates/configmap-nginx.yaml` は `.Values.nginx.enabled` が values.yaml に存在せず常に未出力の**死んだファイル**なので注意。 - PVC はルートを `/var/www` にマウントする(`html/` が公開フォルダ、それ以外は非公開)。`/composer` は Pod 再起動ごとにクリーン再構築される使い捨て領域。 - `uploadMaxSize` 1箇所で nginx `client_max_body_size`・PHP `upload_max_filesize`/`post_max_size`・Ingress `proxy-body-size` の3箇所が連動する。 - Secret / ConfigMap をファイルとして PHP-FPM ワーカー(`www-data`)から読ませる場合、権限は `0644` にする(`0600` だと読めない)。 - Selenium(`selenium.enabled: true`)は v8.5.10-b 以降、nginx/php-fpm と別の Deployment/Service(`-phpfpm-selenium`)。同一 Pod のサイドカーには**しない**(Selenium 単体の不調でメインの Pod が Service の Endpoints から外れ、静的ページ配信まで巻き込んで全断する設計だったため分離した)。 ## チャート改修履歴 ### v8.5.10-bのDeployment.spec.selector変更が既存リリースのアップグレードを壊す不具合を修正(2026-09-26, v8.5.10-c) v8.5.10-bでnginx/php-fpm Deploymentのspec.selector.matchLabelsに`app.kubernetes.io/component: web`を追加したが、Deployment.spec.selectorは作成後immutableのため既存リリースの`helm upgrade`が「field is immutable」で失敗する不具合を確認・修正した。既存Deploymentのselectorは元の内容(name+instanceのみ)に戻し、Selenium側はcomponentラベルではなく`app.kubernetes.io/name`自体を`-selenium`という別名にする方式(新ヘルパー`phpfpm.selenium.name`/`phpfpm.selenium.selectorLabels`)に変更した。componentラベルだけを足す設計だと、SeleniumのPodもnginx/php-fpm側Deploymentのselector(name+instance)に一致してしまい2つのDeployment(ReplicaSet)が同じPod集合を取り合う選択重複を起こすため、name自体をvariantにして構造的に防止する。v8.5.10-bは未適用ならスキップしてv8.5.10-c以降を直接使うこと。 **対象ファイル**: `templates/_helpers.tpl`, `templates/deployment.yaml`, `templates/deployment-selenium.yaml`, `templates/service-selenium.yaml`, `Chart.yaml`, `CHANGELOG-8.5.10-c.md` ### Selenium を独立Deployment/Serviceに分離 + resources死んだ設定を修正(2026-09-26, v8.5.10-b) `selenium.enabled: true` 構成で断続的な php-fpm CrashLoopBackOff とサイト完全停止が続いた件の調査で、2つの設計上の欠陥を確認した。(1) `resources` values キーがテンプレート側で全く参照されておらず、nginx/php-fpm/selenium いずれのコンテナにも requests/limits が反映されない死んだ設定だった(全コンテナが QoS Class: BestEffort → ノードのメモリ逼迫時に OOM Kill の対象になりやすい)。(2) nginx・php-fpm・Selenium が同一 Pod のコンテナで、Kubernetes の Pod Ready 判定は全コンテナの AND のため、Selenium だけが不調(起動失敗・OOM 等)でも Pod 全体が Service の Endpoints から外れ、Selenium を使わない静的ページ配信まで巻き込まれてサービス全体が停止していた。対応: Selenium を独立した Deployment(`-phpfpm-selenium`)/Service に分離(`app.kubernetes.io/component: web`/`selenium` ラベルでセレクタを分離、php-fpm の `SELENIUM_URL` は新Serviceを指すよう自動注入)。`resources` を `resources.nginx`/`resources.phpfpm`/`selenium.resources` に構造化し実際にコンテナへ反映されるよう修正。既存 `selenium.enabled: true` 利用者は `selenium.mountHtml`(PVC html サブパスへの依存があれば true + `persistence.accessMode: ReadWriteMany`)を確認する必要がある。OOM Kill が実際のクラッシュトリガーだったかは本リリース時点では未確認(要検証)だが、上記2点はコード上確認済みの確定した欠陥のため先行修正した。 **対象ファイル**: `templates/deployment.yaml`, `templates/deployment-selenium.yaml`(新規), `templates/service.yaml`, `templates/service-selenium.yaml`(新規), `values.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.10-b.md` ### 外部Secret連携(extraEnvFrom / extraEnv / SMTP existingSecret)を追加(2026-09-08, v8.5.10-a) **背景**: 別リポジトリの `helmchart/secret-manager` チャートが各ネームスペースへ配布する `cred-<名前>` Secret(メールの msmtprc / API キー)を、phpfpm 側から参照する口が無かった (`phpEnv` は直書きのみ、SMTP パスワードは `smtp.auth.password` 直書き+自作 Secret のみ)。 **修正内容**: - `values.yaml` に `extraEnvFrom`(`envFrom` 配列)と `extraEnv`(生の env エントリ配列)を追加。 php-fpm コンテナに既存 Secret/ConfigMap をまるごと env 注入できる。 - `smtp.auth.existingSecret` / `existingSecretKey` を追加。チャートで msmtprc を生成しつつ パスワードファイルだけ既存 Secret から取る。 - `smtp.existingMsmtprcSecret` / `existingMsmtprcSecretKey` を追加。完成済み msmtprc を持つ 既存 Secret をそのまま `/etc/smtp-config/msmtprc` としてマウント(secret-manager が生成する `msmtprc` キーを想定)。指定時は `configmap-smtp` を生成せず host/port/auth.* は無視、 `smtp-secrets` ボリュームも張らない(msmtprc にパスワードが内包されるため)。 - `templates/secret-smtp.yaml` / `templates/configmap-smtp.yaml` を上記フラグで出し分け。 - 既定値は全て空 → 既存挙動は不変(`helm template` の全シナリオで確認済み)。 - 主アプリ(PHP 8.5.10)は変わらないため手動リリース `8.5.10-a`。 **対象ファイル**: `values.yaml`, `templates/deployment.yaml`, `templates/configmap-smtp.yaml`, `templates/secret-smtp.yaml`, `Chart.yaml`, `README.md`, `CLAUDE.md` ### php-fpm を `exec php-fpm -F` で起動しCrashLoopBackOffを修正(2026-09-06, v8.5.9-d) setup シェル末尾の `php-fpm`(シェルの子プロセス)を **`exec php-fpm -F`** に変更。selenium 有効構成(hotels)で php-fpm が `unable to bind ... '9000': Address in use` を出して永続 CrashLoopBackOff になり、nginx が非FastCGI応答を受けて全リクエスト502(`unsupported FastCGI protocol version: 60`)になる障害の修正。原因は php-fpm が setup シェルの子で、コンテナ PID1 のシェルが `SIGTERM` を子へ転送しないため、コンテナ再起動時に旧 php-fpm が残存し 9000 を握ったまま次回起動が二重 bind で失敗する自己増殖ループ。`exec` で php-fpm を PID1 にしてシグナルを直接受けさせ(停止時に 9000 を確実解放)、`-F` で `daemonize` 設定に依存せず必ずフォアグラウンド起動にした。全サイト共通で安全(コンテナで php-fpm を動かす定石)。復旧には `helm upgrade` に加え、残存プロセスを持つ既存 pod の削除が必要な場合がある。 **対象ファイル**: `templates/deployment.yaml`, `Chart.yaml`, `README.md`, `CLAUDE.md`, `CHANGELOG-8.5.9-d.md` ### Ingressのproxy-body-sizeもuploadMaxSizeに連動(2026-08-06, v8.5.9-c) v8.5.9-bのフォローアップ。`templates/ingress.yaml` で `merge (deepCopy .Values.ingress.annotations) (dict "nginx.ingress.kubernetes.io/proxy-body-size" .Values.uploadMaxSize)` を使い、ユーザーが明示指定していなければ `uploadMaxSize` をIngressの `proxy-body-size` にも自動反映。明示指定があればそちらが優先(sprigのmergeはdst=ユーザー指定annotationsが優先、srcのデフォルト値は不足分のみ補う)。これで `uploadMaxSize` 1箇所でnginx・PHP・Ingressの3箇所すべてが揃う。 **対象ファイル**: `templates/ingress.yaml`, `values.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.9-c.md` ### uploadMaxSize の追加(2026-08-06, v8.5.9-b) nginxの `client_max_body_size` とPHPの `upload_max_filesize`/`post_max_size` を1つの `uploadMaxSize`(デフォルト `"100m"`)で連動させるパラメータを追加。片方だけ上げてももう片方の上限でアップロードが無言で失敗する問題への対応。PHP側は起動時に `/usr/local/etc/php/conf.d/99-uploads.ini` を常時生成(他機能の有効/無効に依存しない)。memory_limitは対象外(別途必要なら将来検討)。 **対象ファイル**: `values.yaml`, `templates/configmap.yaml`, `templates/deployment.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.9-b.md` ### sitemap.xml のContent-Type明示(2026-08-06, v8.5.9-a) `templates/configmap.yaml` に `location = /sitemap.xml { types { } default_type "application/xml; charset=utf-8"; ... }` を追加。標準mime.typesでは `.xml` が `text/xml` 扱いでcharset無しになる問題への対応。静的ファイルの場合のみ有効、PHP動的生成には効かない(PHP側でheader()指定が必要)。設定不要・常時有効。 **対象ファイル**: `templates/configmap.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.9-a.md` ### Python導入オプションの追加(2026-07-19, v8.5.8-a) `python` セクションを新設し、`values.yaml` の設定だけでPython仮想環境(venv)を導入可能にした。Composerと同じ設計方針(デフォルト導入先 `/venv` はPVC非マウントの使い捨て領域、`packages`/`useRequirementsTxt`の二択、`additionalApkPackages`でネイティブ拡張ビルド対応)。requirements.txtの展開は `trim | nindent 14`(v8.5.6-dのバグ修正と同じ手法)。PHPからは `exec('/venv/bin/python3 script.py')` で呼び出す。 なお、この改修中に自動更新ワークフローがPHP 8.5.8へのフルリリース(v8.5.8)を実行したため、本機能はそのタグの上に手動リリース `8.5.8-a` として適用した。 **対象ファイル**: `values.yaml`, `templates/deployment.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.8-a.md` ### /etc/msmtprc の権限を0600→0644に修正(2026-07-19, v8.5.6-g) v8.5.6-f のフォローアップ。`/etc/smtp-secrets/password` の権限修正だけでは不十分で、起動スクリプトが `cp` 後に `chmod 600` していた `/etc/msmtprc` 自体もrootのみ読み取り可のままだった(msmtp: account default not found, exit:78)。`chmod 644` に変更。msmtprcには平文パスワードは含まれない(passwordeval経由で別ファイル参照)ため実害なし。 **対象ファイル**: `templates/deployment.yaml`, `Chart.yaml`, `CHANGELOG-8.5.6-g.md` ### SMTPパスワードSecretの権限を0600→0644に修正(2026-07-19, v8.5.6-f) `smtp-secrets` ボリュームの `mode: 0600` が原因で、rootではなく `www-data`(PHP-FPMワーカー)として動く msmtp が `/etc/smtp-secrets/password` を読めず、SMTP認証に失敗する不具合を修正。`0644` に変更(Pod内にしか存在しないファイルのため許容範囲)。 **対象ファイル**: `templates/deployment.yaml`, `Chart.yaml`, `CHANGELOG-8.5.6-f.md` ### PVCルートを /var/www にマウント + /composer を使い捨て化(2026-07-19, v8.5.6-e) php-fpm コンテナのマウントを「`html` サブパスのみ」から「PVCルート → `/var/www`」に変更。`html/` は公開フォルダ、それ以外(`/var/www/<任意>`)は非公開ファイルの格納先として使える。nginx は `html` サブパスのみマウントするため非公開分は公開されない。あわせて `/composer` のPVC永続化マウントを廃止し、Pod再起動ごとにクリーン再構築される使い捨て領域とした(マルウェア混入対策、ユーザー要望)。永続化したい場合は `workingDir` に `/var/www/composer` 等を指定。 **対象ファイル**: `templates/deployment.yaml`, `values.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.6-e.md` ### useComposerJson の YAML parse error 修正(2026-07-19, v8.5.6-d) `useComposerJson: true` 指定時、heredoc 内の `{{ .Values.composer.composerJson }}` がインデント無しで展開され、複数行JSONの2行目以降がブロックスカラーを破壊して YAML parse error になる潜在バグを修正。`trim | nindent 14` で展開するよう変更(`composerLock` も同様)。 **対象ファイル**: `templates/deployment.yaml`, `Chart.yaml`, `CHANGELOG-8.5.6-d.md` ### Composerデフォルト導入先を /composer に変更(2026-07-19, v8.5.6-c) `/var/www` はWebルート `/var/www/html` の親のため、ネストマウントでPVCの `composer` サブパス内に空の `html/` が生成されていた。デフォルトをWebルートと親子関係にない `/composer` に変更してネストを解消。autoloadは `require_once '/composer/vendor/autoload.php';`(values.yaml のコメントにも明記)。 **対象ファイル**: `values.yaml`, `templates/deployment.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.6-c.md` ### 旧composer.jsonの自動移行 + mbstring依存の自動追加(2026-07-19, v8.5.6-b) v8.5.6-a のフォローアップ。起動時に `workingDir` に `composer.json` が無く旧Webルート `/var/www/html` にある場合、`composer.json` / `composer.lock` / `vendor/` を自動移行する。また `additionalPhpExtensions` に `mbstring` 指定時、ビルドに必要な `oniguruma-dev` を自動追加(GDと同じ仕組み)。 なお、PVC上の `composer/html/`(空ディレクトリ)はネストマウントのマウントポイント作成による正常な副産物で、実害なし。 **対象ファイル**: `templates/deployment.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.6-b.md` ### composer.workingDir — Composer導入先のWebルート外への変更(2026-07-19, v8.5.6-a) Composerの導入先をWebルート `/var/www/html` からWebルート外の `/var/www` に変更し、`vendor/` や `composer.json` がWeb経由で公開されないようにした。`values.yaml` の `composer.workingDir` で導入先を変更可能(旧動作に戻すには `"/var/www/html"` を指定)。導入先がWebルート以外の場合、PVCの `composer` サブパスをマウントして永続化する。 PHP側の読み込みは `require_once '/var/www/vendor/autoload.php';`。 **対象ファイル**: `values.yaml`, `templates/deployment.yaml`, `README.md`, `Chart.yaml`, `CHANGELOG-8.5.6-a.md` ### phpEnv — 汎用 PHP 環境変数サポート(2026-04-17) `values.yaml` に `phpEnv` セクションを追加し、DB 接続情報と同様に任意のキーと値を PHP-FPM コンテナの環境変数として渡せるようにした。 ```yaml phpEnv: API_KEY: "your-api-key" STRIPE_SECRET: "sk_live_..." REDIS_URL: "redis://localhost:6379" ``` PHP 側では `$_ENV['API_KEY']` または `getenv('API_KEY')` で取得できる。 **対象ファイル**: `values.yaml`, `templates/deployment.yaml`, `README.md`