根本原因是容器内PHP进程用户与runtime目录权限不一致;需确认Web进程用户、构建时固化runtime权限、挂载时分离可写路径、并确保umask为0002。

根本原因不是代码或配置写错了,是容器内 PHP 进程用户和 runtime 目录权限没对齐。缓存写不进 runtime/cache、runtime/view 或 runtime/log,90% 都卡在这一步。
确认 Web 进程实际运行用户
别猜,直接查:
- 进容器执行
ps aux | grep php-fpm或ps aux | grep apache,看 USER 列是什么(常见为www-data或apache) - 在
public/index.php开头临时加echo get_current_user(); die();,访问页面看输出 - 检查
php-fpm.conf里user =和group =是否与上一步一致
构建镜像时就设好 runtime 权限
别等容器跑起来再 chmod,Dockerfile 里明确固化:
RUN mkdir -p /var/www/runtime/{cache,log,view,route} && chown -R www-data:www-data /var/www/runtime- 如果用 Alpine 基础镜像,用户可能是
www-data或nginx,先apk add --no-cache shadow再用usermod确保存在 - 避免在
ENTRYPOINT里动态改权限——每次启动都执行,不可靠且慢
挂载方式要隔离可写路径
不要 -v ./app:/var/www 整个挂载,否则宿主机目录属主会覆盖容器内设置:
立即学习“PHP免费学习笔记(深入)”;
- 改成只读挂载代码:
-v ./app:/var/www:ro - 单独挂载 runtime 目录:
-v ./runtime:/var/www/runtime - 确保宿主机
./runtime目录本身对容器用户可写(例如chown -R 33:33 ./runtime,33 是 www-data 的 UID)
验证 umask 是否影响子目录创建
ThinkPHP 运行时会自动建多级子目录(如 runtime/cache/ab/cd/),权限由 umask 控制:
- 进容器执行
php -r "echo umask();",理想值是2(即0002) - 若返回
18(0022),新建目录默认是755,组用户无写权 → 在php-fpm.conf加php_admin_value[umask] = 0002 - 不推荐在 PHP 代码里调
umask(0002),仅作临时排查



















