简介在Windows 10的WSLWindows Subsystem for Linux中运行Docker时常会遇到“Cannot connect to the Docker daemon at unix:///var/run/docker.sock.”的报错本资源针对该问题提供了一份详细的排查与解决文档特别适合使用Ubuntu 18.04子系统的开发者和运维人员。内容基于实际安装Docker过程中遇到的权限、守护进程及Cgroups配置等问题梳理了完整的错误成因分析及多种解决思路涵盖使用systemctl或service检查服务状态、添加用户到docker组后的权限生效、通过cgroupfs-mount挂载控制组、重启守护进程及更新重装Docker等操作指引能为读者提供清晰的排错方向。资源以1个PDF文件呈现整体大小仅38KB便于快速查阅。已有超过14000人学习浏览是一份针对WSL环境下Docker启动失败的实用参考笔记。1. 不是命令写错了是 WSL 里 Docker daemon 压根没起来先搞清这个报错再说在 Windows 10 的 WSLUbuntu 18.04里装完 Docker执行docker images却甩来一句Cannot connect to the Docker daemon at unix:///var/run/docker.sock遇到这个报错的十有八九是刚接触 WSL 的新手。我最初也以为是安装命令敲错了实际上apt install docker.io、usermod -aG docker这套流程本身没问题真正的坑在于WSL 不是完整 systemd 环境Docker daemon 经常处于“看似装了、实际没跑”的状态连带着 cgroup 挂载也是坏的。这篇文章把诊断思路、修复命令和 WSL1/WSL2 的版本差异一次说透适合想在 Win10 里把 Docker 真正用起来、而不是只装个壳的从业者。2. 拆解 Docker daemon 连接链路socket、权限和 cgroup 三件事挨个查2.1 先理解unix:///var/run/docker.sock是什么Docker 采用客户端-守护进程架构docker这个命令行工具只是个客户端真正干活的是后台的dockerd守护进程。客户端和守护进程之间通过一套 REST API 通信在 Linux 默认走的就是 Unix socket/var/run/docker.sock。这句话翻译过来是你敲docker images时客户端尝试连接这个 socket 文件但连接失败。失败只有两种可能socket 文件不存在也就是守护进程没跑或者 socket 文件在但没有访问权限。很多人一看到报错就去重装 Docker从头折腾一遍其实方向完全跑偏了。正确做法是先确认 daemon 是否活着。用以下命令查看守护进程状态# 查看 docker daemon 进程是否存在更贴近底层 ps aux | grep dockerd # 或者用 service 命令查服务状态 sudo service docker status如果ps输出里看不到dockerd或者service docker status显示dockerd is not running那就可以判定daemon 根本没启动后续所有权限问题都谈不上。常见做法是先sudo service docker start再立刻看ps aux | grep dockerd确认进程是否稳定存活。有些情况下进程启动了但瞬间退出说明配置或环境有问题这就要继续往下查。2.2 用户组权限加了 docker 组不一定立刻生效在我的排查顺序里第二步是确认当前用户在不在 docker 组里。你之前执行过sudo usermod -aG docker leo这个命令本身是对的但存在一个容易忽略的细节用户组变更不作用于当前已打开的会话。# 查看当前用户属于哪些组 id leo # 如果输出中看不到 docker说明组变更没生效 # 如果能看到 docker 组继续检查 socket 文件权限 ls -l /var/run/docker.sock正常情况下 socket 文件权限是srw-rw---- root docker也就是 root 用户和 docker 组成员才有权访问。如果你id命令里能看到 docker 组但访问仍被拒绝多半是当前 WSL 会话的用户组信息没刷新。解决办法是彻底重启 WSL不是简单关掉窗口而是在 Windows 的 PowerShell 里执行wsl --shutdown然后再重新进入 Ubuntu 子系统。我一般会再跑一遍id确认 docker 组已经生效再做下一步。2.3 WSL 的 cgroup 挂载最容易翻车的隐藏关卡WSL 不是一个完整 Linux 内核环境它通过一组内核接口和 Windows 内核沟通很多原本由 systemd/init 系统自动完成的初始化工作都得手动补。cgroup控制组文件系统挂载就是最典型的一项。Docker 依赖 cgroup 来管理容器的 CPU、内存等资源配额如果 cgroup 没挂载daemon 即使强行启动也会运行失败。检查挂载状态# 查看 cgroup 是否已经挂载 mount | grep cgroup如果输出为空或者只有零散几条说明挂载不完整。在 WSL 里手动挂载的常见做法是使用cgroupfs-mount这个工具它把标准 cgroup 文件系统按固定规则挂载到/sys/fs/cgroup下。你可以在安装了该工具后用一行命令修复# 安装 cgroupfs-mount如果尚未安装 sudo apt install -y cgroupfs-mount # 执行挂载 sudo cgroupfs-mount执行完手动挂载后必须重启 Docker 守护进程才能让它重新读取 cgroup 状态。一句话总结这一章报错是表象daemon 没起来是主因权限和 cgroup 是常见的隐性帮凶按这个顺序排查能省下大量试错时间。3. 三个命令把 Docker daemon 救活从挂载 cgroup 到重启服务3.1 标准修复流程cgroupfs-mount 与 service docker restart先说你最关心的可抄作业环节。整套修复流程在我的 WSLUbuntu 18.04上验证过核心就是两个命令加一次 WSL 重启操作全部在 WSL 终端里执行。# 第一步以 root 权限重新挂载 cgroup sudo cgroupfs-mount # 第二步重启 docker 服务 sudo service docker restart # 第三步验证 daemon 是否可连接 docker images这段逻辑很直白cgroupfs-mount修复 Docker daemon 启动依赖的底层资源限制框架service docker restart让守护进程带着完整的 cgroup 视图重新初始化最后用docker images做连通性验证。如果你的环境里没有cgroupfs-mount会提示 command not found需要先安装sudo apt update sudo apt install -y cgroupfs-mount这里有一个参数层面的细节值得展开service docker restart这个命令在 WSL 里往往比systemctl restart docker更可靠原因在于 WSL 的 init 进程是定制的systemd 的那套 unit 管理机制在多数 WSL 配置下并不完整service命令走的是 SysV init 脚本路径对 WSL 的适配更成熟。少部分 WSL 版本里 systemd 也是可用的但那通常需要额外编辑/etc/wsl.conf开启不是默认状态。3.2 为什么必须先重启 WSL 再重启 Docker在上面修复流程里有一个容易被跳过的关键动作执行完sudo usermod -aG docker leo之后需要重启 WSL 才能让用户组变更生效。重启用的是 Windows 侧的命令不是在 WSL 里执行shutdown。# 这是在 Windows 的 PowerShell 或 CMD 里执行不是在 WSL 里 wsl --shutdown # 然后重新打开 Ubuntu 终端wsl --shutdown会终止当前所有 WSL 发行版的运行实例包括正在后台跑的任何进程。下次启动 Ubuntu 时会重新初始化内核态环境用户组信息也会重新加载。如果不做这一步即使你执行了sudo cgroupfs-mount和sudo service docker restart后续用docker images时仍然可能因为组权限没刷新而连接失败。3.3 修复失败时的诊断手段这套流程大概率能解决你当前的问题但如果你遇到的是变体场景比如 cgroup 挂载后 Docker 依然无法启动那就需要看守护进程日志了# 前台启动 dockerd让日志直接打到终端 sudo dockerd --debug # 或者查看系统日志 sudo tail -f /var/log/docker.log我一般用第一种方式因为--debug参数会输出完整调用链能明确看出是 cgroup 报错、iptables 报错还是网络命名空间创建失败。注意如果dockerd已经在运行直接执行上述命令会报端口被占用需要先sudo service docker stop停掉再试。日志中如果出现failed to mount cgroup说明 cgroupfs-mount 没有真正生效需要手动检查/sys/fs/cgroup目录是否存在如果出现iptables相关错误多半是 WSL 网络层配置问题这个问题我会在第 5 章详谈。4. WSL1 与 WSL2 的 Docker 差异同一条报错两种处理思路4.1 WSL1 里 Docker 只能算“半可用”说实话你现在能跑通 cgroupfs-mount 并让 Docker 工作说明用的是 WSL1 或旧版内核兼容层。WSL1 的架构是 API 翻译层不走虚拟化对 Linux 内核特性的支持并不完整。Docker 依赖的 cgroup、overlayfs、iptables 都属于比较底层的内核能力WSL1 里要么缺失、要么模拟得别别扭扭。在 WSL1 下Docker 的典型表现就是安装没问题、启动时好时坏、容器网络经常不通。解决报错靠的是各种手工补丁cgroupfs-mount 就是其中最重要的一个这也是为什么你搜到的答案几乎都指向这个工具。但也正因如此WSL1 里的 Docker 只适合做初学者练习或轻量验证真跑复杂服务我强烈不建议。4.2 WSL2 的 Docker优先装 Docker Desktop 还是直接在发行版里装 docker.ioWSL2 用了真正的轻量虚拟机内核几乎完整cgroup、overlayfs 都原生支持理论上直接apt install docker.io也能跑通。但这里有个实际体验差异在 WSL2 里我一般优先用 Windows 侧安装的 Docker Desktop开启 WSL2 backend 之后在 Ubuntu 子系统里直接执行docker命令就能连通到 Windows 侧 daemon省去了 WSL 内部管理服务进程的麻烦。下表列出两种方案的差异方便按自己的使用习惯选择对比项方案 ADocker Desktop WSL2 backend方案 BWSL2 内直接装 docker.iodaemon 运行位置Windows 服务独立于 WSL 生命周期WSL 发行版内部进程启动方式Docker Desktop 自启WSL 里即开即用需要手动service docker startcgroup 处理由 Docker Desktop 接管无需手动挂载可能需要 cgroupfs-mount 或 systemd 支持资源占用较高要跑一个虚拟机较低适合人群希望零配置、高度稳定的从业者对资源占用敏感、愿意手动维护的人方案 A 的一个明显优势是你不会再遇到Cannot connect to the Docker daemon这个报错因为 daemon 的启动不依赖 WSL 内部 init 机制。方案 B 则保留了更纯粹的 Linux 环境适合模拟生产环境时练习。4.3 如何确认你当前用的是 WSL1 还是 WSL2判断版本很简单。在 Windows 的 PowerShell 里执行wsl -l -v输出会列出每个发行版的名称和版本号。看到VERSION列是 1 就表示 WSL1是 2 就是 WSL2。如果你的发行版是 WSL1 且想升级到 WSL2可以用以下命令# 先确保 Windows 的虚拟化平台功能已开启 wsl --set-version Ubuntu-18.04 2升级过程中需要把整个根文件系统从 API 翻译层转换为虚拟磁盘文件耗时从几分钟到十几分钟不等。升级前注意备份重要数据我见过有人在这步因为磁盘空间不足导致转换失败所以先检查一下 C 盘剩余空间是否充足。5. 避坑记录Docker 在 WSL 里翻车的四个高频问题与处理5.1 现象service docker start 显示进程已启动但 docker images 依然报连接失败原因service docker start只是触发了 init 脚本但 dockerd 在启动过程中因为 cgroup 挂载缺失等原因崩退。WSL1 环境下很常见。解决先执行sudo cgroupfs-mount补挂载再执行sudo service docker restart不要只 start 不 restart。如果仍然反复崩溃用sudo dockerd --debug前台启动观察具体报错点是 cgroup 还是 iptables。5.2 现象用户已经在 docker 组里但仍提示 permission denied原因WSL 的会话生命周期和普通 Linux 不同usermod执行后的组信息不会自动同步到当前会话。即使新开一个 Ubuntu 窗口有时跑到的仍是旧会话缓存。解决在 PowerShell 执行wsl --shutdown等待几秒后重新进入 WSL再用id命令确认 docker 组已出现。注意执行完wsl --shutdown后所有后台进程都会被终止如果之前有挂着跑的脚本先保存好数据。5.3 现象执行 cgroupfs-mount 提示 command not found原因apt 源里没有安装这个工具。它是单独的软件包不会随 docker.io 自动装入。解决先sudo apt update再sudo apt install -y cgroupfs-mount。如果安装后执行sudo cgroupfs-mount仍然报错检查/sys/fs/cgroup目录是否已存在若存在则先sudo umount /sys/fs/cgroup再挂载。5.4 现象Docker 能被启动但容器内部网络不通ping 外网失败原因WSL 的 NAT 网络模式与 Linux 原生的 iptables 规则不兼容Docker 创建网桥时设置的 iptables 规则没有真正生效。解决在 WSL2 环境下优先用 Docker Desktop 的 WSL backend避免自行管理网络栈在 WSL1 环境下如果只是本地开发可以把容器端口映射到localhost使用跨主机访问不要依赖容器网络直接用宿主机端口转发。6. 从修好到固化写一个一键启动脚本让 Docker 在 WSL 里不再“重启就消失”折腾到这里你的 Docker 应该能跑起来了。但 WSL 和普通 Linux 服务器有一个本质区别WSL 每次重新进入都会重建部分内核态环境也就是说你今天手动执行的挂载、启动步骤明天关机后再打开又得重来。把修复流程固化成脚本才是一劳永逸的做法。在~/.bashrc末尾追加一段逻辑让每次打开 WSL 终端时自动检查 Docker 状态# 自动修复 Docker daemon 状态追加到 ~/.bashrc 末尾 if ! docker info /dev/null 21; then echo Docker daemon 未运行尝试自动修复... sudo cgroupfs-mount sudo service docker start sleep 2 docker info /dev/null 21 echo Docker 已就绪 || echo Docker 修复失败请手动排查 fi这段脚本的思路是每次新开终端时先检查 Docker daemon 是否可连不可连才执行修复动作。docker info是比docker images更完整的连通性检查它会向 daemon 请求完整的系统信息只要有任意一项异常就会非零退出。sleep 2是必要的等待时间因为service docker start执行后守护进程需要几百毫秒到一两秒才能进入就绪状态不等就直接检查容易误判失败。脚本里故意用了sudo service docker start而不是restart原因在于 WSL 会话是短生命的绝大多数情况下不存在需要先停止的旧进程直接start更快更稳。如果你在同一个 WSL 实例里切换过多个终端可能遇到“另一个终端已启动了服务这个终端再 start 会报 already running”的情况这不会影响使用无需处理。执行source ~/.bashrc或者重开终端后测试两次第一次可以故意先sudo service docker stop再走一遍完整脚本流程第二次直接重开终端确认脚本能自动检测并跳过启动步骤。从那以后我每装一个 WSL 环境都强制走一遍这套方案先确认 WSL 版本再决定用 Docker Desktop 还是原生 docker.io不论哪条路最后一定固化一个自检脚本。这样就不会再被Cannot connect to the Docker daemon这种初级问题打断思路。希望这篇拆解能帮你少走几趟弯路把精力留到真正该用的容器编排和图像构建上去。本文还有配套的精品资源点击获取