Docker permission denied:/var/run/docker.sock 权限被拒的正确解法与安全代价
现象:加了 sudo 就能跑,不加就被拒
permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.sock/_ping":
dial unix /var/run/docker.sock: connect: permission denied
一行结论:docker.sock 这个 socket 文件属于 root:docker,你的用户既不是 root 也不在 docker 组。docker 是 C/S 架构:CLI 以你的用户身份去连 socket,daemon(通常 root 身份)那头验的不是镜像、不是仓库,就是「你有没有资格碰这个 socket」。
验证一下归属:
ls -l /var/run/docker.sock
# srw-rw---- 1 root docker 0 ... /var/run/docker.sock
# ↑ 属主 root,属组 docker,其他人无权限(rwx 都没有)
修法:把用户加进 docker 组(一步)
sudo usermod -aG docker $USER
newgrp docker # 当前终端立即生效,不用注销
docker ps # 不加 sudo 试一下
newgrp 只对当前 shell 生效;彻底生效要注销重登(组信息在登录时加载,su - $USER 也行)。-a 参数千万别丢——不带 -a 的 -G docker 会把你从其他所有组里移出去,sudo 组没了就锁死自己了。
三个常见的错误修法
1. chmod 777 /var/run/docker.sock
能跑,但等于把 daemon 的控制权发给机器上所有用户,而且 daemon 重启后 socket 重建、权限复原,问题「莫名复发」。别用。
2. 长期 sudo docker ...
能用但有两类代价:所有 docker 产物(volume 数据、build cache)默认落在 root 名下,之后不加 sudo 的脚本读不到;CI 脚本里到处 sudo 反而更难审计。
3. 改 socket 属主 chown $USER /var/run/docker.sock
和 777 同一性质——改的是系统组件的所有权,升级/重启后复原。
必须知道的安全代价:docker 组 ≈ root
加了 docker 组,等于拿到了免密 root 的等价权限:
# 任何 docker 组用户都能这样拿到宿主机 root shell
docker run -v /:/host -it alpine chroot /host sh
所以:个人开发机加组没毛病;多用户生产服务器上,docker 组的授予要当成 sudo 权限一样走审批。更安全的替代:
- rootless Docker:daemon 跑在你自己的用户下,socket 在
~/.config/docker,无权限问题也无提权风险(代价:部分功能受限,如绑定 1024 以下端口需额外配置); - 精细授权:docker socket proxy(如 tecnativa/docker-socket-proxy)只放行白名单 API。
排查中容易混淆的相邻错误
| 报错 | 含义 | 方向 |
|---|---|---|
| permission denied ... docker.sock | socket 在,你无权访问 | 本篇 |
| Cannot connect to the Docker daemon | socket 不存在 / daemon 没跑 | 守护进程篇 |
| permission denied(pull 镜像时) | 仓库认证失败 | docker login,不是本篇 |
第三种最迷惑:报错里也有 permission denied,但发生在 docker pull 阶段,是** registry 私仓没登录**,和 socket 权限无关。
Rootless Docker:让权限错误类整体消失
最干净的修复不是授予 socket 访问而是消灭它:Rootless Docker 以你的用户跑 daemon——没有 socket 组、没有 root 提权路径,这个权限错误类直接不存在。代价:部分卷挂载和 iptables 网络行为不同、文件密集 bind mount 性能有损(FUSE 开销)。CI 和你可控的开发机:Rootless 日益成为默认推荐;共享服务器上,socket 组加下面的审计习惯仍是标准。
必须用 socket 组时的审计习惯
把用户加进 docker 组 = 给 root 等效权(任何成员都能把宿主文件系统挂进容器)。当 sudo 对待:只具名用户、永不给服务账号、定期 getent group docker 复查谁还需要。某工具要 Docker 访问但全组资格显得过度时,socket-proxy 模式暴露过滤后的 API——放行 containers/json 和 create、禁掉带宿主挂载的 build——最小权限版的 socket。
DinD 与 socket 挂载:刻意选择
给 CI 容器 Docker 能力的两种方式,失败模式相反:socket 挂载共享宿主 daemon——快、缓存友好,但「内部」容器是兄弟不是孩子(清理脚本必须知道),安全面是整个 daemon。真 DinD(内部 --privileged)隔离正确但要特权、嵌套层吃磁盘。要避免的错误:把 socket 挂进跑不可信代码的构建容器——那是包着一层容器的宿主 root 远程代码执行。
WSL2 与 Docker Desktop:两套 socket
Windows + WSL2 里,发行版内的 docker 常对接 Desktop 的中继,而不是经典的、属组为 docker 的 /var/run/docker.sock。症状:usermod 之后仍 permission denied,或 sock 落在 /mnt/wsl/...。处理:在 Docker Desktop 为该发行版打开 WSL 集成、重启发行版,并确认 docker context show 指向 desktop-linux(或你打算用的 context)。无 Desktop 的纯 Linux 宿主仍按本文的组权限思路排查。
排查清单
ls -l /var/run/docker.sock— 确认属组是 dockerid— 输出里的组列表有 docker 吗?- 没有 →
sudo usermod -aG docker $USER && newgrp docker - 加了组仍不行 → 注销重登(组信息登录时才刷新)
- 服务器场景 → 先读「安全代价」一节再决定是否加组
- 永远不用 chmod 777 / chown / 长期 sudo 这三个坑修法
- WSL2 + Desktop → 先核集成与
docker context,再查组权限
排查注记
修法只有一行 usermod,错误修法却单开三节——chmod 777、长期 sudo、chown 都「能用」,共同问题是 daemon 重启后 socket 重建、权限复原,变成「莫名复发」;长期 sudo 还会把所有 docker 产物落在 root 名下。安全代价一节刻意放在修法之后:docker 组等价于免密 root,文中那条挂载宿主根文件系统的命令就是证明,多用户服务器上要按 sudo 权限一样走审批。usermod 的 -a 标成「千万别丢」,是因为不带 -a 的 -G 会把你移出其他所有组——sudo 组没了就锁死自己。
来自 ToolVault 工具匣 的开发手记。相关工具:Dockerfile 生成器、docker run 转 compose、Linux 命令速查、chmod 权限计算器(rwx ↔ 755 双向换算,记不准权限数字时用上)。相关阅读:Docker daemon 连不上排查、SSH Permission denied (publickey) 排查。访问 首页 查看更多开发者工具。
相关工具
相关文章
Linux crontab 定时任务实战:命令、日志与排查
crontab 不只是写表达式:三个必会命令、/etc/cron.d 与用户 crontab 的区别、任务没跑的五步排查法、PATH/时区/% 转义、MAILTO,以及秒级任务的正确解法。
docker run 转 docker-compose 完全指南:为什么转、怎么转、参数对照表
把 docker run 命令迁移到 docker-compose.yml 的完整指南:compose 相比裸 run 的五大优势、参数逐项对照表(端口/卷/环境变量/重启策略/网络)、常见坑(裸 -e 透传、匿名卷、--rm 语义),附在线转换器用法。
Permission denied (publickey) 怎么解决?Git 推送失败的 6 种原因与修复
git clone/push 报 Permission denied (publickey) fatal: Could not read from remote repository?覆盖公钥没生成、没加载进 agent、没添加到 GitHub/Gitee、多账号配错密钥、deploy key 权限、remote URL 写错六种根因,附 ssh -v 诊断方法。