hyperf容器写入失败90%因uid/gid不匹配,须对齐数字身份:查容器内id -u/-g与挂载目录ls -ln属主数值,通过docker-compose环境变量注入uid/gid、dockerfile中usermod重设或构建时chown vendor/runtime目录解决。

Hyperf 容器内写入失败,90% 是因为容器用户 UID/GID 与挂载目录属主不匹配,而不是框架或代码问题。直接改 chmod 777 或重启服务没用,必须对齐数字身份。
确认容器内 Swoole 进程实际运行 UID/GID
别信配置文件里写的 www-data,Linux 权限只认数字。进容器执行:
-
id -u和id -g—— 看输出是不是你预期的值(比如 82) -
ps aux | grep swoole—— 确认进程确实以该 UID 启动,不是 fallback 到nobody -
ls -ln /app/runtime—— 对比目录第一列数字 UID 是否和上面一致;不一致就说明挂载时被宿主机“强加”了属主
修复 Docker Compose 中 UID/GID 不同步问题
常见于本地开发:宿主机用户是 UID 1000,但容器内 www-data 固定为 UID 33 或 82。不能靠 chown 宿主机目录来迁就容器,而应让容器适配宿主机。
- 在项目根目录建
.env,写入:UID=1000、GID=1000(用id -u实际值) - docker-compose.yml 中对应 service 的
build.args或environment里引用这两个变量 - Dockerfile 中用
ARG UID GID+usermod -u $UID -g $GID www-data重设 UID/GID(注意顺序:先改 GID 再改 UID,否则会失败) - 构建后验证:
docker-compose build --no-cache && docker-compose up -d,再进容器跑id
runtime/storage/view 目录权限必须由容器内用户创建或预置
Hyperf 在首次启动时尝试自动创建 runtime/,但如果父目录不可写,它会静默失败,后续所有写操作都崩。不要手动 mkdir 后 chown 宿主机路径——挂载进去后属主又变回 root。
- 在 Dockerfile 构建阶段就创建并赋权:
RUN mkdir -p runtime storage view && chown -R www-data:www-data runtime storage view - 如果用 volume 挂载
./src:/app,就不要挂载整个项目根目录;改成只挂载日志或上传目录,其余用COPY - 检查
config/autoload/view.php中storage.path是否为绝对路径(如/app/runtime/view),相对路径在协程中容易失效 - 多 Worker 场景下,避免共用同一
storage.path,可用'path' => '/app/runtime/view/worker_'.getmypid()隔离
vendor 目录属主错误导致类加载失败
报 Class not found 却查不到语法错误?大概率是 vendor/ 属主为 root:root,而 Swoole 以 www-data 运行,连 vendor/autoload.php 都打不开。
- 进容器执行
ls -ld vendor,开头是drwxr-xr-x 12 root root就坐实了 - 不要在容器里
chown -R—— 宿主机挂载卷的属主无法被容器内命令修改 - 解决方案只有两个:① 构建镜像时用非 root 用户装依赖(
RUN chown -R www-data:www-data /app && su www-data -c "composer install");② CI/CD 脚本中提前chown -R $(id -u):$(id -g) vendor再打包 - 顺手检查
vendor/bin/hyperf.php是否有执行权限:chmod +x vendor/bin/hyperf.php
最易被忽略的是:权限修复后,残留的只读缓存文件(如 runtime/container 下的旧代理类)仍会触发 Permission denied。清空 runtime/ 必须在改完权限之后、启动之前做一次,且不能跳过。










