From b872dd4bd931cdc4dc43b15049715b36c6612701 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 19:54:49 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20php-fpm=E3=82=92exec=20php-fpm=20-F?= =?UTF-8?q?=E3=81=A7=E8=B5=B7=E5=8B=95=E3=81=97CrashLoopBackOff(9000?= =?UTF-8?q?=E4=BA=8C=E9=87=8Dbind)/502=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setupシェルの子として起動していたためコンテナ再起動時にシェル(PID1)がSIGTERMを子へ転送せず、旧php-fpmが9000を握ったまま残存し次回起動が Address in use で失敗する自己増殖ループに陥っていた。execでphp-fpmをPID1にしシグナルを直接受けさせ、-Fで必ずフォアグラウンド起動にする。 --- CHANGELOG-8.5.9-d.md | 54 +++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 6 +++++ Chart.yaml | 2 +- README.md | 18 +++++++++++++ templates/deployment.yaml | 11 +++++++- 5 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG-8.5.9-d.md diff --git a/CHANGELOG-8.5.9-d.md b/CHANGELOG-8.5.9-d.md new file mode 100644 index 0000000..24c1c86 --- /dev/null +++ b/CHANGELOG-8.5.9-d.md @@ -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 " ... 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 -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) diff --git a/CLAUDE.md b/CLAUDE.md index f385a22..e0840fa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,6 +26,12 @@ Websites 組織の各サイト(e-learn.jp / fcdomain.com / hotels / tskholding ## チャート改修履歴 +### 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箇所すべてが揃う。 diff --git a/Chart.yaml b/Chart.yaml index d338851..062a9a6 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -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-c +version: 8.5.9-d appVersion: "8.5.9" icon: https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/PHP-logo.svg/330px-PHP-logo.svg.png diff --git a/README.md b/README.md index 1bc4aca..ecee28d 100644 --- a/README.md +++ b/README.md @@ -867,6 +867,24 @@ 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 -l app.kubernetes.io/name=phpfpm +``` + ### データベース接続エラー **確認**: diff --git a/templates/deployment.yaml b/templates/deployment.yaml index 964d918..2677c42 100644 --- a/templates/deployment.yaml +++ b/templates/deployment.yaml @@ -252,7 +252,16 @@ 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ポートでリッスン volumeMounts: