Docker Desktop 启动超时排查:一次 WslService 卡死导致的 WSL CommandTimedOut 故障
最近在 Windows 开发环境中启动 Docker Desktop 时,遇到了一个看起来像是 Docker Desktop 自身不稳定的问题。
Docker Desktop 启动失败,并提示:
A timeout occurred while preparing WSL distro for Docker Desktop.
Restart Docker Desktop.
listing WSL distros: running wslexec:
An error occurred while running the command.
DockerDesktop/Wsl/CommandTimedOut:
c:\windows\system32\wsl.exe -l -v --all:
exit status 1
第一反应很容易是:
Docker Desktop 又挂了?
但经过逐层排查后发现,这次故障实际上并不发生在 Docker Engine、containerd,甚至还没有真正进入 Docker Desktop 的 Linux Backend 启动阶段。
真正卡住的是 Windows 侧的 WSL Service(WslService)。
最终通过强制结束异常的 wslservice.exe 进程并重新启动 WslService,在不重启 Windows、不重装 Docker Desktop、不重置 WSL 的情况下恢复正常。
本文完整记录这次问题的定位过程。
一、故障现象
Docker Desktop 启动时出现:
DockerDesktop/Wsl/CommandTimedOut
其中最关键的信息不是 DockerDesktop,而是下面这条命令:
c:\windows\system32\wsl.exe -l -v --all
Docker Desktop 在启动 WSL Backend 之前,需要先查询当前系统中的 WSL Distribution。
正常情况下执行:
wsl -l -v --all
应该立即返回类似:
NAME STATE VERSION
* Ubuntu Stopped 2
docker-desktop Stopped 2
但是在本次故障中:
wsl -l -v --all
直接卡住,没有任何返回。
这实际上是整个排查过程中最重要的一个信息。
因为这意味着:
Docker Desktop 报超时只是表象,真正发生超时的是 Windows 的
wsl.exe。
二、第一步:脱离 Docker Desktop 检查 WSL
遇到 Docker Desktop 的 WSL 错误时,不建议第一时间:
重装 Docker Desktop
Reset to factory defaults
删除 docker-desktop
重装 WSL
这些操作不仅比较重,而且有可能破坏原有 Docker 环境。
应该首先脱离 Docker Desktop,直接测试 WSL:
wsl --status
wsl -l -v --all
结果:
wsl -l -v --all
持续卡住。
到这里实际上已经可以初步判断:
Docker Desktop
│
│ 调用
▼
wsl.exe
│
▼
WSL 管理层
│
X
卡住
也就是说,此时继续研究 Docker Engine、containerd、Docker 镜像、Docker 网络已经没有意义。
因为 Docker Desktop 甚至还没有走到那个阶段。
三、尝试关闭 WSL,出现 0x80080005
通常 WSL 出现临时异常时,一个非常有效的恢复方法是:
wsl --shutdown
它会关闭当前 WSL2 Utility VM。
但本次执行后直接报错:
服务器运行失败
错误代码: Wsl/0x80080005
即:
Wsl/0x80080005
Server execution failed
这时候问题进一步明确了。
现在已经同时出现:
wsl -l -v --all
↓
卡死
wsl --shutdown
↓
Wsl/0x80080005
这说明已经不是某个 Linux Distribution 中的应用程序卡住,而是 Windows 侧负责管理 WSL 的组件出现异常。
四、检查 WSL 和 Hyper-V 服务状态
接下来检查 Windows 服务:
Get-Service WslService -ErrorAction SilentlyContinue
Get-Service LxssManager -ErrorAction SilentlyContinue
Get-Service vmcompute
Get-Service hns
现场结果:
Status Name DisplayName
------ ---- -----------
StopP... WslService WSL Service
Stopped LxssManager LxssManager
Running vmcompute Hyper-V 主机计算服务
Running hns 主机网络服务
这里出现了一个非常关键的异常:
WslService
StopP...
也就是:
STOP_PENDING
与此同时:
vmcompute = Running
hns = Running
说明 Hyper-V Host Compute Service 和 Host Network Service 本身仍然处于运行状态。
继续检查进程:
Get-Process wsl,wslservice,vmmem,vmmemWSL -ErrorAction SilentlyContinue
得到:
Handles NPM(K) PM(K) WS(K) CPU(s) Id ProcessName
------- ------ ----- ----- ------ -- -----------
274 16 5332 18472 0.11 22768 wslservice
此时系统中:
wslservice.exe 存在
vmmemWSL 不存在
问题开始高度集中到 WslService。
五、确认 WslService 卡在 STOP_PENDING
进一步通过 Windows Service Control Manager 查看:
sc.exe queryex WslService
结果:
SERVICE_NAME: WslService
TYPE : 10 WIN32_OWN_PROCESS
STATE : 3 STOP_PENDING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 22768
这个结果基本坐实了问题。
WslService 已经收到了停止请求,进入:
STOP_PENDING
但对应进程:
PID = 22768
始终没有退出。
尤其值得注意的是:
CHECKPOINT : 0x0
WAIT_HINT : 0x0
正常 Windows Service 如果停止过程需要较长时间,通常会通过 CheckPoint 和 WaitHint 向 Service Control Manager 汇报停止进度。
而当前服务长时间停留在:
STOP_PENDING
且没有进一步进展。
这已经非常符合"服务退出流程卡死"的特征。
六、检查 vmcompute
为了确认是不是底层 Hyper-V Compute Service 同时出现问题,又检查:
sc.exe queryex vmcompute
结果:
SERVICE_NAME: vmcompute
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
PID : 26008
也就是说:
WslService STOP_PENDING ← 异常
vmcompute RUNNING ← 正常
hns RUNNING ← 正常
因此此时没有必要贸然:
重置 Hyper-V
重启 HNS
删除虚拟网络
重新启用 VirtualMachinePlatform
故障范围已经可以进一步缩小到:
WslService自身,或者WslService正在等待的某个 WSL 管理对象。
七、强制结束卡死的 WslService
由于 WslService 已经无法正常停止,最终决定强制结束其进程:
taskkill /PID 22768 /F
然后再次检查:
sc.exe queryex WslService
状态变为:
SERVICE_NAME: WslService
STATE : 1 STOPPED
WIN32_EXIT_CODE : 1067 (0x42b)
PID : 0
这里出现:
WIN32_EXIT_CODE : 1067
并不奇怪。
因为我们刚刚通过 taskkill /F 强制结束了服务进程,所以 Service Control Manager 会认为服务进程发生了异常终止。
这并不是新的故障。
关键是:
STATE : STOPPED
PID : 0
说明之前卡死的 wslservice.exe 已经真正退出。
八、重新启动 WslService
接下来:
Start-Service WslService
再次查看:
sc.exe queryex WslService
得到:
SERVICE_NAME: WslService
STATE : 4 RUNNING
WIN32_EXIT_CODE : 0 (0x0)
PID : 29920
注意这里 PID 已经发生变化:
原 PID:22768
新 PID:29920
说明 Windows 已经启动了一个新的 wslservice.exe。
九、验证 WSL 是否恢复
先不启动 Docker Desktop,直接执行:
wsl --status
正常返回:
默认分发: Ubuntu
默认版本: 2
然后:
wsl -l -v --all
立即返回:
NAME STATE VERSION
* Ubuntu Stopped 2
docker-desktop Stopped 2
至此 WSL 管理面完全恢复。
整个过程中:
-
没有重启 Windows
-
没有重装 Docker Desktop
-
没有重装 WSL
-
没有删除
docker-desktop -
没有 Reset Docker Desktop
-
没有修改 Hyper-V
-
没有破坏 Docker 数据
只是将卡死的:
wslservice.exe
强制结束并重新启动。
十、完整故障链
回过头来看,这次故障链已经非常清晰:
Windows
│
▼
WslService
│
├── 正常情况下负责 WSL 管理
│
▼
进入 STOP_PENDING
│
│
└── wslservice.exe 无法完成退出
│
├──────────────┐
│ │
▼ ▼
wsl -l -v --all wsl --shutdown
│ │
▼ ▼
卡死 0x80080005
│
│
▼
Docker Desktop
│
│ 启动时执行
▼
wsl.exe -l -v --all
│
▼
一直等待
│
▼
DockerDesktop/Wsl/CommandTimedOut
因此:
DockerDesktop/Wsl/CommandTimedOut
是故障结果,并不是这次故障的真正根因。
十一、为什么 WslService 会卡死?
这里需要区分两个概念:
1. 已经确认的直接原因
已经可以确定:
WslService收到了停止请求并进入STOP_PENDING,但服务进程没有完成退出。
因此所有需要通过 WSL Service 完成的操作都出现异常。
包括:
wsl -l -v
wsl --status
wsl --shutdown
以及 Docker Desktop 对:
wsl.exe
的调用。
2. 为什么退出流程没有完成?
这一层仅凭当前现场还不能百分之百确定。
WSL2 并不是简单的 Linux 进程,它背后涉及:
Windows
│
├── WslService
│
├── Hyper-V Host Compute Service
│
├── HNS
│
├── Utility VM
│
├── VHDX
│
├── Hyper-V Socket / IPC
│
└── Linux Kernel
因此 WslService 在启动或关闭 WSL 环境时,需要协调多个对象。
如果某个对象没有按照预期返回,就可能出现类似:
WslService
│
▼
等待某个 WSL/VM/IPC/VHDX 对象
│
▼
一直没有完成
│
▼
STOP_PENDING
比较常见的诱因包括:
-
WSL 自身的状态机异常
-
WSL 版本回归或 Bug
-
Docker Desktop 与 WSL 的特定版本组合问题
-
Windows 睡眠/休眠后的虚拟化状态异常
-
Docker Desktop 长时间运行后 WSL 状态异常
-
Windows Update 或 WSL Update 后组件状态不一致
-
WSL Utility VM、VHDX 或 IPC/vSocket 退出过程中异常
-
内存或 I/O 压力导致 WSL Backend 状态异常
所以不能简单地得出:
Docker Desktop 不稳定。
更准确的描述应该是:
Docker Desktop 的 WSL2 Backend 依赖 Windows WSL 管理栈,因此 WSL 管理服务发生异常时,最终往往会以 Docker Desktop 启动失败的形式表现出来。
十二、以后再遇到,可以快速定位
以后看到:
DockerDesktop/Wsl/CommandTimedOut
第一件事不是重装 Docker Desktop。
先执行:
wsl -l -v --all
情况一:正常返回
那么继续调查 Docker Desktop 自身:
docker-desktop distro
Docker Backend
containerd
Docker Engine
网络
磁盘
情况二:命令本身卡住
问题已经下沉到:
Windows / WSL
尝试:
wsl --shutdown
如果成功,再重新启动 Docker Desktop。
情况三:出现 0x80080005
例如:
服务器运行失败
错误代码: Wsl/0x80080005
马上检查:
sc.exe queryex WslService
如果发现:
STATE : 3 STOP_PENDING
并且长期不恢复,再获取 PID:
PID : XXXXX
强制结束:
taskkill /PID XXXXX /F
然后:
Start-Service WslService
最后:
wsl --status
wsl -l -v --all
如果全部正常,再启动 Docker Desktop。
十三、建议保留的一套快速诊断命令
以后再遇到 Docker Desktop + WSL 异常,可以先执行:
wsl --status
wsl -l -v --all
Get-Service WslService -ErrorAction SilentlyContinue
Get-Service LxssManager -ErrorAction SilentlyContinue
Get-Service vmcompute
Get-Service hns
Get-Process wsl,wslservice,vmmem,vmmemWSL -ErrorAction SilentlyContinue
sc.exe queryex WslService
sc.exe queryex vmcompute
这几条命令基本可以快速回答几个问题:
是 Docker 的问题?
│
├── 还是 WSL 的问题?
│
├── WslService 是否卡死?
│
├── WSL VM 是否仍存在?
│
└── vmcompute 是否正常?
比一上来重装 Docker Desktop 有效得多。
十四、如果问题反复出现,还要继续追根因
本文解决的是:
如何从 Docker Desktop 的
Wsl/CommandTimedOut定位到WslService STOP_PENDING,并恢复环境。
但如果同一台机器频繁出现 WslService 卡死,就不能满足于每次:
taskkill
而应该进一步检查版本:
wsl --version
winver
同时记录 Docker Desktop 版本。
还可以在故障现场检查 Windows Event Log:
Get-WinEvent -LogName "Microsoft-Windows-Hyper-V-Compute-Admin" -MaxEvents 50 |
Format-List TimeCreated,Id,LevelDisplayName,Message
以及:
Get-WinEvent -LogName "System" -MaxEvents 200 |
Where-Object {
$_.ProviderName -match "Service Control Manager|Hyper-V|Host-Network-Service"
} |
Select-Object TimeCreated,ProviderName,Id,LevelDisplayName,Message
如果能够把:
WslService 卡死时间
+
Windows Event Log
+
WSL Version
+
Windows Build
+
Docker Desktop Version
对应起来,就有机会继续判断到底属于:
WSL Bug
Windows/Hyper-V Bug
Docker Desktop 触发问题
特定版本兼容性问题
休眠/恢复问题
资源压力问题
而不是长期停留在"Docker Desktop 偶尔不稳定"的结论上。
十五、总结
这次问题最值得记录的并不是最终执行了:
taskkill /PID 22768 /F
Start-Service WslService
而是整个定位思路。
看到:
DockerDesktop/Wsl/CommandTimedOut
不要被 DockerDesktop 这个前缀误导。
真正关键的是错误信息里的:
wsl.exe -l -v --all
于是脱离 Docker Desktop 单独执行该命令。
发现:
wsl -l -v --all
→ 卡死
继续:
wsl --shutdown
→ Wsl/0x80080005
再检查:
WslService
→ STOP_PENDING
同时:
vmcompute
→ RUNNING
hns
→ RUNNING
最终将故障范围从:
Docker Desktop 启动失败
逐步缩小到了:
wslservice.exe 卡死
强制结束旧进程并重新启动服务后:
WslService → RUNNING
wsl --status → 正常
wsl -l -v --all → 正常
问题解决。
这也是排查 Windows + WSL2 + Docker Desktop 问题时非常重要的一条原则:
先确定哪一层真正失败,再处理哪一层。不要因为错误最终显示在 Docker Desktop 上,就直接重装 Docker。
Docker Desktop 只是 WSL2 的消费者之一。
当 wsl.exe 自己都已经无法正常工作时,应该首先解决 WSL,而不是 Docker。