20 Commits
Author SHA1 Message Date
GitHub Actions Bot 0cf3e29b9e chore: update to PHP 8.5.12, nginx 1.31.8-alpine-perl, selenium 155.0-chromedriver-155.0 2026-10-21 23:22:52 +00:00
claude f8aaa5944d docs: nginx.customConfig の取り違えと client_max_body_size 重複を防ぐ記述に修正
Helm Chart Release / release-chart (push) Successful in 6s
あるプロジェクトから「serverSnippet が効かない」「snippet は古いキー」との
指摘があり調査した結果、指摘の前提は誤りだった。

- 実際に使われる templates/configmap.yaml が読むのは snippet で、values.yaml と
  README も snippet で一致している。
- serverSnippet / httpSnippet は、.Values.nginx.enabled が存在せず一度も出力
  されない configmap-nginx.yaml だけが読むキーで、values・README に載ったことが
  なく、指定しても黙って無視される。
- README 例6・例9 が snippet に client_max_body_size を書く手順になっており、
  v8.5.9-b 以降は uploadMaxSize の自動出力と重複して nginx が起動しない
  (2026-09-29 の障害の発生源)。例6 は location ~ \.php$ も重複定義していた。

挙動の変更はなくドキュメント・コメントのみ。
- values.yaml / README: 読まれるキーは snippet のみ、挿入先は server ブロック内、
  client_max_body_size は書かず uploadMaxSize を使うことを明記
- README 例6・例9 を uploadMaxSize 指定に修正
- configmap-nginx.yaml: 未使用であることを示す注記を追加

手動リリース 8.5.11-a。
2026-10-20 20:38:07 +09:00
GitHub Actions Bot 5ab3428893 chore: update nginx to 1.31.7-alpine-perl, selenium to 155.0-chromedriver-155.0 (no release) 2026-10-19 02:00:17 +00:00
GitHub Actions Bot 328a67213e chore: update to PHP 8.5.11, nginx 1.31.6-alpine-perl, selenium 152.0-chromedriver-152.0 2026-09-28 02:00:19 +00:00
claude 6cd35ce023 feat: 定期実行(CronJob)機能を追加
Helm Chart Release / release-chart (push) Successful in 5s
cron.jobs(配列)にジョブを定義すると、php-fpmと同じPHPイメージを使う
Kubernetes CronJobをジョブごとに生成する。

- templates/cronjob.yaml(新規): PVCルートを/var/wwwにマウントし、
  externalDatabase/phpEnv/extraEnv/extraEnvFrom/SELENIUM_URLをphp-fpm
  コンテナと同じ内容で注入。smtp.enabled時はmsmtpも自動導入。
- templates/_helpers.tpl: phpfpm.cron.name/selectorLabelsを追加。
  Selenium分離と同じ理由で、生成PodのラベルをDeploymentのselectorと
  衝突しないバリアント名(<chart>-cron)にする。
- values.yaml: cronセクションを追加(既定は空配列で無効)。
- README.md: パラメータ表と使用例、Composer/Pythonとの併用時の注意点
  (デフォルトの使い捨て領域はCronJobから見えないため、永続化パスへの
  変更が必要)を追加。

templates/deployment.yamlは変更していない(既存Deploymentへの影響なし)。
手動リリース 8.5.10-e。
2026-09-27 16:26:18 +09:00
claude c7397b3c9d feat: ingress.tls[].secretNameをhostから自動導出できるように変更
Helm Chart Release / release-chart (push) Successful in 6s
ingress.hosts[].hostは既にYAMLアンカー(&appDomain)でingress.tls[].hosts
と値を共有できていたが、secretNameは独立した文字列指定が必須で、
ドメイン変更時に別途書き換えが必要だった。

secretNameを省略可能にし、未指定時はそのエントリの最初のhostから
自動生成する(.を-に置換して-tlsを付与。例: example.tld → example-tld-tls)。
明示的に指定した場合はそちらが優先されるため既存挙動は変わらない。

手動リリース 8.5.10-d。
2026-09-27 15:28:15 +09:00
pieter 9d8fb83bac values.yaml を更新
Helm Chart Release / release-chart (push) Successful in 8s
2026-09-27 06:18:00 +00:00
claude abb5dba4a1 fix: v8.5.10-bのDeployment.spec.selector変更が既存リリースのアップグレードを壊す不具合を修正
Helm Chart Release / release-chart (push) Successful in 9s
既存の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自体を<chart名>-seleniumという別名にする方式(新ヘルパーphpfpm.selenium.name/phpfpm.selenium.selectorLabels)に変更した。componentラベルだけを足す設計だとSeleniumのPodもnginx/php-fpm側Deploymentのselectorに一致してしまいReplicaSetの選択重複を起こすため、name自体をvariantにして構造的に防止する。v8.5.10-bは既存リリースへの適用不可のためスキップし、v8.5.10-c以降を使うこと。
2026-09-26 09:46:56 +09:00
claude 86cd705d06 fix: Seleniumを独立Deployment/Serviceに分離しresourcesの死んだ設定を修正
Helm Chart Release / release-chart (push) Successful in 6s
selenium.enabled=true構成でphp-fpmのCrashLoopBackOffとサイト完全停止が続いた件を調査し、2つの設計上の欠陥を確認した。(1) resources values キーがテンプレートで一切参照されておらず、全コンテナがQoS Class: BestEffortで動作しOOM Killされやすい状態だった。(2) nginx/php-fpm/SeleniumをすべてSelenium同一Podで起動しており、Kubernetesの Pod Ready判定(全コンテナのAND)により、Seleniumだけが不調でもPod全体がServiceのEndpointsから外れ、Seleniumを使わない静的ページ配信まで巻き込まれてサービス全体が停止していた。対応: Seleniumを独立Deployment(<release>-phpfpm-selenium)/Serviceに分離し、SELENIUM_URLを自動注入。resourcesをnginx/phpfpm/selenium個別に構造化して実際にコンテナへ反映されるよう修正。詳細はCHANGELOG-8.5.10-b.md参照。
2026-09-26 08:05:10 +09:00
GitHub Actions Bot 6eb1c24732 chore: update nginx to 1.31.6-alpine-perl, selenium to 152.0-chromedriver-152.0 (no release) 2026-09-21 02:00:22 +00:00
pieter 3e1830426c values.yaml を更新
Helm Chart Release / release-chart (push) Successful in 6s
2026-09-15 17:01:32 +00:00
claude c81083fd57 feat: 外部Secret連携(extraEnvFrom / extraEnv / SMTP existingSecret)を追加
Helm Chart Release / release-chart (push) Successful in 6s
helmchart/secret-manager が各ネームスペースへ配布する cred-* Secret を
phpfpm 側から参照できるようにする。
- extraEnvFrom / extraEnv: 既存 Secret/ConfigMap を php-fpm コンテナへ env 注入
- smtp.auth.existingSecret / existingSecretKey: パスワードファイルだけ既存 Secret から取得
- smtp.existingMsmtprcSecret / existingMsmtprcSecretKey: 完成済み msmtprc を
  そのままマウント(指定時は configmap-smtp を生成せず host/port/auth.* は無視)
既定値は全て空のため既存挙動は不変。手動リリース 8.5.10-a。
2026-09-08 14:14:39 +09:00
GitHub Actions Bot 6ae463fc49 chore: update to PHP 8.5.10, nginx 1.31.5-alpine-perl, selenium 152.0-chromedriver-152.0 2026-09-07 02:00:19 +00:00
claude b872dd4bd9 fix: php-fpmをexec php-fpm -Fで起動しCrashLoopBackOff(9000二重bind)/502を修正
Helm Chart Release / release-chart (push) Successful in 6s
setupシェルの子として起動していたためコンテナ再起動時にシェル(PID1)がSIGTERMを子へ転送せず、旧php-fpmが9000を握ったまま残存し次回起動が Address in use で失敗する自己増殖ループに陥っていた。execでphp-fpmをPID1にしシグナルを直接受けさせ、-Fで必ずフォアグラウンド起動にする。
2026-09-06 19:54:49 +09:00
claude 6de85b9ad4 docs: CLAUDE.md を階層化した共通ルールに合わせて整理し、GEMINI.md と .agents/rules(Antigravity 用参照)を追加
Helm Chart Release / release-chart (push) Successful in 5s
2026-09-04 13:24:02 +09:00
GitHub Actions Bot eb3eef601a chore: update nginx to 1.31.4-alpine-perl, selenium to 151.0-chromedriver-151.0 (no release) 2026-08-24 02:00:21 +00:00
GitHub Actions Bot 7c5e9e44c8 chore: update nginx to 1.31.3-alpine-perl, selenium to 151.0-chromedriver-151.0 (no release) 2026-08-17 02:00:23 +00:00
claudeandClaude Fable 5 e9428c6448 feat: IngressのproxyBodySizeもuploadMaxSizeに自動連動 (v8.5.9-c)
Helm Chart Release / release-chart (push) Successful in 5s
uploadMaxSizeでnginx/PHPのアップロード上限は連動していたが、
ingress.enabled: true の場合、ingress-nginx側にも独自の上限
(デフォルト1MB)があり、そこで先に弾かれるケースが残っていた。

templates/ingress.yaml で、ingress.annotationsに
nginx.ingress.kubernetes.io/proxy-body-sizeが明示指定されていない
場合、uploadMaxSizeの値を自動的に付与するようにした(merge使用、
明示指定があればそちらを優先)。

これでuploadMaxSize 1箇所の設定でnginx・PHP・Ingressの3箇所すべてに
反映される。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 00:09:20 +09:00
claudeandClaude Fable 5 8f1b050bb2 feat: アップロード最大サイズをvalues.yamlで設定可能に (v8.5.9-b)
Helm Chart Release / release-chart (push) Successful in 5s
大きなファイルのアップロードが失敗する問題(nginxとPHPそれぞれに
別々の上限があり、片方だけ上げても失敗する)に対応するため、
uploadMaxSize パラメータを新設(デフォルト 100m)。

- values.yaml: uploadMaxSize を追加
- templates/configmap.yaml: nginx の client_max_body_size に反映
- templates/deployment.yaml: PHP-FPM起動時に
  /usr/local/etc/php/conf.d/99-uploads.ini を生成し、
  upload_max_filesize / post_max_size に同じ値を設定(常時適用)
- README.md: パラメータ表と設計についての注記を追加

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 23:22:26 +09:00
claudeandClaude Fable 5 e27f02992f fix: sitemap.xmlのContent-Typeを application/xml; charset=utf-8 に明示 (v8.5.9-a)
Helm Chart Release / release-chart (push) Successful in 7s
標準のmime.typesでは .xml が text/xml 扱いとなりcharsetが付与されず、
ブラウザやGoogle Search Consoleなどのツールが正しく解釈できない
場合があった。

templates/configmap.yaml のnginx設定に location = /sitemap.xml を
追加し、types {} + default_type で明示的にContent-Typeを指定する
ようにした。静的ファイルの場合のみ有効(PHP動的生成には別途
header()指定が必要)。設定不要・常時有効。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 22:14:31 +09:00
23 changed files with 1212 additions and 91 deletions
+7
View File
@@ -0,0 +1,7 @@
---
trigger: always_on
description: Read the CLAUDE.md hierarchy via GEMINI.md before doing anything in this workspace
---
最初に、このディレクトリの `GEMINI.md` を読み、そこに列挙された CLAUDE.md を上から順にすべて読んで従うこと。
Read `GEMINI.md` in this directory first, then read and follow every CLAUDE.md it lists, in order.
+105
View File
@@ -0,0 +1,105 @@
# Changelog - Version 8.5.10-b
> ⚠️ **v8.5.10-b は単体では既存リリースの `helm upgrade` が失敗する不具合を含む**
> (`Deployment.spec.selector: ... field is immutable`)。設計・原因の記録として
> 本ファイルは残すが、**実際の適用は v8.5.10-c 以降を使うこと**。修正内容は
> `CHANGELOG-8.5.10-c.md` を参照。
## 不具合修正・アーキテクチャ変更
### Selenium を独立した Deployment/Service に分離(サービス完全停止の防止)
**背景(実際に発生した障害)**
`selenium.enabled: true` の構成(hotels / booking.e-stay.jp)で、php-fpm コンテナの
`CrashLoopBackOff` が断続的に発生し、その間サイト全体が Nginx の 502(`unsupported
FastCGI protocol version`)で完全に閲覧不能になる障害が続いた。v8.5.9-d で php-fpm の
起動方式(`exec php-fpm -F`)を修正した後も、8時間で1,375回という高頻度の再起動が
継続して観測された。
**原因(確定した2点)**
1. **`resources` values キーがテンプレート側で一切参照されていなかった(死んだ設定)。**
`values.yaml` の `resources: {}` にどんな値を書いても、nginx・php-fpm・selenium
いずれのコンテナにも CPU/メモリの requests・limits が反映されない実装だった。
このため全コンテナが `QoS Class: BestEffort`(実際のデプロイでも確認済み)で動作し、
ノードのメモリ逼迫時に Linux の OOM Killer に真っ先に狙われる状態だった。
Selenium(Chromium)はメモリを多く消費するため、Raspberry Pi 等のメモリに余裕がない
ノードでは他コンテナの OOM Kill を誘発しやすい。
2. **nginx・php-fpm・Selenium を同一 Pod のコンテナとして起動しており、Pod の Ready 判定
が「全コンテナの AND」になっていた。** readinessProbe を持たないコンテナは、
Running であれば Ready 扱いになる一方、CrashLoopBackOff で Waiting/Terminated を
繰り返している間は Ready=false になる。Kubernetes の Service は Pod 全体が Ready
でなければ Endpoints に含めないため、**Selenium だけが不調でも Service の
Endpoints がゼロになり、Selenium を全く使わない静的ページの配信まで巻き込まれて
サイト全体が停止していた**。`replicaCount: 1`(冗長性なし)の構成では、この1点が
即・全断につながる。
(OOM Kill が今回の php-fpm クラッシュの直接のトリガーだったかは、`kubectl describe pod`
の `Last State` / `Reason` 等での確認が必要で、本リリース時点では未確認・要検証。
ただし上記2点はコード上で確認できる確定した設計上の欠陥であり、いずれも本番運用の
安定性を損なうため、原因の切り分けを待たずに先に修正する。)
**対応**
- `selenium.enabled: true` のとき、Selenium は nginx/php-fpm と別の
**独立した Deployment(`<release>-phpfpm-selenium`)と Service** として起動するように
変更した(`templates/deployment-selenium.yaml` / `templates/service-selenium.yaml` を新設)。
- php-fpm コンテナの `SELENIUM_URL` 環境変数は、`selenium.enabled: true` のとき
自動的にこの新しい Service(`http://<release>-phpfpm-selenium:4444/wd/hub`)を
指すよう自動注入される(`phpEnv` で独自に設定していても、こちらが優先される)。
- `selenium.replicaCount`(既定 `1`)で Selenium の Pod 数を独立して設定可能。
- `selenium.mountHtml`(既定 `false`): `true` にすると Selenium コンテナにも
PVC の `html` サブパスをマウントする。別 Pod からの同時マウントになるため、
有効にする場合は `persistence.accessMode: ReadWriteMany`
(NFS バックエンドの StorageClass なら対応可能)が必要。
- メインの Service(`<release>-phpfpm`)・Deployment には
`app.kubernetes.io/component: web` ラベルを、Selenium 側には `component: selenium`
ラベルを付与し、セレクタが混線しないようにした。
- `resources` values キーを実際にコンテナへ反映されるよう修正し、**nginx・php-fpm・
selenium で個別に設定できる構造**に変更した:
```yaml
resources:
nginx: { requests: {...}, limits: {...} }
phpfpm: { requests: {...}, limits: {...} }
selenium:
resources: { requests: {...}, limits: {...} }
```
既定値は空(`{}`)で、requests/limits なしの現行動作を維持する。**本番運用では
設定を強く推奨する**(推奨値の例は `values.yaml` のコメントを参照)。
**互換性(重要・要対応)**
- **`selenium.enabled: true` を使っている既存リリースは、アップグレード後に
以下の対応が必要:**
1. Selenium コンテナがそれまで暗黙にマウントしていた PVC の `html` サブパスに
依存していた場合(例: ブラウザのダウンロード先を公開ディレクトリに置いていた等)、
`selenium.mountHtml: true` を設定し、`persistence.accessMode` を
`ReadWriteMany` に変更する。依存していなければ何もする必要はない
(既定 `mountHtml: false` のままでよい)。
2. `phpEnv.SELENIUM_URL` に `http://localhost:4444/wd/hub` 等を手動設定している場合、
Selenium が別 Pod になったことで `localhost` には到達できなくなる。ただし
チャートが自動的に新しい Service を指す値へ上書きするため、**多くの場合は
何もしなくても動作する**(自動注入の値が env リストの後方にあるため優先される)。
設定の混乱を避けるため、`phpEnv.SELENIUM_URL` の手動指定は削除することを推奨する。
- `resources: {}` は元々どのコンテナにも一切効いていなかったため、この構造変更で
既存の動作が変わることはない(誰も実質的な値を得ていなかったため、破壊的変更にはならない)。
**対象ファイル**: `templates/deployment.yaml`, `templates/deployment-selenium.yaml`(新規),
`templates/service.yaml`, `templates/service-selenium.yaml`(新規), `values.yaml`,
`README.md`, `Chart.yaml`, `CLAUDE.md`, `CHANGELOG-8.5.10-b.md`
## アップグレード手順
```bash
helm repo update
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.10-b -f values.yaml
```
`selenium.enabled: true` の場合、上記「互換性」を確認のうえアップグレードすること。
---
**リリース日**: 2026-09-26
**担当**: プロサーバーエンジニア(Claude)
+60
View File
@@ -0,0 +1,60 @@
# Changelog - Version 8.5.10-c
## 不具合修正
### v8.5.10-b の Selenium分離が既存リリースのアップグレードを壊す問題を修正
v8.5.10-b で Selenium を独立 Deployment/Service に分離した際、既存の nginx/php-fpm
Deployment の `spec.selector.matchLabels` に `app.kubernetes.io/component: web` を
追加した。しかし **`Deployment.spec.selector` は作成後 immutable** であり、
既存リリースを `helm upgrade` すると次のエラーで失敗する。
```
cannot patch "<release>-phpfpm" with kind Deployment: Deployment.apps "<release>-phpfpm"
is invalid: spec.selector: Invalid value: ...: field is immutable.
```
**対応**
- 既存の nginx/php-fpm Deployment の `spec.selector.matchLabels` は
元の内容(`app.kubernetes.io/name` + `app.kubernetes.io/instance` のみ)に戻し、
以後も変更しない。
- Selenium 側は `app.kubernetes.io/component` ラベルではなく、
**`app.kubernetes.io/name` 自体を `<chart名>-selenium` という別名にする**方式に変更した
(新ヘルパー `phpfpm.selenium.name` / `phpfpm.selenium.selectorLabels`。
`templates/_helpers.tpl`)。component ラベルを足すだけの設計だと、Selenium の Pod も
nginx/php-fpm 側 Deployment の selector(name+instance)に一致してしまい、
2つの Deployment(ReプリカSet)が同じ Pod 集合を取り合う selector 重複を起こすため、
name 自体を variant にして構造的に重複を防止する。
- `templates/deployment-selenium.yaml` / `templates/service-selenium.yaml` の
selector・pod template labels をこの新ヘルパーに合わせて修正。
`app.kubernetes.io/component: selenium` は情報用のラベルとして pod template には
引き続き付与する(selector には使わない。README の `kubectl logs -l
app.kubernetes.io/component=selenium` 等の運用コマンドはそのまま使える)。
- メインの Service(`<release>-phpfpm`)の selector に残した
`app.kubernetes.io/component: web` は Service の selector なので immutable 制約は
受けず、そのまま維持している(Selenium 側が別名になったことで実質不要になったが、
害はないため多層防御として残す)。
**v8.5.10-b をまだ適用していない場合**: 8.5.10-b は上記のバグを含むため、
直接 **8.5.10-c 以降**を適用すること。
**v8.5.10-b の適用に失敗した場合**(今回のエラーが出た場合): リリースは
アップグレードに失敗した時点のリビジョンのままのはずなので、Chart version を
`8.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`
## アップグレード手順
```bash
helm repo update
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.10-c -f values.yaml
```
---
**リリース日**: 2026-09-26
**担当**: プロサーバーエンジニア(Claude)
+35
View File
@@ -0,0 +1,35 @@
# Changelog - Version 8.5.9-a
## 修正
### sitemap.xml のContent-Typeを明示的に指定
`/sitemap.xml`(静的ファイル)へのアクセス時、標準の `mime.types` では `.xml` が `text/xml` 扱いとなり `charset` が付与されないため、ブラウザやGoogle Search Consoleなどのツールが正しく解釈できない場合がありました。
**対応**: `templates/configmap.yaml` のnginx設定に `location = /sitemap.xml` を追加し、`types { } default_type "application/xml; charset=utf-8";` によって明示的にContent-Typeを指定するようにしました。
```nginx
location = /sitemap.xml {
types { }
default_type "application/xml; charset=utf-8";
try_files $uri =404;
}
```
## 注意事項
- この対応は `/sitemap.xml` が**静的ファイル**として `html/` 直下に配置されている場合に適用されます。
- PHPで動的に生成する場合(`/index.php` へのフォールバック経由)は、nginxのこの設定は適用されません。PHP側で `header('Content-Type: application/xml; charset=utf-8');` を明示的に指定してください。
- 設定不要・常時有効です(values.yamlへの変更はありません)。ファイルが存在しない場合は従来どおり404を返します。
## アップグレード手順
```bash
helm repo update
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.9-a -f values.yaml
```
---
**リリース日**: 2026-08-06
**担当**: プロサーバーエンジニア(Claude)
+52
View File
@@ -0,0 +1,52 @@
# Changelog - Version 8.5.9-b
## 新機能
### アップロード最大サイズを values.yaml で設定可能に
大きなファイルのアップロードが失敗する問題(nginxとPHPそれぞれに別々のアップロード上限があり、片方だけ上げても失敗する)に対応するため、`uploadMaxSize` パラメータを新設しました。
#### 主な変更点
1. **values.yaml**
- `uploadMaxSize: "100m"` を追加(デフォルト100MB)
2. **templates/configmap.yaml**
- nginx設定に `client_max_body_size {{ .Values.uploadMaxSize }};` を追加
3. **templates/deployment.yaml**
- PHP-FPM起動時に `/usr/local/etc/php/conf.d/99-uploads.ini` を生成し、
`upload_max_filesize` / `post_max_size` に同じ値を設定
- 常時適用(他機能の有効化状態に依存しない)
4. **README.md**
- パラメータ表と、nginx/PHP両方に反映される設計についての注記を追加
## 背景
nginxの `client_max_body_size` だけを上げても、PHPには独自の `upload_max_filesize`(デフォルト2M)/ `post_max_size`(デフォルト8M)という別の上限があり、nginxを通過した後にPHP側で無言で失敗するケースがありました。この2つを同じ値で連動させることで、設定漏れによる失敗を構造的に防ぎます。
## 使用例
```yaml
uploadMaxSize: "100m"
# 大きな動画ファイルなどを扱う場合
# uploadMaxSize: "500m"
```
## 互換性
- デフォルト値は `100m`(従来の暗黙の上限より大幅に緩和)。既存よりアップロード可能サイズが大きくなる方向の変更のため、既存環境への悪影響はありません。
- 大きなファイルをPHP側でメモリに読み込んで処理する場合、`memory_limit`(デフォルト128M程度)が別途不足する可能性がある点に注意してください。
## アップグレード手順
```bash
helm repo update
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.9-b -f values.yaml
```
---
**リリース日**: 2026-08-06
**担当**: プロサーバーエンジニア(Claude)
+40
View File
@@ -0,0 +1,40 @@
# Changelog - Version 8.5.9-c
## 新機能
### Ingressのアップロードサイズ上限も uploadMaxSize に自動連動
v8.5.9-b で `uploadMaxSize` によりnginx/PHPのアップロード上限を連動させましたが、`ingress.enabled: true` で運用している場合、Ingressコントローラー(ingress-nginx)にも独自のリクエストサイズ上限(デフォルト1MB)があり、そこで先に弾かれてしまうケースが残っていました。
**対応**: `templates/ingress.yaml` で、`ingress.annotations` に `nginx.ingress.kubernetes.io/proxy-body-size` が明示指定されていない場合、`uploadMaxSize` の値を自動的に付与するようにしました。ユーザーが `ingress.annotations` に明示的に指定した場合はそちらが優先されます。
```yaml
# 何も指定しなくても、Ingressにも uploadMaxSize の値(デフォルト100m)が反映される
uploadMaxSize: "100m"
ingress:
enabled: true
```
これにより、`uploadMaxSize` 1箇所の設定で以下すべてに反映されます:
- nginx(Podコンテナ内)の `client_max_body_size`
- PHPの `upload_max_filesize` / `post_max_size`
- ingress-nginxの `nginx.ingress.kubernetes.io/proxy-body-size`
## 互換性
- Ingressコントローラーがingress-nginx以外の場合、このアノテーションは無視されます。該当コントローラー向けの設定を `ingress.annotations` に明示的に指定してください。
- 既存で `ingress.annotations` に独自の `proxy-body-size` を指定している場合、その値がそのまま優先されるため影響ありません。
## アップグレード手順
```bash
helm repo update
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.9-c -f values.yaml
```
---
**リリース日**: 2026-08-06
**担当**: プロサーバーエンジニア(Claude)
+54
View File
@@ -0,0 +1,54 @@
# Changelog - Version 8.5.9-d
## 不具合修正
### php-fpm を `exec php-fpm -F` で起動(CrashLoopBackOff / 502 の修正)
php-fpm コンテナの起動コマンドを、setup シェルスクリプト末尾の `php-fpm`(シェルの子プロセスとしてフォアグラウンド起動)から **`exec php-fpm -F`** に変更しました。
**背景(実際に発生した障害)**
`selenium.enabled: true` の構成(例: hotels / booking.e-stay.jp)で、php-fpm コンテナが次のエラーで永続的に CrashLoopBackOff に陥る事象が発生しました。
```
[NOTICE] Failed implicitly binding to ::, retrying with 0.0.0.0
[ERROR] unable to bind listening socket for address '9000': Address in use (98)
[ERROR] FPM initialization failed
```
php-fpm が 9000 を bind できず起動に失敗するため、nginx が `fastcgi_pass 127.0.0.1:9000` に投げても FastCGI ではない応答が返り、`upstream sent unsupported FastCGI protocol version: 60` として **全リクエストが 502** になります(`60` = `<`、= 9000 を握っている別プロセスが HTML 等を返している)。
**原因**
起動コマンドが `sh -c "<setup> ... php-fpm"` の形で、**php-fpm が setup シェルの子プロセス**になっていた。コンテナ PID1 はシェルであり、シェルは既定で受け取った `SIGTERM` を子プロセスへ転送しない。そのためコンテナ(php-fpm コンテナのみ)の再起動時に、PID1 のシェルだけが先に終了し、**旧 php-fpm が一時的に残存して 9000 を握ったまま**になることがある。この状態で新しい php-fpm が起動すると `Address in use` で失敗 → 再起動 → 同じ残存 → という自己増殖ループに入り、CrashLoopBackOff から復帰できなくなる。selenium サイドカーは 9000 を使用しておらず無関係(別 pod でのポート占有調査でも確認済み)。
**対応**
- `exec php-fpm` … php-fpm が setup シェルを置き換えて**コンテナの PID1 になる**。kubelet からの `SIGTERM`/`SIGKILL` が php-fpm 本体へ直接届き、停止時に 9000 が確実に解放されるため、次回起動での二重 bind が起きない。
- `-F`(`--nodaemonize`)… php-fpm.conf の `daemonize` 設定に依存せず、必ずフォアグラウンドで起動する(master が背後に残る事故を防ぐ)。
これは全サイト共通で安全な変更(コンテナ内で php-fpm を動かす際の定石)であり、既存の正常稼働サイトの挙動は変わりません。
**復旧手順(重要)**
チャートを `8.5.9-d` に上げても、既存 pod のネットワーク名前空間に残存プロセスがある場合は、その pod を作り直してクリーンな状態にする必要があります。`helm upgrade` で新しい pod に置き換わりますが、置き換わらない場合は crashloop 中の pod を明示的に削除してください。
```bash
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.9-d -f values.yaml
# 置き換わらない場合:
kubectl delete pod -n <namespace> -l app.kubernetes.io/name=phpfpm
```
**対象ファイル**: `templates/deployment.yaml`, `Chart.yaml`, `README.md`, `CLAUDE.md`, `CHANGELOG-8.5.9-d.md`
## アップグレード手順
```bash
helm repo update
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.9-d -f values.yaml
```
---
**リリース日**: 2026-09-06
**担当**: プロサーバーエンジニア(Claude)
+95 -6
View File
@@ -1,27 +1,116 @@
# 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:<tag>-fpm-alpine`)。サブアプリ: nginx
## 実行環境について
**PHP の実行環境(インタープリタ)はこのリポジトリには含まれていない。**
チャートは `docker.io/php:<tag>-fpm-alpine` の公式イメージを Kubernetes 上で起動するものであり、PHP コードそのものは PVC(`/var/www/html`)に別途配置する必要がある。
## Git コミット情報
## 設計上の注意(既知の落とし穴)
| 項目 | 値 |
|------|-----|
| 名前 | Claude |
| メール | claude@cafepieters.com |
| SSH キー | `P:\Claude\.ssh\id_claude` |
- `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(`<release>-phpfpm-selenium`)。同一 Pod のサイドカーには**しない**(Selenium 単体の不調でメインの Pod が Service の Endpoints から外れ、静的ページ配信まで巻き込んで全断する設計だったため分離した)。
## チャート改修履歴
### nginx.customConfig の取り違え防止(ドキュメント修正、2026-10-20, v8.5.11-a)
- **症状 / 背景**: あるプロジェクトのレポートで「`serverSnippet` が効かない。既定の `snippet:` はどのテンプレートも読まない古いキーでは」という指摘があった。別件で、`snippet` に `client_max_body_size` を書いていたプロジェクトが `directive is duplicate` で nginx 起動失敗する障害(2026-09-29)も起きていた。
- **原因**:
- 指摘は誤り。実際に使われる `templates/configmap.yaml` が読むのは `snippet` で、`values.yaml`・README と一致している。`serverSnippet` / `httpSnippet` は、一度も出力されない `templates/configmap-nginx.yaml`(`.Values.nginx.enabled` が values に無く常に偽)だけが読むキーで、values・README に載ったことがない(コミット `31106e0` 由来)。指定すると黙って無視される。
- README 例6・例9 が `snippet` に `client_max_body_size` を書く手順を案内しており、v8.5.9-b 以降は `uploadMaxSize` の自動出力と重複して起動失敗する。例6 はチャート本体と重複する `location ~ \.php$` も再定義していた。
- **修正内容**: 挙動の変更なし(ドキュメント・コメントのみ)。`values.yaml` と README に「読まれるキーは `snippet` のみ、挿入先は server ブロック内、`client_max_body_size` は書かず `uploadMaxSize` を使う」を明記。README 例6・例9 を `uploadMaxSize` 指定に修正。`configmap-nginx.yaml` 先頭に「未使用」の注記を追加。
- **やらなかったこと**: `snippet` を `serverSnippet` に改名する(動いているキーを壊すため)。`serverSnippet` を `snippet` の別名として有効化する(これまで無視されていた設定が突然有効になり、重複で起動失敗する恐れがあるため)。`http` レベルの snippet が必要になった場合は、別途 `configmap.yaml` に正式対応を追加する。
- **対象ファイル**: `values.yaml`, `README.md`, `templates/configmap-nginx.yaml`(コメントのみ), `Chart.yaml`
### Cron(CronJob)定期実行機能を追加(2026-09-27, v8.5.10-e)
- **背景**: 定期実行したいPHPスクリプト(レポート送信・バッチ処理等)を動かす手段がなく、外部で別途スケジューラを用意する必要があった。
- **追加内容**: `cron.jobs`(配列)にジョブを定義すると、`templates/cronjob.yaml`がジョブごとにKubernetes CronJobを生成する。php-fpmと同じPHPイメージを使用し、PVCルートを`/var/www`にマウント、`externalDatabase`/`phpEnv`/`extraEnv`/`extraEnvFrom`/`SELENIUM_URL`をphp-fpmコンテナと同じ内容で注入する。`smtp.enabled: true`の場合はCronJob内でも自動的にmsmtpを導入する(`templates/deployment.yaml`のSMTP設定と重複実装、変更時は両方揃えること)。
- **設計上の注意点**:
- CronJobが生成するPodのラベル(`app.kubernetes.io/name`)は`phpfpm.cron.name`ヘルパーで`<chart>-cron`というバリアント名にしている。Selenium分離(v8.5.10-b)と同じ理由で、nginx/php-fpm DeploymentのmatchLabels(`name: phpfpm, instance: <release>`)と一致させると、ReplicaSetコントローラーがCronJob由来のPodを誤って自身の管理対象とみなし削除する事故につながるため。
- CronJob名は`trunc 52`で切り詰めている(Kubernetesの実務上の制約。CronJobは生成するJob/Pod名にタイムスタンプ等のsuffixが付くため、フルの253/63文字ではなく52文字程度に収める必要がある)。
- Composer(`/composer`)・Python venv(`/venv`)はデフォルトでPVC非マウントの使い捨て領域のため、CronJobのPodには存在しない。意図的にCronJob側では再インストールを行わない設計とした(頻繁な実行での再インストールコストを避けるため)。CronJobから使いたい場合は`composer.workingDir`/`python.venvDir`を`/var/www`配下に変更しPVC上へ永続化することをREADMEで案内している。
- **対象ファイル**: `templates/cronjob.yaml`(新規), `templates/_helpers.tpl`, `values.yaml`, `README.md`, `Chart.yaml`
### ingress.tls[].secretNameをhostから自動導出可能に(2026-09-27, v8.5.10-d)
- **背景**: `ingress.hosts[].host` は既にYAMLアンカー(`&appDomain`)で `ingress.tls[].hosts` と値を共有できるようになっていたが、`ingress.tls[].secretName` は独立した文字列指定が必須で、ドメイン変更時に別途書き換えが必要だった。
- **修正内容**: `templates/ingress.yaml` で `secretName` を省略可能にし、未指定時はそのエントリの最初のhostから自動生成する(`.`を`-`に置換して`-tls`を付与。例: `example.tld` → `example-tld-tls`)。明示的に指定した場合はそちらが優先される(後方互換)。デフォルトの`values.yaml`も自動導出を使う例に更新。
- **対象ファイル**: `templates/ingress.yaml`, `values.yaml`, `README.md`, `Chart.yaml`
### 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`自体を`<chart名>-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(`<release>-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')` で呼び出す。
+2 -2
View File
@@ -2,6 +2,6 @@ apiVersion: v2
name: phpfpm
description: Nginx + PHP-FPM Helm Chart with external DB and optional Selenium support
type: application
version: 8.5.9
appVersion: "8.5.9"
version: 8.5.12
appVersion: "8.5.12"
icon: https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/PHP-logo.svg/330px-PHP-logo.svg.png
+24
View File
@@ -0,0 +1,24 @@
# GEMINI.md — Antigravity (Gemini) 用エントリポイント(HelmChart\phpfpm)
このディレクトリのルールはすべて **`CLAUDE.md`** に記載されている。本ファイルにはルール本文を書かず、読むべき CLAUDE.md への参照だけを置く(正本は常に CLAUDE.md)。
## 必ず最初に実行すること
以下のファイルを**上から順に**読み込み、すべての指示に従うこと。上位ほど広い範囲に適用される共通ルールで、下位は上位を前提とした補足・例外である。
1. `P:\Claude\CLAUDE.md` — 全組織共通ルール(Git 運用・コミット書式・実行環境・情報記載の原則)
2. `P:\Claude\HelmChart\CLAUDE.md` — HelmChart 組織共通ルール
3. `P:\Claude\HelmChart\phpfpm\CLAUDE.md` — phpfpm リポジトリ固有ルール(このディレクトリ)
> Antigravity はワークスペース(または git ルート)直下のルールしか自動で読まず、親フォルダを遡らない。そのため上位階層のパスをここに明示している。`P:\Claude` はクラウド同期されており、デスクトップ・ノート PC とも同じパスで存在する。
## 読み替え
- CLAUDE.md 中の「Claude」「Claude Code」は、Antigravity で作業する場合は Gemini 自身のことと読み替える。
- Git のコミット者は Antigravity でも `user.name = Claude` / `user.email = claude@cafepieters.com` のまま使う(変更しない)。コミットメッセージに AI クレジットを付けない。
- Claude Code 固有の機能(`.claude/` 設定、スキル、メモリ等)に関する記述は無視してよい。
## 保守ルール
- ルールの追加・変更は **CLAUDE.md にのみ**行う。本ファイルと `.agents/rules/claude-md.md` は参照だけを保持し、内容を増やさない。
- CLAUDE.md を新しいディレクトリに追加したときは、同じ形式の `GEMINI.md` と `.agents/rules/claude-md.md` も併置する。
+205 -35
View File
@@ -83,20 +83,20 @@ kubectl logs -l app.kubernetes.io/name=phpfpm -c nginx
│ │ Persistent Volume (PVC) │ │
│ │ /var/www/html │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
│ │
│ ┌─────────────────────────────────────┐ │
│ │ Selenium (Optional) │ │
│ │ :4444 │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ External Database (Optional) │
│ MySQL/MariaDB │
└─────────────────────────────────────────────┘
▼ ▼ SELENIUM_URL(自動注入)
┌─────────────────────────────┐ ┌──────────────────────────────┐
│ External Database (Optional)│ │ Selenium Deployment(Optional)│
│ MySQL/MariaDB │ │ 独立Pod・独立Service :4444 │
└─────────────────────────────┘ └──────────────────────────────┘
```
> **Selenium は独立した Deployment/Service(v8.5.10-b以降)**。以前は上の Pod 内の
> サイドカーコンテナだったが、Selenium 単体の不調(起動失敗・OOM等)で Pod 全体が
> Service の Endpoints から外れ、サイト全体が停止する問題があったため分離した
> (下記トラブルシューティング参照)。
## 主要な設定パラメータ
### 基本設定
@@ -108,6 +108,17 @@ kubectl logs -l app.kubernetes.io/name=phpfpm -c nginx
| `image.nginx.tag` | Nginxバージョン | `1.29.4-alpine-perl` |
| `service.type` | Serviceタイプ | `LoadBalancer` |
| `service.port` | Serviceポート | `80` |
| `uploadMaxSize` | アップロード最大サイズ(nginx/PHP両方に反映) | `"100m"` |
> **📌 アップロードサイズ上限について**
> `uploadMaxSize` の値は、以下**すべて**に同時に反映されます。どれか一つでも小さいと、そこで上限に達して失敗するため、この1つの値で揃える設計です。
> - nginx(Podコンテナ内)の `client_max_body_size`
> - PHPの `upload_max_filesize` / `post_max_size`
> - `ingress.enabled: true` の場合、ingress-nginxの `nginx.ingress.kubernetes.io/proxy-body-size`(明示指定があればそちらが優先)
>
> 単位は `k` / `m` / `g`(大文字小文字問わず)が使用できます(例: `"200m"`, `"1g"`)。
>
> 大きなファイルをPHP側でメモリに読み込んで処理する場合は、PHPの `memory_limit`(デフォルト128M程度)が不足する可能性があります。その場合は `phpEnv` 等ではなくカスタムイメージ、または将来的な設定拡張で対応してください。
### 永続化ストレージ
@@ -164,11 +175,55 @@ PHPからPythonスクリプトを呼び出す用途(データ処理・機械
### Selenium設定
v8.5.10-b以降、Seleniumは独立したDeployment/Service(`<release>-phpfpm-selenium`)として起動する(nginx/php-fpmと同一Podのサイドカーではない)。
| パラメータ | 説明 | デフォルト |
|-----------|------|-----------|
| `selenium.enabled` | Selenium有効化 | `false` |
| `selenium.replicaCount` | Selenium Deploymentのレプリカ数 | `1` |
| `selenium.resources` | SeleniumコンテナのCPU/メモリ requests・limits | `{}` |
| `selenium.mountHtml` | PVCの`html`サブパスをSeleniumにもマウントするか(別Podからの同時マウントになるため`true`にする場合は`persistence.accessMode: ReadWriteMany`が必要) | `false` |
| `image.selenium.tag` | Seleniumバージョン | `144.0-chromedriver-144.0` |
`selenium.enabled: true`のとき、php-fpmコンテナの`SELENIUM_URL`環境変数は自動的にこのServiceを指す値(`http://<release>-phpfpm-selenium:4444/wd/hub`)に設定される。`phpEnv.SELENIUM_URL`を独自に指定していても、この自動注入された値が優先される。
### Cron(定期実行)設定
`cron.jobs`に1件以上定義すると、php-fpmと同じPHPイメージ(`image.php`)を使ってスケジュール実行するKubernetes CronJobが、ジョブごとに1つずつ作成される。既定は空配列で、何も作成されない。
| パラメータ | 説明 | デフォルト |
|-----------|------|-----------|
| `cron.jobs` | CronJob定義の配列 | `[]` |
| `cron.jobs[].name` | ジョブ名(英数字とハイフン、CronJob名の一部に使用) | 必須 |
| `cron.jobs[].schedule` | 標準cron形式のスケジュール | 必須 |
| `cron.jobs[].command` | 実行するシェルコマンド(文字列) | 必須 |
| `cron.jobs[].timeZone` | タイムゾーン(Kubernetes 1.27+) | 省略時UTC |
| `cron.jobs[].concurrencyPolicy` | `Allow`/`Forbid`/`Replace` | `Forbid` |
| `cron.jobs[].restartPolicy` | `OnFailure`/`Never` | `OnFailure` |
| `cron.jobs[].successfulJobsHistoryLimit` | 成功ジョブの保持数 | `3` |
| `cron.jobs[].failedJobsHistoryLimit` | 失敗ジョブの保持数 | `1` |
| `cron.jobs[].activeDeadlineSeconds` | 実行タイムアウト(秒) | 省略可 |
| `cron.jobs[].suspend` | `true`でこのジョブだけ一時停止 | `false` |
| `cron.jobs[].resources` | CPU/メモリ requests・limits | `resources.phpfpm`を流用 |
```yaml
# values.yaml
cron:
jobs:
- name: daily-report
schedule: "0 18 * * *"
timeZone: "Asia/Tokyo"
command: "php /var/www/html/cron/daily-report.php"
```
> **📌 CronJobの構成について**
> - PVCルートを`/var/www`にマウントする(php-fpmコンテナと同じ)。`html/`配下の公開コード、または非公開ディレクトリのスクリプト・出力先どちらも利用できる。
> - `externalDatabase` / `phpEnv` / `extraEnv` / `extraEnvFrom` / `SELENIUM_URL`(selenium有効時)は、php-fpmコンテナと同じ内容が渡される。
> - `smtp.enabled: true`の場合、CronJobのPodでも自動的にmsmtpを導入してmsmtprcを配置するため、PHPの`mail()`関数がそのまま使える。
> - **Composer/Pythonとの併用**: `composer.workingDir`/`python.venvDir`が既定の`/composer`・`/venv`(PVC非マウントの使い捨て領域)のままだと、php-fpmの常駐Pod内にしか存在しないためCronJobからは使えない。CronJobから使いたい場合は`composer.workingDir: "/var/www/composer"`のように`/var/www`配下へ変更し、PVC上に永続化すること。
> - CronJobの名前は52文字を超えないよう自動的に切り詰められる(Kubernetesの制約)。`cron.jobs[].name`は短く分かりやすい名前にすること。
> - 生成されるPodのラベル(`app.kubernetes.io/name`)は`<chart>-cron`というバリアント名になっており、nginx/php-fpmのDeploymentのselectorとは一致しない(Selenium分離と同じ設計)。
### 外部データベース設定
| パラメータ | 説明 | デフォルト |
@@ -185,9 +240,29 @@ PHPからPythonスクリプトを呼び出す用途(データ処理・機械
| パラメータ | 説明 | デフォルト |
|-----------|------|-----------|
| `phpEnv` | PHP-FPM コンテナに渡す任意の環境変数(キーと値のマップ) | `{}` |
| `extraEnvFrom` | 既存の Secret / ConfigMap をまるごと環境変数として注入(`envFrom` 配列) | `[]` |
| `extraEnv` | 個別の環境変数を追加(生の `env` エントリ配列。`valueFrom`/`secretKeyRef` 可) | `[]` |
PHP 側では `$_ENV['KEY']` または `getenv('KEY')` で取得できます。
`extraEnvFrom` は、別リポジトリの **secret-manager** チャートが各ネームスペースへ配布する
`cred-<名前>` Secret(API キー等)をそのまま読み込む用途を想定しています。認証情報の変更は
secret-manager 側を更新するだけで全プロジェクトに反映できます。
```yaml
extraEnvFrom:
- secretRef:
name: cred-gemini # GEMINI_API_KEY 等が丸ごと環境変数になる
- secretRef:
name: cred-openai
extraEnv:
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
name: cred-claude
key: ANTHROPIC_API_KEY
```
### SMTP設定
| パラメータ | 説明 | デフォルト |
@@ -199,10 +274,39 @@ PHP 側では `$_ENV['KEY']` または `getenv('KEY')` で取得できます。
| `smtp.auth.enabled` | 認証有効化 | `true` |
| `smtp.auth.username` | SMTPユーザー名 | `smtp-user@example.com` |
| `smtp.auth.password` | SMTPパスワード | `""` (Secretで指定) |
| `smtp.auth.existingSecret` | パスワードを取得する既存 Secret 名(`smtp.auth.password` と自作 Secret の代わり) | `""` |
| `smtp.auth.existingSecretKey` | 上記 Secret 内のキー名 | `password` |
| `smtp.existingMsmtprcSecret` | 完成済み `msmtprc` を持つ既存 Secret 名。指定時はチャートの msmtprc 生成を行わず host/port/auth.* は無視(`from` のみ使用) | `""` |
| `smtp.existingMsmtprcSecretKey` | 上記 Secret 内の `msmtprc` キー名 | `msmtprc` |
| `smtp.from` | 送信元メールアドレス(固定) | `noreply@example.com` |
| `smtp.tls.verify` | TLS証明書検証 | `true` |
| `smtp.tls.allowSelfSigned` | 自己署名証明書を許可 | `false` |
#### secret-manager チャートとの連携(メール設定の一元管理)
**secret-manager** が `cred-gmail` などに生成する完成済み `msmtprc` をそのまま使う場合:
```yaml
smtp:
enabled: true
from: "no-reply@your-domain.com" # PHP の sendmail_from 用に必要
existingMsmtprcSecret: "cred-gmail" # このSecretの msmtprc キーをそのまま利用
```
サーバ設定はチャート側 values に残し、パスワードだけ一元管理したい場合:
```yaml
smtp:
enabled: true
host: "smtp.gmail.com"
port: 587
auth:
enabled: true
username: "no-reply@your-domain.com"
existingSecret: "cred-gmail"
existingSecretKey: "SMTP_PASSWORD"
```
### Ingress設定
| パラメータ | 説明 | デフォルト |
@@ -211,20 +315,36 @@ PHP 側では `$_ENV['KEY']` または `getenv('KEY')` で取得できます。
| `ingress.className` | IngressClass名 | `""` |
| `ingress.annotations` | アノテーション | `{}` |
| `ingress.hosts` | ホスト設定 | `[{host: "example.tld"}]` |
| `ingress.tls` | TLS設定 | `[]` |
| `ingress.tls` | TLS設定(`secretName`省略可) | `[]` |
> **📌 Ingressのアップロードサイズ上限**
> `ingress.enabled: true` の場合、`nginx.ingress.kubernetes.io/proxy-body-size` アノテーションが `uploadMaxSize` の値で**自動的に**付与されます(明示的に `ingress.annotations` へ指定した場合はそちらが優先されます)。Ingressコントローラーがnginx以外の場合は、`ingress.annotations` にそのコントローラー向けの上限設定を明示的に指定してください。
> **📌 hostとTLS secretNameの共有**
> `ingress.hosts[].host` にYAMLアンカー(例: `&appDomain`)を付けておくと、`ingress.tls[].hosts` で `*appDomain` として再利用でき、ドメイン名を1箇所の変更で揃えられます(デフォルトのvalues.yamlも参照)。
> さらに `ingress.tls[].secretName` は**省略可能**で、省略した場合はそのエントリの最初のhostから自動生成されます(`.`を`-`に置換して`-tls`を付与。例: `example.tld` → `example-tld-tls`)。別の証明書Secret名を使いたい場合のみ `secretName` を明示的に指定してください(指定時はそちらが優先されます)。
### Nginx設定
| パラメータ | 説明 | デフォルト |
|-----------|------|-----------|
| `nginx.customConfig.enabled` | カスタム設定有効化 | `false` |
| `nginx.customConfig.snippet` | 設定スニペット | `""` |
| `nginx.customConfig.snippet` | `server { }` ブロック末尾へそのまま挿入するnginx設定(下記注意参照) | `""` |
| `nginx.forwardRealIP.enabled` | リアルIP取得有効化 | `false` |
| `nginx.forwardRealIP.header` | リアルIP取得ヘッダー | `"X-Forwarded-For"` |
| `nginx.forwardRealIP.recursive` | 再帰的IP検索 | `true` |
| `nginx.forwardRealIP.trustedProxies` | 信頼するプロキシネットワーク | `["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]` |
| `nginx.forwardRealIP.additionalTrustedProxies` | 追加の信頼プロキシ | `[]` |
> **📌 `nginx.customConfig.snippet` の注意点**
> - 読まれるキーは `snippet` のみです。`serverSnippet` / `httpSnippet` というキーは存在せず、指定しても**無視されます**(過去に作られた未使用テンプレート `configmap-nginx.yaml` 専用のキーで、一度も出力されたことがありません)。
> - 挿入先は `server { }` ブロック内です。`limit_req_zone` など `http` レベル専用のディレクティブは書けません。
> - チャートが自動で出力する設定を重複して書くと、nginxが起動しなくなります。特に **`client_max_body_size` は書かないでください**(`directive is duplicate` で起動失敗)。アップロード上限は `uploadMaxSize` で設定します。
> **📌 sitemap.xml のContent-Type**
> `/sitemap.xml`(静的ファイルとして配置した場合)は、常に `Content-Type: application/xml; charset=utf-8` で配信されます。標準の `mime.types` では `.xml` が `text/xml` 扱いでcharsetが付かず、ブラウザやGoogle Search Consoleなどのツールが正しく解釈できない場合があるための組み込み対応です(設定不要、常時有効)。
> なお、PHPで動的に生成する場合はこの設定は適用されません(PHP側で `header('Content-Type: application/xml; charset=utf-8');` を指定してください)。
## 使用例
### 例1: シンプルなPHPアプリケーション
@@ -360,19 +480,26 @@ composer:
- "monolog/monolog:^3.0"
selenium:
enabled: true # php-webdriver/webdriverが自動追加
enabled: true # php-webdriver/webdriverが自動追加。独立Deployment/Serviceとして起動する
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "3Gi"
cpu: "2000m"
persistence:
enabled: true
size: 5Gi
resources:
requests:
memory: "1Gi"
cpu: "1000m"
limits:
memory: "3Gi"
cpu: "2000m"
nginx:
requests: { memory: "64Mi", cpu: "50m" }
limits: { memory: "128Mi" }
phpfpm:
requests: { memory: "256Mi", cpu: "200m" }
limits: { memory: "512Mi", cpu: "1000m" }
```
**PHPコード例**:
@@ -383,9 +510,10 @@ require_once '/composer/vendor/autoload.php';
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
// Seleniumに接続
// Seleniumに接続(SELENIUM_URLはselenium.enabled:trueのとき自動注入される。
// 別Deploymentになったため localhost では到達できない点に注意)
$driver = RemoteWebDriver::create(
'http://localhost:4444',
getenv('SELENIUM_URL') ?: 'http://<release>-phpfpm-selenium:4444/wd/hub',
DesiredCapabilities::chrome()
);
@@ -398,21 +526,20 @@ $driver->quit();
```yaml
# values.yaml
# アップロード上限は snippet ではなく uploadMaxSize で設定する
# (nginx の client_max_body_size を snippet に書くと、チャートの自動出力と重複して起動失敗する)
uploadMaxSize: "100m"
nginx:
customConfig:
enabled: true
# server { } ブロックの末尾にそのまま挿入される。
# PHPの location ~ \.php$ はチャート本体が定義済みのため、ここでは再定義しない
# (タイムアウト等は server レベルで指定すれば PHP の location にも継承される)
snippet: |
client_max_body_size 100M;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 300;
fastcgi_send_timeout 300;
}
location /admin {
auth_basic "Administrator Area";
@@ -423,6 +550,8 @@ persistence:
enabled: true
```
> `snippet` で指定する際の注意点は、[Nginx設定](#nginx設定)の「`nginx.customConfig.snippet` の注意点」を参照してください。
### 例7: ベアメタル環境でのリアルIP取得
ベアメタルKubernetesやLoadBalancer経由でのアクセスで、PHPからクライアントの実IPアドレスを取得する設定です。
@@ -583,11 +712,13 @@ ingress:
hosts:
- api.production.com
# アップロード上限は snippet ではなく uploadMaxSize で設定する
uploadMaxSize: "50m"
nginx:
customConfig:
enabled: true
snippet: |
client_max_body_size 50M;
fastcgi_read_timeout 300;
# Opcache設定
@@ -849,6 +980,45 @@ composer:
- "autoconf"
```
### php-fpm が CrashLoopBackOff/全リクエストが 502(`Address in use` / `unsupported FastCGI protocol version: 60`)
**症状**: php-fpm コンテナが `CrashLoopBackOff` になり、nginx ログに `upstream sent unsupported FastCGI protocol version: 60`、php-fpm ログに次が出る。
```
[ERROR] unable to bind listening socket for address '9000': Address in use (98)
[ERROR] FPM initialization failed
```
**原因**: php-fpm が 9000 を bind できず起動失敗し、nginx が非 FastCGI 応答を受けて 502 になる。v8.5.9-c 以前は php-fpm を setup シェルの子プロセスとして起動していたため、コンテナ再起動時に PID1 のシェルが `SIGTERM` を子へ転送せず、旧 php-fpm が残存して 9000 を握ったまま次回起動が二重 bind で失敗する自己増殖ループに陥ることがあった。
**対策**: **v8.5.9-d 以降にアップグレードする**(起動を `exec php-fpm -F` に変更済み。php-fpm が PID1 になりシグナルを直接受けて 9000 を確実解放、`-F` で必ずフォアグラウンド起動)。アップグレード後も残存プロセスを持つ既存 pod が残る場合は作り直す。
```bash
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.9-d -f values.yaml
kubectl delete pod -n <namespace> -l app.kubernetes.io/name=phpfpm
```
### `selenium.enabled: true` でコンテナが不安定になるとサイト全体が完全停止する
**症状**: `selenium.enabled: true` の構成で、いずれかのコンテナ(php-fpm・Selenium 等)が `CrashLoopBackOff` になっている間、Selenium を全く使わない静的ページも含めてサイト全体が閲覧不能(502等)になる。`kubectl get pod` で `2/3` や `1/3` の READY 表示が続く。
**原因**: v8.5.10-b より前は Selenium が nginx/php-fpm と同一 Pod のサイドカーコンテナだった。Kubernetes は Pod の Ready 条件を「全コンテナが Ready」の AND で判定するため、readinessProbe を持たないコンテナは Running であれば Ready 扱いになる一方、いずれか1つでも CrashLoopBackOff で Waiting/Terminated を繰り返している間は Pod 全体が Ready=false になる。Service は Ready な Pod にしかトラフィックを流さないため、`replicaCount: 1`(冗長性なし)の構成では **1つのコンテナの不調がサイト全体の完全停止に直結していた**。
これに加えて、`resources` values キーが v8.5.10-a 以前はテンプレート側で参照されておらず、どのコンテナにも requests/limits が反映されない「死んだ設定」だった。全コンテナが `QoS Class: BestEffort` になり、ノードのメモリ逼迫時に OOM Killer の対象になりやすい状態だった(Chromium を含む Selenium は特にメモリを消費するため、この影響を受けやすい)。
**対策**: **v8.5.10-c 以降にアップグレードする**(v8.5.10-b は既存リリースの
アップグレードが `spec.selector: ... field is immutable` で失敗する不具合を含むため、
v8.5.10-b を経由せず直接 v8.5.10-c 以降を使うこと。詳細は `CHANGELOG-8.5.10-c.md`)。
1. Selenium が独立した Deployment/Service(`<release>-phpfpm-selenium`)になり、Selenium 単体の不調がメイン Pod(nginx/php-fpm)の Ready 状態に一切影響しなくなった。
2. `resources.nginx` / `resources.phpfpm` / `selenium.resources` で実際に requests/limits を設定できるようになった。本番運用では設定を強く推奨する(未設定のままだと引き続き BestEffort のままで、OOM Kill のリスクは残る)。
```bash
helm upgrade <リリース名> cafepieters/phpfpm --version 8.5.10-c -f values.yaml
```
アップグレード後に確認すべき点は `CHANGELOG-8.5.10-b.md` の「互換性(重要・要対応)」を参照(`selenium.mountHtml` / `phpEnv.SELENIUM_URL` の扱い)。
### データベース接続エラー
**確認**:
@@ -869,8 +1039,8 @@ kubectl logs <pod-name> -c php-fpm
# Nginxログ
kubectl logs <pod-name> -c nginx
# Seleniumログ(有効時)
kubectl logs <pod-name> -c selenium
# Seleniumログ(有効時。v8.5.10-b以降は別Pod・別Deploymentのため -c 指定は不要)
kubectl logs -l app.kubernetes.io/component=selenium
# リアルタイム監視
kubectl logs -f <pod-name> -c php-fpm
@@ -1049,7 +1219,7 @@ kubectl cp ./my-app <pod-name>:/var/www/html/ -c php-fpm
- [Composer使用ガイド](./COMPOSER_GUIDE.md)
- [マイグレーションガイド](./MIGRATION_GUIDE.md)
- [Selenium別チャート化設計](./SELENIUM_SEPARATION_DESIGN.md)
- Selenium別Deployment化の設計・経緯は本READMEの「Selenium設定」セクションと `CHANGELOG-8.5.10-b.md`(設計)・`CHANGELOG-8.5.10-c.md`(既存リリースのアップグレードを壊す不具合の修正)を参照(旧: 本リンク先の設計ドキュメントは作成されず実装が先行したため削除)
## ライセンス
+42
View File
@@ -19,3 +19,45 @@ app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/name: {{ include "phpfpm.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Selenium 用の名前・セレクタラベル(v8.5.10-b)。
nginx/php-fpm の既存 Deployment は spec.selector が作成後 immutable なため、
そちらの selector には手を加えられない("field is immutable" でアップグレードが
失敗する)。そのため Selenium 側は app.kubernetes.io/name 自体を variant
("phpfpm-selenium")にして、nginx/php-fpm の Deployment の selector
(name=phpfpm, instance=<release>)とラベルの組が完全に一致しないようにする。
component ラベルだけを足す設計だと、Selenium の Pod も name=phpfpm/instance=<release>
を持つため nginx/php-fpm 側 Deployment の selector にも一致してしまい、
2つの Deployment(ReplicaSet)が同じ Pod 集合を取り合う selector 重複を起こす。
name を variant にすることで、この重複を構造的に防止する。
*/}}
{{- define "phpfpm.selenium.name" -}}
{{- printf "%s-selenium" (include "phpfpm.name" .) | trunc 63 | trimSuffix "-" -}}
{{- end }}
{{- define "phpfpm.selenium.selectorLabels" -}}
app.kubernetes.io/name: {{ include "phpfpm.selenium.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Cron(CronJob)用の名前・ラベル(v8.5.10-e)。
Selenium と同じ理由で、CronJobが生成するPodのラベルにも nginx/php-fpm の
Deployment と同じ app.kubernetes.io/name("phpfpm")+ instance を持たせては
いけない。同じ組み合わせだとDeploymentのReplicaSetコントローラーが
matchLabels(name=phpfpm, instance=<release>)に一致するPodとしてCronJob由来
のPodまで対象に含めてしまい、replicaCountとの差分調整でCronJobのPodを
意図せず削除する等の事故につながる。name自体をvariant("phpfpm-cron")に
することで構造的に衝突を防ぐ。
*/}}
{{- define "phpfpm.cron.name" -}}
{{- printf "%s-cron" (include "phpfpm.name" .) | trunc 63 | trimSuffix "-" -}}
{{- end }}
{{- define "phpfpm.cron.selectorLabels" -}}
app.kubernetes.io/name: {{ include "phpfpm.cron.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
+8
View File
@@ -1,3 +1,11 @@
{{- /*
【未使用】このファイルは出力されない。
下の if が参照する .Values.nginx.enabled は values.yaml に存在しないため、常に偽になる。
実際に使われる nginx 設定は templates/configmap.yaml(deployment.yaml が nginx.conf キーを
マウントしている)。カスタム設定として読まれるのは nginx.customConfig.snippet のみで、
このファイルだけが読む serverSnippet / httpSnippet は指定しても無視される。
nginx の設定を変更する場合は configmap.yaml を編集すること。
*/ -}}
{{- if .Values.nginx.enabled }}
apiVersion: v1
kind: ConfigMap
+1 -1
View File
@@ -1,4 +1,4 @@
{{- if .Values.smtp.enabled }}
{{- if and .Values.smtp.enabled (not .Values.smtp.existingMsmtprcSecret) }}
apiVersion: v1
kind: ConfigMap
metadata:
+12
View File
@@ -55,6 +55,18 @@ data:
root /var/www/html;
index index.php index.html index.htm;
# アップロード可能な最大サイズ(PHP側のupload_max_filesize/post_max_sizeと連動)
client_max_body_size {{ .Values.uploadMaxSize }};
# sitemap.xml のContent-Typeを明示的に指定
# 標準のmime.typesでは .xml は text/xml 扱いでcharsetが付かず、
# ブラウザやSearch Consoleが正しく解釈できない場合があるため
location = /sitemap.xml {
types { }
default_type "application/xml; charset=utf-8";
try_files $uri =404;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
+157
View File
@@ -0,0 +1,157 @@
{{- range .Values.cron.jobs }}
---
# CronJobのPodは、nginx/php-fpmのDeploymentとは別のReplicaSetに属するため、
# jobTemplate.spec.template.metadata.labels には phpfpm.cron.selectorLabels
# (app.kubernetes.io/name: <chart>-cron)を使う。ここで通常の
# phpfpm.selectorLabels(name: phpfpm)を使ってしまうと、nginx/php-fpm
# DeploymentのmatchLabelsと一致するPodが増え、ReplicaSetコントローラーが
# replicaCountとの差分調整でCronJob由来のPodを意図せず削除する事故につながる
# (Selenium分離(v8.5.10-b)と同じ理由)。
apiVersion: batch/v1
kind: CronJob
metadata:
name: {{ printf "%s-cron-%s" (include "phpfpm.fullname" $) .name | trunc 52 | trimSuffix "-" }}
labels:
{{- include "phpfpm.labels" $ | nindent 4 }}
app.kubernetes.io/component: cron
spec:
schedule: {{ .schedule | quote }}
{{- if .timeZone }}
timeZone: {{ .timeZone | quote }}
{{- end }}
concurrencyPolicy: {{ .concurrencyPolicy | default "Forbid" }}
{{- if hasKey . "suspend" }}
suspend: {{ .suspend }}
{{- end }}
successfulJobsHistoryLimit: {{ .successfulJobsHistoryLimit | default 3 }}
failedJobsHistoryLimit: {{ .failedJobsHistoryLimit | default 1 }}
jobTemplate:
spec:
{{- if .activeDeadlineSeconds }}
activeDeadlineSeconds: {{ .activeDeadlineSeconds }}
{{- end }}
template:
metadata:
labels:
{{- include "phpfpm.cron.selectorLabels" $ | nindent 12 }}
app.kubernetes.io/component: cron
spec:
restartPolicy: {{ .restartPolicy | default "OnFailure" }}
containers:
- name: cron
image: "{{ $.Values.image.php.registry }}/{{ $.Values.image.php.repository }}:{{ $.Values.image.php.tag }}"
imagePullPolicy: {{ $.Values.image.php.pullPolicy }}
command:
- sh
- -c
- |
echo "Starting cron job: {{ .name }}"
{{- if $.Values.smtp.enabled }}
# ========================================
# SMTP設定(msmtp) — templates/deployment.yaml のSMTP設定と同じ内容。
# 変更する場合は両方のファイルを揃えること。
# ========================================
echo "Installing msmtp for mail sending..."
apk add --no-cache msmtp ca-certificates
cp /etc/smtp-config/msmtprc /etc/msmtprc
chmod 644 /etc/msmtprc
cat > /usr/local/etc/php/conf.d/99-smtp.ini << 'PHP_SMTP_EOF'
sendmail_path = "/usr/bin/msmtp -t"
sendmail_from = "{{ $.Values.smtp.from }}"
PHP_SMTP_EOF
{{- end }}
echo "Running: {{ .command }}"
{{ .command }}
{{- with (.resources | default $.Values.resources.phpfpm) }}
resources:
{{- toYaml . | nindent 16 }}
{{- end }}
volumeMounts:
# php-fpmコンテナと同様、PVCルートを/var/wwwにマウントする。
# html/ は公開コード、それ以外は非公開ファイルの置き場として利用できる。
- name: app-storage
mountPath: /var/www
{{- if $.Values.smtp.enabled }}
- name: smtp-config
mountPath: /etc/smtp-config
readOnly: true
{{- if and $.Values.smtp.auth.enabled (not $.Values.smtp.existingMsmtprcSecret) }}
- name: smtp-secrets
mountPath: /etc/smtp-secrets
readOnly: true
{{- end }}
{{- end }}
env:
{{- if $.Values.externalDatabase.enabled }}
- name: DB_HOST
value: {{ $.Values.externalDatabase.host | quote }}
- name: DB_PORT
value: {{ $.Values.externalDatabase.port | quote }}
- name: DB_NAME
value: {{ $.Values.externalDatabase.database | quote }}
- name: DB_USER
value: {{ $.Values.externalDatabase.username | quote }}
- name: DB_PASS
valueFrom:
secretKeyRef:
name: {{ include "phpfpm.fullname" $ }}-db-secret
key: {{ include "phpfpm.fullname" $ }}-db-key
{{- end }}
{{- range $key, $value := $.Values.phpEnv }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- if $.Values.selenium.enabled }}
- name: SELENIUM_URL
value: "http://{{ include "phpfpm.fullname" $ }}-selenium:4444/wd/hub"
{{- end }}
{{- with $.Values.extraEnv }}
{{- toYaml . | nindent 16 }}
{{- end }}
{{- with $.Values.extraEnvFrom }}
envFrom:
{{- toYaml . | nindent 16 }}
{{- end }}
dnsPolicy: ClusterFirst
dnsConfig:
options:
- name: ndots
value: "1"
volumes:
- name: app-storage
{{- if $.Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ include "phpfpm.fullname" $ }}-pvc
{{- else }}
emptyDir: {}
{{- end }}
{{- if $.Values.smtp.enabled }}
- name: smtp-config
{{- if $.Values.smtp.existingMsmtprcSecret }}
secret:
secretName: {{ $.Values.smtp.existingMsmtprcSecret }}
items:
- key: {{ $.Values.smtp.existingMsmtprcSecretKey | default "msmtprc" }}
path: msmtprc
{{- else }}
configMap:
name: {{ include "phpfpm.fullname" $ }}-smtp-config
items:
- key: msmtprc
path: msmtprc
{{- end }}
{{- if and $.Values.smtp.auth.enabled (not $.Values.smtp.existingMsmtprcSecret) }}
- name: smtp-secrets
secret:
secretName: {{ $.Values.smtp.auth.existingSecret | default (printf "%s-smtp" (include "phpfpm.fullname" $)) }}
items:
- key: {{ $.Values.smtp.auth.existingSecretKey | default "password" }}
path: password
mode: 0644
{{- end }}
{{- end }}
{{- end }}
+67
View File
@@ -0,0 +1,67 @@
{{- if .Values.selenium.enabled }}
# Selenium を nginx/php-fpm と別 Deployment にする理由(v8.5.10-b):
#
# 以前は selenium/standalone-chromium を nginx・php-fpm と同一 Pod のサイドカー
# コンテナとして起動していた。Kubernetes は Pod の Ready 条件を「全コンテナが Ready」
# の AND で判定するため、readinessProbe を持たないコンテナは「Running であれば Ready」
# として扱われる一方、CrashLoopBackOff で Waiting/Terminated を繰り返す間は Ready=false
# になる。この間 Pod 全体が Service の Endpoints から外れるため、Selenium コンテナ
# だけが不安定(起動失敗・OOM等)でも、Selenium を全く使わない静的ページの配信まで
# 巻き込まれてサービス全体が完全停止していた。
#
# Selenium を独立した Deployment/Service に分離することで、Selenium の不調が
# nginx/php-fpm Pod の Ready 状態に一切影響しなくなり、スクレイピング機能のみが
# 影響を受け、サイト自体は表示され続ける。
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "phpfpm.fullname" . }}-selenium
labels:
{{- include "phpfpm.labels" . | nindent 4 }}
app.kubernetes.io/component: selenium
spec:
replicas: {{ .Values.selenium.replicaCount | default 1 }}
selector:
matchLabels:
{{- include "phpfpm.selenium.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "phpfpm.selenium.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: selenium
spec:
containers:
- name: selenium
image: "{{ .Values.image.selenium.registry }}/{{ .Values.image.selenium.repository }}:{{ .Values.image.selenium.tag }}"
imagePullPolicy: {{ .Values.image.selenium.pullPolicy }}
ports:
- containerPort: 4444 # Selenium用ポート
{{- with .Values.selenium.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.selenium.mountHtml }}
volumeMounts:
- name: app-storage
mountPath: /var/www/html
subPath: html
{{- end }}
dnsPolicy: ClusterFirst
dnsConfig:
options:
- name: ndots
value: "1"
{{- if .Values.selenium.mountHtml }}
volumes:
- name: app-storage
# 別 Pod から同じ PVC の html/ サブパスを読み書きするため、
# persistence.accessMode を ReadWriteMany にする必要がある
# (NFS バックエンドの StorageClass なら対応可能)。
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ include "phpfpm.fullname" . }}-pvc
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
{{- end }}
+58 -14
View File
@@ -7,12 +7,18 @@ metadata:
spec:
replicas: {{ .Values.replicaCount }}
selector:
# 注意: Deployment.spec.selector は作成後 immutable。既存リリースの
# アップグレードを壊さないため、ここに app.kubernetes.io/component は
# 追加しない(component ラベルは下の pod template と Service の
# selector のみに付与する。template.metadata.labels は matchLabels の
# superset であればよいため、追加ラベルを持たせても問題ない)。
matchLabels:
{{- include "phpfpm.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "phpfpm.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: web
spec:
containers:
- name: nginx
@@ -20,6 +26,10 @@ spec:
imagePullPolicy: {{ .Values.image.nginx.pullPolicy }}
ports:
- containerPort: 80
{{- with .Values.resources.nginx }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- name: app-storage
mountPath: /var/www/html
@@ -36,6 +46,14 @@ spec:
- |
echo "Starting PHP-FPM setup process..."
# ========================================
# アップロードサイズ上限(nginxのclient_max_body_sizeと連動)
# ========================================
cat > /usr/local/etc/php/conf.d/99-uploads.ini << 'UPLOADS_INI_EOF'
upload_max_filesize = {{ .Values.uploadMaxSize }}
post_max_size = {{ .Values.uploadMaxSize }}
UPLOADS_INI_EOF
{{- if or .Values.composer.enabled .Values.selenium.enabled .Values.externalDatabase.enabled .Values.python.enabled }}
# ========================================
# APKパッケージのインストール
@@ -244,9 +262,22 @@ spec:
{{- end }}
echo "Setup complete, starting PHP-FPM..."
php-fpm
# exec で php-fpm をコンテナの PID1 に置き換える。
# 目的: setup シェルを介さず php-fpm 自身が SIGTERM/SIGKILL を直接受け取れる
# ようにする。シェルは既定で子プロセスへシグナルを転送しないため、exec せず
# `php-fpm`(子)のまま起動すると、コンテナ再起動時にシェル(PID1)だけが落ちて
# 旧 php-fpm が一時的に残存し、9000 を握ったまま次回起動が
# 「unable to bind ... '9000': Address in use」で失敗して CrashLoopBackOff に陥る。
# exec すれば php-fpm が PID1 になり、停止時に 9000 が確実に解放される。
# -F(--nodaemonize): 設定に依存せず必ずフォアグラウンドで起動する
# (デーモン化して master が背後に残る事故を防ぐ)。
exec php-fpm -F
ports:
- containerPort: 9000 # PHP-FPMは9000ポートでリッスン
{{- with .Values.resources.phpfpm }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
# PVCルートを /var/www にマウント
# - /var/www/html のみ nginx が公開(nginx側は html サブパスだけをマウント)
@@ -263,7 +294,7 @@ spec:
- name: smtp-config
mountPath: /etc/smtp-config
readOnly: true
{{- if .Values.smtp.auth.enabled }}
{{- if and .Values.smtp.auth.enabled (not .Values.smtp.existingMsmtprcSecret) }}
- name: smtp-secrets
mountPath: /etc/smtp-secrets
readOnly: true
@@ -290,15 +321,19 @@ spec:
value: {{ $value | quote }}
{{- end }}
{{- if .Values.selenium.enabled }}
- name: selenium
image: "{{ .Values.image.selenium.registry }}/{{ .Values.image.selenium.repository }}:{{ .Values.image.selenium.tag }}"
imagePullPolicy: {{ .Values.image.selenium.pullPolicy }}
ports:
- containerPort: 4444 # Selenium用ポート
volumeMounts:
- name: app-storage
mountPath: /var/www/html
subPath: html
# Selenium は別 Deployment/Service(templates/deployment-selenium.yaml)として
# 稼働する(v8.5.10-b 以降。selenium.enabled=true の Pod と同居させない設計に変更)。
# phpEnv に SELENIUM_URL を書いても、この行が env リストの後方にあるため
# 最終的にこちらが優先される(Kubernetes は同名 env の重複時、後方の値を採用する)。
- name: SELENIUM_URL
value: "http://{{ include "phpfpm.fullname" . }}-selenium:4444/wd/hub"
{{- end }}
{{- with .Values.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.extraEnvFrom }}
envFrom:
{{- toYaml . | nindent 12 }}
{{- end }}
dnsPolicy: ClusterFirst
dnsConfig:
@@ -323,17 +358,26 @@ spec:
{{- end }}
{{- if .Values.smtp.enabled }}
- name: smtp-config
{{- if .Values.smtp.existingMsmtprcSecret }}
# 完成済み msmtprc を持つ既存 Secret(secret-manager の cred-* 等)を利用
secret:
secretName: {{ .Values.smtp.existingMsmtprcSecret }}
items:
- key: {{ .Values.smtp.existingMsmtprcSecretKey | default "msmtprc" }}
path: msmtprc
{{- else }}
configMap:
name: {{ include "phpfpm.fullname" . }}-smtp-config
items:
- key: msmtprc
path: msmtprc
{{- if .Values.smtp.auth.enabled }}
{{- end }}
{{- if and .Values.smtp.auth.enabled (not .Values.smtp.existingMsmtprcSecret) }}
- name: smtp-secrets
secret:
secretName: {{ include "phpfpm.fullname" . }}-smtp
secretName: {{ .Values.smtp.auth.existingSecret | default (printf "%s-smtp" (include "phpfpm.fullname" .)) }}
items:
- key: password
- key: {{ .Values.smtp.auth.existingSecretKey | default "password" }}
path: password
# 0600だとSecretボリュームの所有者はroot、
# msmtpはPHP-FPMワーカー(www-data等の非root)から実行されるため読めない
+6 -2
View File
@@ -6,7 +6,9 @@ metadata:
labels:
{{- include "phpfpm.labels" . | nindent 4 }}
annotations:
{{- toYaml .Values.ingress.annotations | nindent 4 }}
{{- /* uploadMaxSize を ingress-nginx の proxy-body-size に自動反映(明示指定があればそちらを優先) */}}
{{- $ingressAnnotations := merge (deepCopy .Values.ingress.annotations) (dict "nginx.ingress.kubernetes.io/proxy-body-size" .Values.uploadMaxSize) }}
{{- toYaml $ingressAnnotations | nindent 4 }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
@@ -29,7 +31,9 @@ spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- secretName: {{ .secretName }}
{{- /* secretName省略時は、このエントリの最初のhostから自動生成する(例: example.tld → example-tld-tls)。
明示的に指定した場合はそちらを優先する。 */}}
- secretName: {{ .secretName | default (printf "%s-tls" ((first .hosts) | replace "." "-")) }}
hosts:
{{- range .hosts }}
- {{ . }}
+1 -1
View File
@@ -1,4 +1,4 @@
{{- if .Values.smtp.enabled }}
{{- if and .Values.smtp.enabled (not .Values.smtp.existingMsmtprcSecret) (not .Values.smtp.auth.existingSecret) }}
apiVersion: v1
kind: Secret
metadata:
+18
View File
@@ -0,0 +1,18 @@
{{- if .Values.selenium.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "phpfpm.fullname" . }}-selenium
labels:
{{- include "phpfpm.labels" . | nindent 4 }}
app.kubernetes.io/component: selenium
spec:
type: ClusterIP
ports:
- port: 4444
targetPort: 4444
protocol: TCP
name: selenium
selector:
{{- include "phpfpm.selenium.selectorLabels" . | nindent 4 }}
{{- end }}
+1
View File
@@ -13,3 +13,4 @@ spec:
name: http
selector:
{{- include "phpfpm.selectorLabels" . | nindent 4 }}
app.kubernetes.io/component: web
+155 -23
View File
@@ -4,46 +4,59 @@ image:
nginx:
registry: docker.io
repository: nginx
tag: "1.31.3-alpine-perl"
tag: "1.31.8-alpine-perl"
pullPolicy: IfNotPresent
php:
registry: docker.io
repository: php
tag: "8.5.9-fpm-alpine3.24"
tag: "8.5.12-fpm-alpine3.24"
pullPolicy: IfNotPresent
selenium:
registry: docker.io
repository: selenium/standalone-chromium
tag: "150.0-chromedriver-150.0"
tag: "155.0-chromedriver-155.0"
pullPolicy: IfNotPresent
service:
# type: ClusterIP
type: LoadBalancer
type: ClusterIP
# type: LoadBalancer
port: 80
# アップロード可能な最大サイズ
# 以下3箇所に同じ値を反映する(どれか一つでも小さいと、そこで上限に達して失敗するため):
# - nginx(Podコンテナ内)の client_max_body_size
# - PHPの upload_max_filesize / post_max_size
# - ingress.enabled: true の場合、ingress-nginxの nginx.ingress.kubernetes.io/proxy-body-size
# 単位はnginx/PHP共通でk/m/g(大文字小文字問わず)が使用可能(例: "100m", "1g")
uploadMaxSize: "100m"
ingress:
enabled: false
className: ""
annotations: {}
# {
# acme.cert-manager.io/http01-ingress-class: "nginx",
# cert-manager.io/cluster-issuer: "letsencrypt-issuer",
# nginx.ingress.kubernetes.io/from-to-www-redirect: "true",
# nginx.ingress.kubernetes.io/proxy-body-size: "100m"
# }
# nginx.ingress.kubernetes.io/proxy-body-size は uploadMaxSize の値が自動的に付与されるため
# 明示的に指定する必要はない(Ingress側の上限もnginx/PHPと揃う)
# 別の値にしたい場合や別コントローラーを使う場合は、ここに明示指定すれば上書きされる
annotations:
{
acme.cert-manager.io/http01-ingress-class: "nginx",
cert-manager.io/cluster-issuer: "letsencrypt-issuer",
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
}
hosts:
- host: example.tld
- host: &appDomain example.tld
paths:
- path: /
pathType: Prefix
tls: []
# [
# {
# hosts: [ "example.com" ],
# secretName: "example-tls"
# }
# ]
# secretNameは省略可能。省略した場合、そのエントリの最初のhostの"."を"-"に
# 置換し"-tls"を付与した値が自動生成される(例: example.tld → example-tld-tls)。
# appDomainの変更だけでhostとsecretNameが揃うため、通常は明示指定しなくてよい。
# 別の証明書Secret名にしたい場合のみ secretName: "your-secret-name" を追加する。
tls:
[
{
hosts: [*appDomain]
}
]
persistence:
enabled: true
@@ -51,6 +64,16 @@ persistence:
size: 1Gi
nginx:
# 独自のnginx設定を、server { } ブロックの末尾へそのまま挿入する(templates/configmap.yaml)。
# 読まれるキーは snippet のみ。serverSnippet / httpSnippet は未使用の
# templates/configmap-nginx.yaml 専用で出力されないため、指定しても無視される。
# また挿入先は server ブロック内のため、http レベル専用のディレクティブ
# (limit_req_zone 等)は書けない。
#
# 【重複注意】以下はチャートが自動で出力するため snippet に書かない
# (書くと "directive is duplicate" 等で nginx が起動しなくなる):
# - client_max_body_size → uploadMaxSize で設定する
# - location = /sitemap.xml(Content-Typeの明示)
customConfig:
enabled: false
snippet: |-
@@ -58,7 +81,7 @@ nginx:
# リアルIP転送設定(ベアメタル/LoadBalancer環境向け)
forwardRealIP:
# リアルIP取得機能を有効化
enabled: false
enabled: true
# リアルIPを取得するヘッダー名
# LoadBalancer/Ingressによって異なる
@@ -169,9 +192,62 @@ python:
# - "python3-dev"
# - "jpeg-dev"
# Selenium設定(レガシー互換性維持)
# Selenium設定
# v8.5.10-b以降、Selenium(有効時)はnginx/php-fpmと同一Podのサイドカーではなく、
# 独立したDeployment/Service(<release>-phpfpm-selenium)として起動する。
# 理由: サイドカー方式だとSelenium単体の不調(起動失敗・OOM等)でPod全体がReady=false
# になり、Seleniumを使わない静的ページ配信まで巻き込まれてサービス全体が止まっていた。
# php-fpmコンテナのSELENIUM_URL環境変数は、enabled:true時に自動でこのServiceを指す
# (phpEnvで独自に設定しても、こちらの値が優先される)。
selenium:
enabled: false
# Selenium Deployment自体のレプリカ数
replicaCount: 1
# Chromiumはメモリを多く使う。ノードのメモリ枯渇によるOOM Killを防ぐため、
# 実運用では必ずrequests/limitsを設定することを推奨する(下記resourcesセクション参照)。
resources: {}
# trueにすると、SeleniumコンテナにもPVCのhtmlサブパスを/var/www/htmlとしてマウントする
# (ブラウザのダウンロード先を公開ディレクトリに置きたい場合など)。別Podからの同時マウント
# になるため、有効にする場合はpersistence.accessModeをReadWriteMany
# (NFSバックエンドのStorageClassなら対応可能)にする必要がある。
# 通常のスクレイピング用途(スクリーンショット等をstorage/等の非公開領域に保存する場合)
# では不要なため、既定はfalse。
mountHtml: false
# 定期実行タスク(Kubernetes CronJob)
# php-fpmと同じPHPイメージ(image.php)を使い、指定したスケジュールで
# 1回限りのコマンドを実行するCronJobを作成する。複数ジョブを配列で定義できる。
# jobsが空の場合、CronJobは1つも作成されない。
#
# 【マウント/環境変数】/var/wwwにPVCルートをマウントし、externalDatabase/phpEnv/
# extraEnv/extraEnvFrom/SELENIUM_URLはphp-fpmコンテナと同じ内容が渡される。
# html/ 配下の公開コード、または /var/www/<非公開フォルダ> 配下の
# 非公開スクリプト・出力先のどちらも利用できる。
#
# 【Composer/Pythonとの併用について】
# composer.workingDir / python.venvDir が既定の /composer, /venv
# (PVC非マウントの使い捨て領域)のままの場合、CronJobのPodには存在しない
# (php-fpmの長時間稼働Pod内だけに存在する)ため利用できない。
# CronJobからComposer/Pythonの成果物を使いたい場合は、
# composer.workingDir: "/var/www/composer" のように/var/www配下へ変更し、
# PVC上に永続化すること(本体Deployment側で一度セットアップされていれば、
# CronJob側は改めてインストールし直す必要はない)。
#
# 【SMTPとの併用】smtp.enabled: true の場合、CronJobのPodでもmsmtpの導入・
# msmtprc配置・sendmail_path設定を自動で行うため、PHPのmail()関数がそのまま使える。
cron:
jobs: []
# - name: daily-report # 必須。CronJob名の一部に使用(英数字とハイフンのみ、小文字推奨)
# schedule: "0 18 * * *" # 必須。標準cron形式(timeZone省略時はUTC基準)
# command: "php /var/www/html/cron/daily-report.php"
# timeZone: "Asia/Tokyo" # 省略時はUTC(Kubernetes 1.27+で安定サポート)
# concurrencyPolicy: "Forbid" # Allow / Forbid / Replace(既定: Forbid。前回実行の長期化による多重起動を防止)
# restartPolicy: "OnFailure" # OnFailure / Never(既定: OnFailure)
# successfulJobsHistoryLimit: 3
# failedJobsHistoryLimit: 1
# activeDeadlineSeconds: 3600 # 実行タイムアウト(秒)。省略可
# suspend: false # trueにするとコード変更なしでこのジョブだけ一時停止できる
# resources: {} # 未指定時は resources.phpfpm を流用
externalDatabase:
enabled: false
@@ -212,6 +288,15 @@ smtp:
# password: "your-smtp-password"
password: ""
# 【外部Secret連携】チャートで msmtprc を生成しつつ、パスワードファイルだけ
# 既存 Secret から取りたい場合に指定する。
# 例: secret-manager チャートが配布する cred-<プロバイダ> の SMTP_PASSWORD キー
# existingSecret: "cred-gmail"
# existingSecretKey: "SMTP_PASSWORD"
# 指定時は smtp.auth.password と自作の -smtp Secret は使われない。
existingSecret: ""
existingSecretKey: "password"
# 送信元アドレス(固定値)
# PHPプログラムで mail() 関数の $additional_parameters で上書き可能
# 例: mail($to, $subject, $body, $headers, "-f user@example.com")
@@ -224,7 +309,34 @@ smtp:
# 自己署名証明書を許可する場合(テスト環境のみ)
allowSelfSigned: false
resources: {}
# 【外部Secret連携】完成済みの msmtprc がまるごと入っている既存 Secret を使う。
# 指定するとチャート内の msmtprc 生成(configmap-smtp)は行わず、
# host / port / protocol / auth.* / tls.* は無視される(from だけ PHP の
# sendmail_from 用に使用)。
# secret-manager チャートが cred-<プロバイダ> に生成する msmtprc キーを
# そのまま利用できる:
# existingMsmtprcSecret: "cred-gmail"
# existingMsmtprcSecretKey: "msmtprc"
existingMsmtprcSecret: ""
existingMsmtprcSecretKey: "msmtprc"
# nginx / php-fpm コンテナの CPU/メモリ requests・limits。
# v8.5.10-b より前は本キーがテンプレート側で参照されておらず(死んだ設定)、
# 何を指定してもコンテナには一切反映されない不具合があった(既存デプロイは
# 全コンテナが requests/limits なしの QoS Class: BestEffort になっていた)。
# BestEffortはノードのメモリ逼迫時にOOM Killの対象になりやすいため、
# 本番運用では requests/limits の設定を推奨する。例:
# resources:
# nginx:
# requests: { cpu: "50m", memory: "64Mi" }
# limits: { memory: "128Mi" }
# phpfpm:
# requests: { cpu: "100m", memory: "256Mi" }
# limits: { memory: "512Mi" }
# (selenium用は selenium.resources を参照。Chromiumは256Mi等では確実に不足する)
resources:
nginx: {}
phpfpm: {}
# PHP-FPM コンテナに渡す任意の環境変数
# DB接続情報(externalDatabase)と同様に、values.yamlで設定した値がPHPに環境変数として渡される
@@ -234,3 +346,23 @@ phpEnv: {}
# STRIPE_SECRET: "sk_live_xxxxxxxxxxxxxxxx"
# REDIS_URL: "redis://localhost:6379"
# SOME_SERVICE_URL: "https://api.example.com"
# 既存の Secret / ConfigMap をまるごと環境変数として PHP-FPM コンテナへ注入する(envFrom)。
# 別リポジトリの secret-manager チャートが各ネームスペースへ配布する
# cred-<名前> Secret(API キー等)をそのまま読み込む用途を想定。
# 変更は secret-manager 側を更新するだけで全プロジェクトに反映できる。
extraEnvFrom: []
# - secretRef:
# name: cred-gemini
# - secretRef:
# name: cred-openai
# - configMapRef:
# name: some-shared-config
# 個別の環境変数を追加する(生の env エントリ配列。value / valueFrom(secretKeyRef 等) 使用可)。
extraEnv: []
# - name: OPENAI_API_KEY
# valueFrom:
# secretKeyRef:
# name: cred-openai
# key: OPENAI_API_KEY