K8s Web Container Logs/Batch Permission Denied Root Cause¶
概念概覽
根本原因¶
核心知識¶
根本原因¶
init-all.sh 在 Jenkins pipeline 中以 su -s /bin/bash www-data 執行,但其中跑的 PHP 用 Monolog 寫 log 時,會自動 mkdir 當天的日期子目錄(如 logs/batch/2026-04-10/)。問題在於 supervisord 是以 root 跑,整個 PHP-FPM master 也是 root,因此 Monolog auto-mkdir 出來的目錄 owner 是 root:root 755,後續 cron 以 www-data 跑時無法在該目錄下建檔。
多層修正方案¶
Layer 1:Dockerfile(預建目錄 + 正確 owner)¶
RUN mkdir -p /var/www/html/Gamania/logs/syncdb /var/www/html/Gamania/logs/batch
RUN chown -R 1000:1000 /var/www/html/
Layer 2:docker-entrypoint.sh(容器啟動後 chown)¶
# 啟動前將 logs/ 擁有者統一為 www-data
chown -R 1000:1000 /var/www/html/Gamania/logs
supervisord -n -c /etc/supervisord.conf
Layer 3:Jenkins Pipeline(init 之後補 chown,根治關鍵)¶
kubectl exec --context ${ctx} -i $POD_NAME -n ps -- \
su -s /bin/bash www-data -c 'bash /var/www/html/env/scripts/init-all.sh ${params.restartSite}'
kubectl exec --context ${ctx} -i $POD_NAME -n ps -- \
chown -R 1000:1000 /var/www/html/Gamania/logs
偵錯工具¶
kubectl exec ... -- ls -la /var/www/html/Gamania/logs/batch/確認日期目錄 ownerkubectl exec ... -- ps aux確認誰在跑 PHP(root/www-data)kubectl get pod ... -o jsonpath='{.spec.containers[0].volumeMounts}'確認有無 EFS mount 干擾kubectl rollout restart後立即查 ls,確認新 pod 初始狀態
經驗教訓¶
-
Monolog 的 auto-mkdir 行為會繼承呼叫者的 uid,即使 su 成 www-data,若上層 PHP-FPM master 是 root,建出的目錄仍可能是 root
-
docker-entrypoint.sh 的 chown 只在啟動瞬間生效,init script 跑完後建的目錄不受保護
-
根治方式:在 Jenkins pipeline 跑完 init-all.sh 之後,必須補一道 chown -R 1000:1000 /var/www/html/Gamania/logs
-
相同版號的 ECR image build 不會強制更新,需要用不同 tag 才能讓 k8s 拉新 image
-
偵錯時要先確認 volumeMounts,排除 EFS 等外部 mount 干擾
常見陷阱¶
-
只改 Dockerfile 不改 Jenkins pipeline,init-all.sh 跑完後仍會留下 root:root 日期目錄
-
以為 su -s /bin/bash www-data 跑 init 就沒事,但 PHP 內部 Monolog mkdir 仍可能是 root
-
rollout restart 後 pod name 換了但 image 沒換,問題依舊
-
相同版號 tag push 到 ECR 不代表 k8s 會拉新 image(imagePullPolicy 問題)
最佳實踐¶
-
Dockerfile 預建 logs 子目錄並 chown,確保 image 初始狀態正確
-
entrypoint.sh 在 supervisord 啟動前補 chown logs/,覆蓋 openapi 生成等 root 操作
-
Jenkins init stage 跑完腳本後補 chown,這是唯一能覆蓋 Monolog 日期目錄的時機
-
查 permission 問題時,先用 ls -la 確認目錄 owner,再用 ps aux 確認 process uid
相關概念¶
- EKS Node Group Creation with eksctl
- Ireland House Ops Pipeline
- Jenkins Inline Dockerfile Web Image Build
來源 Sessions¶
| 日期 | Session | 貢獻摘要 |
|---|---|---|
| 2026-04-14 | 2915f12c-2e40-49a6-9734-a50edf42bc3a | 完整追蹤並解決 K8s PHP Web container 中 logs/batch/