这是典型的权限错配问题:/var/run/docker.sock父目录权限或SELinux上下文不匹配,导致dockerd无法绑定socket;需检查目录权限、确认root运行、验证systemd配置,并避免直接将CI用户加入docker组。

dockerd 启动时提示 Failed to start daemon: listen unix /var/run/docker.sock: bind: permission denied
这是最典型的权限错配现象:dockerd 进程尝试绑定 /var/run/docker.sock,但当前运行用户(通常是 root)对该路径所在目录没有写权限,或路径已被其他进程占用且属主不同。
根本原因不是 socket 文件本身,而是其父目录 /var/run/docker.sock 所在的挂载点(常为 tmpfs)权限或 SELinux 上下文不匹配。常见于手动修改过 /var/run 权限、使用 systemd-tmpfiles 覆盖默认配置、或容器化部署中挂载了宿主机目录。
- 检查
/var/run目录权限:ls -ld /var/run,应为drwxr-xr-x root root;若属组非root或权限含w给 group/other,可能触发拒绝 - 确认
dockerd是否以root用户启动:ps aux | grep dockerd,避免用sudo -u nobody dockerd类方式启动 - 若使用 systemd,检查
/usr/lib/tmpfiles.d/docker.conf或/etc/tmpfiles.d/docker.conf是否覆盖了默认 socket 目录创建逻辑 - 临时验证:手动创建目录并赋权:
mkdir -p /var/run/docker.sock→chown root:root /var/run/docker.sock→chmod 755 /var/run/docker.sock(仅调试,勿长期保留)
如何安全地把非 root 用户加入 docker 组来访问 /var/run/docker.sock
把用户加进 docker 组是常规做法,但本质是赋予该用户等同于 root 的容器控制权——这不是权限“降级”,而是能力“平移”。一旦该用户能执行 docker run --privileged 或挂载宿主机敏感路径,就等于获得 root shell。
- 必须确保
/var/run/docker.sock所在目录(/var/run)对docker组可写,否则 socket 创建失败;典型修复:sudo chmod g+rwX /var/run+sudo chgrp docker /var/run - 用户加入组后需重新登录或运行
newgrp docker,否则groups命令不显示生效 - 禁止在生产环境将 CI/CD agent 用户(如
gitlab-runner)直接加入docker组;应改用rootless Docker或限制容器能力(--cap-drop=ALL) -
docker组权限无法被 SELinux 或 AppArmor 自动继承,若启用了这些模块,还需额外策略放行unix_stream_socket访问
修改 dockerd 的 -H 参数指定 socket 路径后,客户端连不上
当通过 dockerd -H unix:///opt/mydocker.sock 指定非默认路径,docker CLI 默认仍连 /var/run/docker.sock,不会自动跟随服务端配置变更。
- 客户端必须显式指定:
docker -H unix:///opt/mydocker.sock info,或设环境变量DOCKER_HOST=unix:///opt/mydocker.sock - socket 文件路径的父目录(如
/opt/mydocker.sock)必须存在且由dockerd进程可写;dockerd不会自动创建中间目录 - 若路径含非标准目录(如
/home/user/docker.sock),注意该路径是否在 tmpfs 或 nosuid 挂载分区上——部分发行版对非/var/run下的 unix socket 有额外限制 - systemd 配置中修改
ExecStart后,务必同步更新SocketPath=(如果用了 socket activation)和docker.socket单元的ListenStream=字段
rootless Docker 下 docker.sock 的位置与权限表现差异
rootless 模式下,dockerd-rootless.sh 默认监听 $XDG_RUNTIME_DIR/docker.sock(通常为 /run/user/1001/docker.sock),这个路径由 PAM 和 systemd user session 管理,权限模型与传统模式完全不同。
- socket 文件属主是当前用户,无需加
docker组;但$XDG_RUNTIME_DIR必须存在且权限为drwx------,否则 rootless daemon 启动失败 - 不能通过
sudo docker访问 rootless socket;sudo切换用户后$XDG_RUNTIME_DIR变为 root 的路径,完全不匹配 - CI 场景中若用非交互式 shell(如
ssh user@host 'docker info'),需确保该 shell 能读取 user session 的 D-Bus 地址和 XDG 变量,否则报Cannot connect to the Docker daemon - rootless 不支持
--network=host和部分 cgroup v1 特性;若业务依赖这些,强行迁移会导致功能缺失而非权限问题
socket 文件路径本身不难改,难的是上下游工具链是否适配它的生命周期管理——比如 kubectl 的 docker-env 插件、buildkit 的 docker-container 后端、甚至 IDE 的 Docker 插件,都可能硬编码了默认路径。










