docker 权限被拒:permission denied 速查
更新时间:2026-10-24。FAQ 速查页,面向装完 docker 一敲命令就撞
permission denied的同学。这个报错在 docker 世界里有两个完全不同的出处:一是你够不着 docker 守护进程——/var/run/docker.sock这个套接字文件把你挡在门外;二是容器里的进程够不着文件——挂载卷、UID、SELinux 在容器内部拦你。两处病灶的修法南辕北辙,必须先分清是哪一层。顺六根轴排查基本必中:docker 组、socket 权限、sudo 滥用、挂载卷属主、SELinux/AppArmor、rootless 模式。如果报错是拉镜像时的pull access denied,那是仓库登录态问题,请转 docker 镜像找不到速查。
本文要回答的问题
permission denied while trying to connect to the docker daemon socket是什么意思?- 把用户加进 docker 组后为什么当前终端还是报错?
- 容器里写挂载目录报 permission denied,宿主机上明明权限够?
- SELinux 的
Permission denied与文件权限位的有什么区别? - rootless 模式下为什么挂载卷的属主会变成奇怪的 nobody?
一、报错原文与典型现象
报错按发生层分两类,先对号入座(工程路径以 /proj/demo 占位):
$ docker ps
permission denied while trying to connect to the docker daemon socket at unix:///var/run/docker.sock:
Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json": dial unix /var/run/docker.sock: connect: permission denied$ docker run --rm -v /proj/demo/data:/data myapp:latest
docker: Error response from daemon: ... mkdir /proj/demo/data: permission denied.
# 或容器内:
$ docker exec myapp touch /data/out.txt
touch: cannot touch '/data/out.txt': Permission denied# SELinux 场景下 audit 日志里的原文:
type=AVC msg=audit(...): avc: denied { write } for pid=... comm="app" name="data" dev="..." scontext=system_u:system_r:container_t:s0 tcontext=...:var_t:s0 tclass=dir permissive=0读报错先抓层次:connect: permission denied 且提到 docker.sock 的,是客户端到守护进程这一层——你还没碰到容器就被拦了;mkdir/touch/open ... permission denied 发生在 run 或 exec 阶段的,是容器内到挂载文件这一层——守护进程收下了你的请求,但容器里的进程碰文件被拒。两层各有一套修法。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| 任何 docker 命令都报 sock 权限错 | 当前用户不在 docker 组 | groups 输出里没有 docker | sudo usermod -aG docker $USER,重登录 |
| 加组后当前终端仍报错 | 组变更对已登录会话不生效 | id -nG 对比 groups | 重开终端或 newgrp docker |
| sock 报错且组正常 | docker.sock 权限位/属组被改 | ls -l /var/run/docker.sock | 恢复 srw-rw---- root docker |
| 一直靠 sudo docker 用 | 没配组,用 root 权宜 | 不加 sudo 就报错 | 配 docker 组,戒掉 sudo docker |
| run/exec 对挂载目录写报错 | 卷内文件属主与容器内 UID 不匹配 | ls -ln /proj/demo/data 看数字 UID | 对齐 UID 或容器内用对应用户跑 |
| 权限位看着对仍被拒 | SELinux(或 AppArmor)拦截 | getenforce 为 Enforcing | 挂载加 :z 或 :Z 后缀 |
| rootless 下卷属主变 nobody | 用户命名空间 UID 映射 | docker info 看 Rootless 与 userns | 按映射后 UID 调整属主,或换路径 |
| 装完 docker 第一次用就报错 | 安装后从未把用户加组 | 见第一条 | 装后第一步就是加组 |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓住一个分水岭:报错发生在哪一层。提到 docker.sock 的走左支,查用户组成员关系;发生在容器运行期碰文件被拒的走右支,查挂载卷 UID 与 SELinux。千万别拿左支的修法(加组)去修右支的错——那是容器内部的文件权限世界,跟你能不能连守护进程毫无关系。
四、逐条排查展开
左支第一步:看自己在不在 docker 组。 docker 守护进程的套接字 /var/run/docker.sock 默认属主是 root:docker、权限 srw-rw----——意思是 root 和 docker 组成员可写,其他人免进。确认与修复:
groups # 看有没有 docker
ls -l /var/run/docker.sock
sudo usermod -aG docker $USER加组后必须让会话重新加载组信息。 这是踩坑率最高的一步:usermod 改的是账户数据库,你当前这个终端的登录会话还拿着旧的组列表。处置任选:newgrp docker 当前终端立即生效、注销重登录、或直接重开终端。验证用 id -nG 看到 docker 才算数。CI 机器与云主机初始化脚本里把加组写进装机流程,能省掉每个新人问一遍。
戒掉 sudo docker 这个权宜之计。 不加组、靠 sudo docker 硬闯能跑,但后患无穷:脚本里混着 sudo 与非 sudo、文件属主被 root 污染、CI 里没 tty 输密码直接挂。docker 组本就是官方给的正路(注意它等价于把 root 权限发给组员,多人共用机器上要控制组成员名单)。
右支:挂载卷的 UID 战争。 容器内进程的 UID 与宿主机文件属主是数字对数字的裸比较,跟用户名无关。镜像里的应用常以非 root 用户跑(比如 UID 1000 的 node),而你挂载的 /proj/demo/data 属主可能是宿主机上另一个 UID 的目录——容器内写它就 permission denied。确认:
ls -ln /proj/demo/data # 看数字 UID/GID
docker run --rm myapp id # 看容器内跑的身份修法按场景三选一:chown -R 1000:1000 /proj/demo/data 把目录让给容器内用户;docker run --user $(id -u):$(id -g) 让容器用你的身份跑;或在 Dockerfile 里就规划好运行 UID 并在部署文档里写明卷属主要求。
SELinux 拦的错,权限位看不出来。 RHEL/Fedora/CentOS 系默认 Enforcing,容器进程的安全上下文(container_t)摸宿主机普通目录(var_t 等)会被内核直接拒,文件权限位再宽也没用。确认与处置:
getenforce # Enforcing 才有此坑
docker run -v /proj/demo/data:/data:Z myapp # :Z 重新打私有标签,:z 打共享标签:z/:Z 让 docker 在挂载时把目录 SELinux 标签改成容器可读写的类型,是正路;setenforce 0 全局放行是偷懒,别带进生产。
rootless 模式的 UID 映射幻觉。 rootless docker 里容器内的 root 实际映射到宿主机的你的普通用户,容器内 UID 1000 映射成一个无人认领的高位 UID——挂载卷属主在宿主机上看着就是一串陌生数字或 nobody。docker info | grep -i rootless 确认模式;排这类错时永远用 ls -ln 看数字 UID 再对照 rootless 的映射表(/etc/subuid),别按用户名猜。
还有一类隐蔽错:挂载源路径本身不存在。 docker 对不存在的源路径会自动创建(以 root 身份建空目录),后续容器内写入就撞 root 属主目录的权限墙。表现和 UID 不匹配一模一样。预防:挂载前先确认 /proj/demo/data 存在且属主符合预期,compose 里显式建好目录再 up。
容器内降权后的次生权限问题。 按安全规范给容器降权(USER 1000、--cap-drop ALL)之后,原本 root 能干的事(写 /var/log、绑定 1024 以下端口)会突然 permission denied,容易被误判成挂载卷问题。分辨方法:看报错路径——卷路径走 UID 对齐,镜像内部路径则要改 Dockerfile 提前建好目录并 chown 给运行用户,或在启动命令里避开特权操作。降权是正确方向,但要把「目录归属」和「端口选择」在镜像构建期一次性配套。
五、规范做法与预防
- 装机脚本固化加组:
usermod -aG docker写进新机器初始化脚本,并注明「重登录生效」。 - Dockerfile 定死运行用户:
USER 1000写进镜像,README 里同步写挂载卷属主要求。 - SELinux 机器挂载必带 😒/:Z:团队约定写进 compose 模板,不靠记忆。
- compose 声明 user 与卷:
user: "1000:1000"与预建目录进版本库,权限问题在评审时暴露而不是运行时。 - 不用 sudo docker 当日常:看到脚本里
sudo docker就当 bug 处理。 - 复验用最小镜像:
docker run --rm hello-world验守护进程连通性,再验带卷的真实容器,分层闭环。
这一篇在知识体系里的位置
本篇是 docker 排错速查簇的权限篇,定位「permission denied 的两层病灶」:连守护进程被拒与容器内碰文件被拒的修法完全不同。拉镜像阶段的 pull access denied(仓库登录态)看 docker 镜像找不到速查;权限修好、容器跑起来之后端口连不上的看 docker 容器端口连接被拒速查。ls -ln、id、getenforce 三件确认套在一切 Linux 权限类排错里通用。
一句话总结
docker 权限被拒先按报错分层:提到 docker.sock 的是客户端连守护进程被拒——groups 确认在不在 docker 组,不在就 sudo usermod -aG docker $USER 并重开终端让组生效,别用 sudo docker 当长期方案;发生在 run/exec 碰文件的是容器内 UID 与挂载卷属主的裸数字冲突——ls -ln 对 docker run myapp id 对齐 UID,SELinux 机器(getenforce 为 Enforcing)挂载必须带 :z/:Z,rootless 模式按 UID 映射表看数字属主。装机脚本固化加组、Dockerfile 定死运行用户、compose 声明卷权限,这类报错即可基本绝迹。