Docker K8s Init Script Permission Inheritance¶
概念概覽
根因模式¶
核心知識¶
根因模式¶
當 Kubernetes container 的 init script(如 init-all.sh)以 root 身份執行並觸發應用程式框架(PHP Monolog、Python logging 等),框架自動建立的目錄(如 logs/batch/<date>/)會繼承 root:root owner。等到 runtime user(www-data, uid 1000)要寫入時,就會爆出 Permission denied。
關鍵觀察:Dockerfile 預建目錄並 chown 只能保護目錄本身,無法阻止 init script 執行後 Monolog 在子目錄下建出的 root:root 日期子目錄。Phase 2 kubectl exec 輸出直接佐證此點。
雙層修正(缺一不可)¶
Layer 1 — Dockerfile:
RUN mkdir -p /var/www/html/app/logs/batch \
&& chown -R 1000:1000 /var/www/html/app/logs
Layer 2 — Jenkins Pipeline(init-all.sh exec 之後):
kubectl exec $POD -- chown -R 1000:1000 /var/www/html/app/logs
- Layer 1 確保 image 內目錄初始 owner 正確
- Layer 2 修正 init script 執行後被 Monolog 建出的 root:root 子目錄
- 若 Layer 2 受
restartServer=true參數控制,執行 pipeline 時須確認此參數已啟用
診斷驗證方法¶
- 排除 EFS 持久化假說:
kubectl describe pod確認 volumeMounts 中是否有 EFS/PVC,若無則 rebuild 必然生效 - 確認根因:手動刪除 root:root 的日期目錄後觀察 cron 重建的 owner——若 cron(www-data)自行建出的目錄 owner 正確,即確認問題只在 init script 觸發 Monolog 的那一刻
- 嚴禁:不要使用
chmod -R 777作為永久解,違反最小權限原則
經驗教訓¶
-
init script 以 privileged user 執行並觸發應用程式框架,框架自動建立的目錄繼承了 root owner,是 Docker + K8s 環境中的隱藏地雷
-
雙層修正(Dockerfile + Pipeline chown)缺一不可,Phase 2 kubectl 輸出是最有力的佐證
-
懷疑 rebuild 沒用時,優先用 volumeMount 確認是否有 EFS/PVC 持久化,可快速排除假說
-
此模式可套用到所有「init 由 root 執行、runtime 由非 root 執行」的 PHP/Python/Node.js 容器場景
常見陷阱¶
-
Dockerfile 預建目錄 + chown 只保護目錄本身,無法保護 init script 執行後 framework 自動建立的子目錄
-
chmod 777 是錯誤的永久解,只適合緊急救火
-
Layer 2 chown 若綁定在受參數控制的 stage(restartServer=true),忘記勾選參數會導致修正不生效
-
同版號 ECR image tag 不會自動覆蓋,Dockerfile 修改後必須遞增版號才能讓 deploy 拿到新 image
最佳實踐¶
-
Dockerfile 中預建所有 runtime 需要寫入的目錄並 chown 給 runtime user(uid)
-
Jenkins pipeline 在執行 init script 後補 chown,作為第二層防護
-
建議在 init-all.sh 末尾自行補 chown,使邏輯自包含,避免只能靠 pipeline 補救
-
使用 chown 1000:1000 而非 chmod 777,遵循最小權限原則
相關概念¶
- Docker Bind Mount + fsnotify 熱載入限制
- ECR Image Deployment Pattern
- ECR Image Tag Versioning in Jenkins Pipeline
- EKS NoExecute Taint Toleration Scheduling
來源 Sessions¶
| 日期 | Session | 貢獻摘要 |
|---|---|---|
| 2026-04-10 | 2915f12c-2e40-49a6-9734-a50edf42bc3a | 揭示 init script 以 root 執行並觸發 PHP framework(Monolog)時,自動建立的子目錄繼承 root:root owner 導致 runtime user 無法寫入的根因,並驗證雙層修正的必要性 |