Windows 上跑 Docker:选 Docker Desktop 还是 WSL2 原生引擎?
原创 · 约 27 分钟阅读 · 阅读 --

Windows 上跑 Docker:选 Docker Desktop 还是 WSL2 原生引擎?

作者: Alex Xiang


本文完全由 WorkBuddy 独立收集资料、调试代码并完成文章写作。

扫码注册 WorkBuddy 即可获取 2000 积分

我是 Alex Xiang,前百度/微博工程师,现在专注于 AI 工程与工具产品。更多文章欢迎关注微信公众号「字与码」。

这个问题看起来一句话就能答完,但我在一次讨论里被连续追问了四轮,结论被推翻了两次。

第一轮的问题是:在 WSL2 下装 Docker,该用 Docker Engine 还是 Docker Desktop?

第二轮:想让里面的容器一直在线,是不是要有额外操作?比如单独起一个保活用的 WSL 实例?

第三轮:如果是对外提供 7×24 小时服务,必须用 Windows 机器,选哪个?

第四轮,也是真正把结论推翻的那一轮:这台机器是 Windows 家庭版。

约束每加一层,答案就换一次。把一个完整的判断链写下来,比直接给结论有用得多。

先分清两条路的架构

一个容易被忽略的前提:在 Windows 上跑 Linux 容器,不存在「不用虚拟机」这个选项。Windows 内核跑不了 Linux 容器,所以无论选哪条路,容器最终都跑在一个 Linux VM 里。

区别在于两件事:谁在管这个 VM,dockerd 住在哪。

Docker Desktop 的 WSL2 后端会创建属于它自己的发行版 —— 早期是 docker-desktop(跑 dockerd)和 docker-desktop-data(存镜像与数据),新版把两者合并了。你的 Ubuntu 只是被「接线」过去:Docker Desktop 往里面注入 docker CLI、/var/run/docker.sock 和几个环境变量,你自己的发行版里其实没有 dockerd。

而在 WSL2 里直接装 docker-ce 的方案,dockerd 就住在你自己的发行版里,由 systemd 管理。

Docker Desktop 与 WSL2 原生引擎的架构对比

这个架构差异派生出后面所有区别:资源占用、与生产环境的一致性、排障方式,以及两者能不能同时存在。

顺带说一个高频事故:这两条路不要同时装。Docker Desktop 会往你的发行版注入 CLI 和 socket 配置,和本地原本的 dockerd 抢 /var/run/docker.sock,报错信息完全看不出根因 —— 典型表现是连上一个空 socket,或者莫名其妙的 permission denied。要换路线就先把旧的卸干净:Desktop 卸载后记得清理它留下的发行版,原生方案则要 apt purge docker-ce docker-ce-cli containerd.io 并删掉 /etc/docker。

开发场景下,授权才是最大的变量

如果是自己开发用,技术差异其实都是次要的,最先要确认的是授权。

Docker Desktop 的订阅协议规定:员工少于 250 人 且 年收入低于 1000 万美元的公司,可以免费商用。注意这两个条件是「且」——跨过其中任意一条,每个打开 Docker Desktop 的人都得付费订阅。按年付口径,Pro 是每人每月 9 美元,Team 15 美元,Business 24 美元,而 Business 没有任何年付折扣。政府实体没有免费档,哪怕只有五个人。

Docker Engine 本身是 Apache 2.0,在 Linux VM 里装它没有任何限制。许可证约束的是 Docker Desktop 这个产品——那个 GUI、那个托管的 VM、它捆绑的 Compose v2 二进制。底层那些开源项目(Docker Engine、containerd、runc、BuildKit)都不在此限。

维度Docker Desktop(WSL2 后端)WSL2 里装 docker-ce
授权个人、教育、开源免费;公司 ≥250 人或 ≥1000 万美元收入需付费Apache 2.0,任何规模免费
安装与运维装完勾选 WSL 集成即可,自动更新要开 systemd、手动 apt upgrade、自己配 daemon.json
图形界面有 Dashboard,可看容器、镜像、日志、资源曲线无,纯命令行
Kubernetes一键开单节点自己搭 kind / k3d / minikube
Windows 侧可用是,PowerShell 里直接 docker ps否,只能用 wsl docker ...
资源开销偏高,多一层 GUI 进程和托管 VM低,只有 dockerd 和容器进程
与生产一致性隔了一层封装,docker info 与服务器不同和线上 Linux 主机完全一致

一个容易被误解的点:授权是合同约束,不是技术拦截。超出免费范围之后 Docker Desktop 不会停止工作,但这件事会在收购尽调或 SOC 2 审计时浮现出来,而且 Docker 确实发过补缴账单。

所以开发场景的结论很清楚:个人、学习用途、未越线的小团队,用 Docker Desktop 省事;公司已越线、或者你在意合规风险,就在 WSL2 里装 docker-ce。

想让容器一直在线,先搞清它为什么会掉

第二个问题的答案是:必须做额外操作。而且原因很反直觉。

WSL2 有两道空闲超时,默认都开着:

  • instanceIdleTimeout,写在 .wslconfig 的 [general] 段,默认约 8 秒 —— 当实例里所有用户进程都结束后,多久关掉这个发行版
  • vmIdleTimeout,写在 [wsl2] 段,默认 60000 毫秒 —— 当所有实例都停止后,多久销毁整个 WSL2 轻量 VM

WSL2 的两级空闲超时关闭链路

换句话说:你关掉最后一个终端窗口,8 秒后发行版关闭,dockerd 被杀,容器全灭;再过 60 秒,整个 VM 也被销毁,内存归还给 Windows。

这里有个几乎所有人都会踩的误解:systemctl enable docker 保不了活。

它只解决了「实例启动时自动把 dockerd 拉起来」,没有解决两件更根本的事:开机后根本没人启动这个实例,以及实例自己在 8 秒后会关掉。systemd 管理的服务不算「用户进程」,WSL 该关还是关。有用户报告,启用 systemd 之后连一个独立的 tmux 会话都会被一起带走。

关于「另起一个保活用的 WSL 实例」这个思路,它不成立,而且方向反了。所有 WSL 发行版共享同一个轻量 VM,VM 被销毁时它们一起死,多开一个实例只是白吃一份内存。要保活的是那个共享 VM,不是在它里面加实例。

保活要过三道闸门

第一道,先让实例别自杀。在 Windows 用户目录下创建或编辑 .wslconfig:

[general]
instanceIdleTimeout=-1

[wsl2]
vmIdleTimeout=-1
memory=8GB

-1 表示永不自动关闭。改完必须执行 wsl --shutdown 才生效。顺带建议显式设 memory 上限 —— 默认 WSL 可以吃掉宿主机一半内存,常驻不退的话会一直占着。

第二道,让实例真的存在,并挂住一个常驻进程。WSL 不会开机自启,必须有人拉它。最直白的做法是用 Windows 计划任务挂一个不会结束的进程:

wsl.exe -d Ubuntu -u root -e sleep infinity

这个 wsl.exe 进程会一直挂着,实例就一直活着。

第三道,容器自己要有重启策略。docker run 时加 --restart=always,或者 compose 里写 restart: unless-stopped。后者的意思是「除非你手动停过,否则总拉起来」,做常驻服务时可控性更好。

还有个好消息:如果你用 Docker Desktop,这三道闸门基本不用你操心 —— 它是个 Windows 侧应用,开机自启后会自己拉起并维持 WSL 实例。但有个细节要知道:Resource Saver 在 WSL 上的行为和 Mac 不同。官方文档明确说,它只暂停 docker-desktop 发行版里的 Docker Engine,不会停 WSL VM,因为那个 Linux VM 是所有发行版共享的、不归 Docker 管。好消息是它的触发条件是「持续一段时间没有容器运行」(默认 5 分钟),所以只要有容器一直在跑,它就不会介入。

7×24 服务,关键变成谁在管那个 VM

到这里才是真正分岔的地方。开发场景下两条路差异不大,但一旦变成无人值守的对外服务,判断依据就换了:这个 VM 的生命周期由什么驱动。

Windows 上跑 Linux 容器的三条路径与生命周期驱动者

三条路摆在一起看:

  • Docker Desktop + Hyper-V 后端:由 com.docker.service 这个 Windows 服务驱动,不依赖用户登录
  • Docker Desktop + WSL2 后端:由 Docker Desktop.exe 这个用户态应用驱动,依赖会话
  • WSL2 原生引擎:由 wsl.exe 会话驱动,依赖用户进程

后两条本质上都是在跟 WSL 的设计意图拔河。WSL 是个开发工具 —— 按需启动、空闲自杀、内存动态回收。你做的所有保活配置都是在对抗这个取向,而这种对抗在 Windows 更新之后容易失效。

所以如果必须二选一,选 Docker Desktop,前提是切到 Hyper-V 后端。这是三条路里唯一一条从 Windows 服务起步的。

这个切换有两个门槛。一是需要 all-users 安装模式(装到 C:\Program Files,要管理员权限),官方文档写得很明确:Hyper-V 只在 all-users 安装时可用,默认的 per-user 安装没有这个选项。二是需要专业版或更高 —— 家庭版没有 Hyper-V。另外补一句:Docker Desktop 官方不支持 Windows Server,2019 和 2022 都不行。

切过去之后,让它在无人登录的情况下启动,可以用官方的 headless 参数配合任务计划程序。注意要用「创建任务」而不是「创建基本任务」,触发器选「启动时」,勾选「使用最高权限运行」:

"C:\Program Files\Docker\Docker\Docker Desktop.exe" --headless

后面那串参数是官方提供的无界面运行方式,配合 S4U 登录类型可以在不把密码写到磁盘的前提下工作。

但更好的答案不是在两者里选

如果真实约束是「必须用 Windows 机器」,而不是「必须用 Docker Desktop」,那最优解其实是第三条路:

在 Hyper-V 里跑一个标准 Ubuntu Server VM,在 VM 里装 Docker Engine。Docker Desktop 和 WSL 都不用。

听起来更麻烦,但它一次解决了前面所有问题:

  • 不依赖用户登录:VM 的「自动启动操作」设为「始终自动启动」,由 Hyper-V 主机服务在开机时拉起,不需要任何用户会话
  • 网络干净:用外部虚拟交换机给 VM 分一个局域网固定 IP,对外服务不需要 netsh portproxy,Windows 重启也不影响
  • 有检查点:升级出问题能回滚,这是 WSL 完全没有的能力
  • 不牵扯 Docker Desktop 的授权
  • 就是一个标准 Linux 服务器:现成的运维知识、脚本、systemd 配置、journalctl 排障流程全部可用

代价是内存要固定分配(WSL 是动态共享的),而且需要专业版以上。如果这台机器是专职跑服务的,这两点都不是问题。

如果只有 Windows 家庭版

这是最后一个被追加的约束,而它把前面给出的最优解直接推翻了。

家庭版缺的不只是一个 Hyper-V:

缺失的能力对 7×24 服务的影响
Hyper-V无法用「Hyper-V VM + Docker Engine」这条最优路径
组策略(gpedit.msc)无法长期推迟 Windows 更新,自动重启是无人值守服务的头号杀手
远程桌面主机不能作为 RDP 目标,无人值守机器的运维通道要另想办法
BitLocker 管理只有简易设备加密,没有恢复密钥托管

最要命的是中间两条。家庭版没法长期推迟更新,只能用注册表(NoAutoRebootWithLoggedOnUsers、AUOptions)硬撑,而这些键在功能更新后可能被重置。而远程桌面主机这一条,意味着你得改用 SSH、RustDesk 或 VNC 之类的通道。

关于 Hyper-V:家庭版不能启用它。用 dism 强行打开也没用 —— 外部虚拟交换机、嵌套虚拟化、第二代虚拟机这些「只在专业版上正常工作」,在家庭版上要么组件缺失,要么服务看起来启动了但实际不工作。这不是技术能力问题,是微软在操作系统层面划的许可边界。

于是家庭版实际只剩 WSL2 一条路。第三方虚拟机(VirtualBox、VMware)算备选,但它们的 VM 注册同样是按用户的,一样绕不过登录问题,还要和 WSL2 抢虚拟化后端 —— 得关掉内存完整性才能跑全速。

在这条路上,我建议用原生 docker-ce 而不是 Docker Desktop:少一层桌面应用依赖,可预测性更好。无人值守服务里,可预测性比省事重要 —— Docker Desktop 那些「贴心」的自动化(自动更新、Resource Saver)在这个场景下全都变成不可控的变量。

还有个缺口必须说清楚:家庭版没有官方支持的无用户登录自启方案。

WSL 发行版注册在 HKCU\...\Lxss 注册表里,是按用户的。社区流传的用 SYSTEM 账户跑 wsl.exe 的做法(再配合 WSL 内的 loginctl enable-linger)有人成功,也有人稳定失败,典型报错是 return code 4294967295。这不是微软支持的路径。

稳的做法是配置 Windows 自动登录,再把保活挂在用户级计划任务上:触发器设「登录时」,再加一个每 2 分钟重复的巡检。代价很直白 —— 任何能物理接触这台机器的人,开机即进桌面。

顺带避一个坑:网上有回答给出 [wsl2] autostart=true 这个配置项,它根本不存在,别照抄。

结论

把四层约束的结论并排放在一起:

你的情况该选什么主要原因
个人开发、学习、未越线的小团队Docker Desktop(WSL2 后端)省事,省下的配置和排障时间超过那点内存开销
公司已越 250 人或 1000 万美元WSL2 原生 docker-ceApache 2.0 免费,避开授权审计风险
要贴近生产、要写 CI、要调 daemonWSL2 原生 docker-ce与线上 Linux 主机完全一致
内存吃紧、讨厌常驻 GUIWSL2 原生 docker-ce没有托管 VM 和托盘进程那层开销
必须 Windows、能做 7×24 服务、有专业版Hyper-V VM + Docker Engine唯一从系统服务起步的路径,还能配固定 IP
必须 Windows、且想用 DesktopDocker Desktop + Hyper-V 后端三条路里唯一从 Windows 服务起步的
Windows 家庭版WSL2 原生 docker-ceHyper-V 用不了,只剩这条路

最后说一句实在话。如果这个服务有「不能停」的语义,就不该让一台 Windows 桌面机成为唯一节点。桌面机硬件没有冗余,系统更新会强制重启,断电就是硬关机 —— 而 WSL 的 ext4.vhdx 在非正常关机后的损坏是有实证案例的:微软官方问答区就有人拿它跑生产站点的数据然后挂掉了,典型报错是 Error code: 74 Wsl/Service/CreateInstance/E_FAIL,VHDX 文件还在、大小正常,但死活挂不上,救援手段是 wsl --mount --vhd --bare 配合 e2fsck。

还有一件事无论选哪条路都值得做:别让业务数据只活在 VM 磁盘里。数据库的 volume 挂到 NTFS 分区,或者定期导出 dump,再加一个定期的 wsl --export 冷备份。这样即使 VM 磁盘出事,数据还在。

参数、有效期和定价都会变,动手前建议核对一下官方文档当期的说法。

参考资料

打开原图 ↗