跳到主要内容
DevOps2026-09-084 分钟阅读

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.socksocket 在,你无权访问本篇
Cannot connect to the Docker daemonsocket 不存在 / 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 宿主仍按本文的组权限思路排查。

排查清单

  1. ls -l /var/run/docker.sock — 确认属组是 docker
  2. id — 输出里的组列表有 docker 吗?
  3. 没有 → sudo usermod -aG docker $USER && newgrp docker
  4. 加了组仍不行 → 注销重登(组信息登录时才刷新)
  5. 服务器场景 → 先读「安全代价」一节再决定是否加组
  6. 永远不用 chmod 777 / chown / 长期 sudo 这三个坑修法
  7. 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) 排查。访问 首页 查看更多开发者工具。