☸️ WSL2 Docker 数据持久化:docker-desktop-data 缺失导致容器丢失的诊断与修复

📌 一、问题场景

在日常开发中,使用 Docker Desktop + WSL2 后端是一个常见组合。然而部分开发者在执行 wsl --shutdown 后,重新打开终端时发现一个严重问题: 之前创建的所有容器、镜像、数据卷全部消失

以下是一个典型的问题复现过程:

#  1. 正常使用 Docker,创建测试容器
$ docker run -d --name my-app -p 8080:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
...
cc3c2e0be814: Pull complete
Status: Downloaded newer image for nginx:latest
a1b2c3d4e5f6...  # 容器启动成功

#  2. 确认容器正在运行
$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                  NAMES
a1b2c3d4e5f6   nginx     "/docker-entrypoint.…"   5 seconds ago   Up 5 seconds   0.0.0.0:8080->80/tcp   my-app

#  3. 手动执行 WSL 关闭(或系统重启触发)
$ wsl --shutdown

#  4. 重新打开终端,检查容器
$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
#  输出为空 —— 所有容器消失!

这个场景的核心问题在于:Docker Desktop 在 WSL2 中的持久化数据没有被正确保存,导致 wsl --shutdown 后所有状态丢失。本文将深入分析根因并提供完整的修复方案。

🔍 二、Docker Desktop 在 WSL2 中的架构

要理解数据为什么丢失,首先需要搞清楚 Docker Desktop 在 WSL2 模式下的内部架构。

🔢 2.1 核心组件

Docker Desktop 在 WSL2 中运行时会创建 两个 WSL 发行版(WSL Distribution),各自承担不同的职责:

flowchart LR
    %% ==========================================
    %% 样式定义
    %% ==========================================

    ROOT[Docker Desktop\nWSL2 后端架构]

    ROOT --> DD[docker-desktop\n守护进程实例]
    ROOT --> DDD[docker-desktop-data\n数据存储实例]

    DD --> DD_ROLE["⚙️ 运行 Docker 守护进程 (dockerd)\n• 管理容器生命周期\n• 处理 API 请求 (docker CLI)\n• 编排镜像构建与容器调度"]
    DD --> DD_STORAGE["⚠️ 临时存储 (非持久化)\n• /var/lib/docker (部分运行时数据)\n• 仅在 docker-desktop 内部"]

    DDD --> DDD_ROLE["💾 持久化数据存储\n• 镜像层 (image layers)\n• 容器文件系统 (container FS)\n• 数据卷 (volumes)\n• Docker 引擎状态"]

    DD -.->|读取/写入镜像与容器数据| DDD
    style ROOT fill:#0f172a,stroke:#3b82f6,stroke-width:2px,color:#ffffff,font-weight:bold
    style DD fill:#2d1a05,stroke:#f59e0b,stroke-width:2px,color:#ffffff,font-weight:bold
    style DDD fill:#2d1a05,stroke:#f59e0b,stroke-width:2px,color:#ffffff,font-weight:bold
    style DD_ROLE fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style DDD_ROLE fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style DD_STORAGE fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#ffffff,font-weight:bold

🛠️ 2.2 两个 WSL 实例的职责对比

组件WSL 实例名称核心职责数据持久性wsl --shutdown
守护进程实例docker-desktop运行 Docker 守护进程(dockerd),处理 CLI 请求运行时临时数据重置(临时数据丢失)
数据存储实例docker-desktop-data存储镜像层、容器文件系统、数据卷、网络配置等持久化存储数据保留(存储在独立 VHD 中)

两者的关系可以概括为: docker-desktop计算层docker-desktop-data存储层 。Docker 守护进程在 docker-desktop 中运行,但所有需要持久化的数据都写入 docker-desktop-data 对应的虚拟磁盘文件中。

🔢 2.3 正常状态下的数据流

sequenceDiagram
    participant User as 用户
    participant CLI as docker CLI
    participant Daemon as dockerd(docker-desktop)
    participant Data as docker-desktop-data

    User->>CLI: docker run -d nginx
    CLI->>Daemon: REST API 请求创建容器
    Daemon->>Data: 检查镜像缓存
    Data-->>Daemon: 返回镜像层信息
    Daemon->>Data: 拉取镜像层 (如本地不存在)
    Daemon->>Data: 创建容器可写层
    Daemon->>Data: 写入容器元数据
    Daemon-->>CLI: 返回容器 ID
    CLI-->>User: 显示容器 ID

    Note over User,Data: --- wsl --shutdown 后重启 ---

    User->>CLI: docker ps -a
    CLI->>Daemon: 查询容器列表
    Daemon->>Data: 读取容器元数据
    Data-->>Daemon: 返回持久化的容器信息
    Daemon-->>CLI: 返回容器列表
    CLI-->>User: 显示之前的容器 ✓

在正常情况下, docker-desktop-data 独立存储所有持久化数据, wsl --shutdown 后守护进程重启时能够从数据实例中恢复完整状态。

⚙️ 三、问题根因分析

🔢 3.1 故障状态的架构

docker-desktop-data 实例缺失时,系统处于以下异常状态:

flowchart TD
    %% ==========================================
    %% 样式定义
    %% ==========================================

    %% ==========================================
    %% 缺失数据实例的问题链条
    %% ==========================================
    subgraph ABNORMAL ["异常状态:docker-desktop-data 缺失"]
        START([Docker Desktop 启动]) --> CHECK{"WSL 实例列表\n是否存在\ndocker-desktop-data ?"}
        CHECK -- 否(缺失) --> FALLBACK["dockerd 将数据写入\ndocker-desktop 内部存储"]
        FALLBACK --> NOTE["镜像/容器/卷\n全部存储在 docker-desktop 中"]
    end

    %% ==========================================
    %% shutdown 后果链
    %% ==========================================
    subgraph SHUTDOWN ["wsl --shutdown 的影响"]
        SHUT([执行 wsl --shutdown]) --> TERM["所有 WSL 实例终止"]
        TERM --> RESET["docker-desktop 实例重置\n(该实例设计为无状态)"]
        RESET --> LOSS["内部临时数据全部清除"]
    end

    %% ==========================================
    %% 最终结果
    %% ==========================================
    subgraph RESULT ["最终后果"]
        RESULT1["容器全部丢失"]
        RESULT2["镜像全部丢失"]
        RESULT3["数据卷全部丢失"]
        RESULT4["每次需重建容器"]
    end

    NOTE -.-> SHUTDOWN
    LOSS --> RESULT1
    LOSS --> RESULT2
    LOSS --> RESULT3
    RESULT1 --> RESULT4
    style START fill:#701a4c,stroke:#e11d48,stroke-width:2px,color:#ffffff,font-weight:bold
    style SHUT fill:#701a4c,stroke:#e11d48,stroke-width:2px,color:#ffffff,font-weight:bold
    style CHECK fill:#2a1147,stroke:#a855f7,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style FALLBACK fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style NOTE fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style TERM fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style RESET fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style LOSS fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style RESULT1 fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style RESULT2 fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style RESULT3 fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style RESULT4 fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#ffffff,font-weight:bold

🛠️ 3.2 为什么安装路径(C盘/D盘)不是根因

很多用户将 WSL2 安装在 D 盘,遇到问题后第一反应是"磁盘路径有问题"。但实际上:

因素与问题的关系说明
WSL 安装在 C 盘无直接关系默认安装同样可能出现此问题
WSL 安装在 D 盘无直接关系只是 VHD 文件存放位置不同
Docker Desktop 安装路径无直接关系问题出在 WSL 实例层面
docker-desktop-data 实例缺失直接根因缺少持久化存储目标

问题本质是 Docker Desktop 初始化 WSL2 后端时未能正确创建 docker-desktop-data 实例 ,导致持久化数据无处存放。这与磁盘分区、安装路径无关。

✅ 3.3 如何确认自己是否遇到此问题

#  检查 WSL 实例列表
$ wsl --list --verbose
  NAME                   STATE           VERSION
* docker-desktop         Running         2

如果输出中 只有 docker-desktop缺少 docker-desktop-data ,则你的环境存在本文描述的问题。正常环境应同时出现两个实例:

#  正常环境的输出
$ wsl --list --verbose
  NAME                   STATE           VERSION
* docker-desktop         Running         2
  docker-desktop-data    Stopped         2

📊 四、解决方案

🔢 4.1 整体修复流程

以下是完整的修复流程概览:

flowchart TD
    %% ==========================================
    %% 样式定义
    %% ==========================================

    %% ==========================================
    %% 修复流程
    %% ==========================================
    subgraph PHASE1 ["阶段一:准备"]
        P1_START([开始修复]) --> P1_CLOSE["关闭 Docker Desktop"]
        P1_CLOSE --> P1_TERM["wsl --terminate docker-desktop"]
    end

    %% ==========================================
    %% 创建数据实例
    %% ==========================================
    subgraph PHASE2 ["阶段二:创建数据实例"]
        P1_TERM --> P2_DIR["创建目标目录\nNew-Item -Path D:\\WSL\\docker-desktop-data\n-ItemType Directory -Force"]
        P2_DIR --> P2_DL["下载 Alpine Linux rootfs\n作为 WSL 初始化文件"]
        P2_DL --> P2_IMPORT["wsl --import docker-desktop-data\nD:\\WSL\\docker-desktop-data\nalpine-rootfs.tar.gz --version 2"]
        P2_IMPORT --> P2_CLEAN["清理临时 rootfs 文件"]
    end

    %% ==========================================
    %% 验证与测试
    %% ==========================================
    subgraph PHASE3 ["阶段三:验证"]
        P2_CLEAN --> P3_CHECK{"wsl --list --verbose\n确认 docker-desktop-data\n出现 ?"}
        P3_CHECK -- 是 --> P3_RESTART["重启 Docker Desktop"]
        P3_CHECK -- 否 --> P3_RETRY["检查导入命令\n重新执行阶段二"]
        P3_RESTART --> P3_TEST["测试:docker run -d --name test nginx"]
        P3_TEST --> P3_SHUTDOWN["wsl --shutdown"]
        P3_SHUTDOWN --> P3_VERIFY{"docker ps -a\n容器是否存在 ?"}
        P3_VERIFY -- 是 --> P3_DONE([修复成功])
        P3_VERIFY -- 否 --> P3_RETRY
    end
    style P1_START fill:#701a4c,stroke:#e11d48,stroke-width:2px,color:#ffffff,font-weight:bold
    style P3_DONE fill:#701a4c,stroke:#e11d48,stroke-width:2px,color:#ffffff,font-weight:bold
    style P3_CHECK fill:#2a1147,stroke:#a855f7,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style P3_VERIFY fill:#2a1147,stroke:#a855f7,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style P1_CLOSE fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style P1_TERM fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style P2_DIR fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style P2_DL fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style P2_IMPORT fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style P2_CLEAN fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style P3_RESTART fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#ffffff
    style P3_TEST fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style P3_SHUTDOWN fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#ffffff,font-weight:bold

🔢 4.2 详细操作步骤

🛠️ 步骤一:准备工作

首先关闭 Docker Desktop,可以通过系统托盘图标右键退出,然后终止 WSL 中正在运行的 docker-desktop 实例:

#  在 PowerShell(管理员权限)中执行
wsl --terminate docker-desktop

--terminate 会优雅终止指定 WSL 实例中的所有进程,比 --shutdown (终止所有实例)更精准。

📥 步骤二:下载 Alpine Linux rootfs

WSL 的 --import 命令需要一个合法的 Linux rootfs 文件作为初始化的种子。这里选择 Alpine Linux,因为它体积小(约 3 MB):

#  下载 Alpine mini rootfs
Invoke-WebRequest -Uri "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-minirootfs-3.19.0-x86_64.tar.gz" -OutFile "D:\alpine-rootfs.tar.gz"

rootfs (Root Filesystem)是 Linux 系统的最小文件系统骨架,包含 /bin/etc/lib 等基础目录结构。WSL 用它初始化新实例的根文件系统。

🔧 步骤三:创建 docker-desktop-data 实例

#  创建目标目录
New-Item -Path "D:\WSL\docker-desktop-data" -ItemType Directory -Force

#  导入 WSL 实例
wsl --import docker-desktop-data "D:\WSL\docker-desktop-data" "D:\alpine-rootfs.tar.gz" --version 2

参数说明:

参数含义
docker-desktop-data新 WSL 实例的名称(必须与此完全一致)
D:\WSL\docker-desktop-data实例的 VHD 虚拟磁盘存放路径
D:\alpine-rootfs.tar.gz用于初始化的 rootfs 文件
--version 2指定使用 WSL2 内核

✅ 步骤四:清理并验证

#  删除临时 rootfs 文件
Remove-Item "D:\alpine-rootfs.tar.gz"

#  确认实例创建成功
wsl --list --verbose

期望输出:

  NAME                   STATE           VERSION
* docker-desktop         Stopped         2
  docker-desktop-data    Stopped         2

注意 docker-desktop-data 状态为 Stopped 是正常的——该实例不需要主动运行,Docker Desktop 只会挂载其虚拟磁盘来读写数据。

🔄 步骤五:重启 Docker Desktop 并验证

启动 Docker Desktop,等待引擎就绪后执行测试:

#  创建测试容器
$ docker run -d --name test-nginx nginx

#  确认容器存在
$ docker ps
CONTAINER ID   IMAGE     ...   NAMES
b2c3d4e5f6a7   nginx     ...   test-nginx

#  执行 shutdown 测试
$ wsl --shutdown

#  重启后验证
$ docker ps -a
CONTAINER ID   IMAGE     ...   NAMES
b2c3d4e5f6a7   nginx     ...   test-nginx  # 容器依然存在!

🔢 4.3 修复前后的状态对比

维度修复前修复后
WSL 实例数量1 个(仅 docker-desktop2 个( docker-desktop + docker-desktop-data
数据存储位置docker-desktop 内部(临时)docker-desktop-data 的独立 VHD 中
wsl --shutdown所有容器/镜像/卷丢失数据完整保留
磁盘占用占用 C 盘(默认 VHD 位置)数据固定在指定路径(可放 D 盘)

🛠️ 五、注意事项

🔢 5.1 旧数据无法恢复

此方案是 创建新的 docker-desktop-data 实例 ,而非修复已有实例。在修复之前,Docker 的镜像和容器数据从未真正持久化过——它们被写入 docker-desktop 的内部临时存储中,每次 wsl --shutdown 时都会被清除。因此:

  • 修复前的容器/镜像/卷会丢失 :这本就是问题本身的症状,这些数据从未被持久化。
  • 如需保留当前运行中的容器数据,可在修复前执行 docker commit 或导出镜像备份。

🛠️ 5.2 docker-desktop-data 的 Stopped 状态

执行 wsl --list --verbose 时, docker-desktop-data 显示为 Stopped完全正常 的:

  • docker-desktop-data 不需要运行一个独立的 Linux 内核实例
  • Docker Desktop 通过 挂载其虚拟磁盘(VHD) 的方式访问其中的数据
  • 只有在需要手动维护(如备份/导出)时才需要启动该实例

🔢 5.3 关于备份

创建好 docker-desktop-data 后,建议定期备份:

#  导出数据实例为 tar 文件
wsl --export docker-desktop-data D:\backup\docker-data-$(Get-Date -Format 'yyyyMMdd').tar

wsl --export 会将 WSL 实例的完整文件系统打包为 tar 归档,包含了所有 Docker 数据(镜像层、容器、卷)。

📋 六、延伸与优化

🔢 6.1 磁盘空间管理

该方案天然附带了一个好处: 数据实例的 VHD 文件固定在指定路径 (本例为 D:\WSL\docker-desktop-data ),不会占用 C 盘空间。Docker 镜像和容器长期使用后可能累积几十 GB,将其固定在 D 盘是磁盘管理的有效手段。

可以通过以下命令查看 VHD 文件的实际大小:

#  查看 WSL 实例对应的 VHD 文件
Get-ChildItem -Path "D:\WSL\docker-desktop-data" -Recurse | Select-Object Name, Length

🔢 6.2 快速诊断命令速查

目的命令
查看 WSL 实例列表wsl --list --verbose
查看 Docker 容器docker ps -a
创建数据实例wsl --import docker-desktop-data <路径> <rootfs> --version 2
关闭所有 WSL 实例wsl --shutdown
终止单个实例wsl --terminate docker-desktop
备份数据实例wsl --export docker-desktop-data <备份路径.tar>
查看 VHD 文件位置在注册表 HKCU\Software\Microsoft\Windows\CurrentVersion\Lxss 中查找

🔢 6.3 类似问题的排查思路

日后遇到 Docker Desktop 在 WSL2 中的异常(容器丢失、启动报错、镜像拉取失败等),优先执行:

wsl --list --verbose

检查输出中是否同时存在 docker-desktopdocker-desktop-data 。如果 docker-desktop-data 缺失或状态异常,优先修复该实例。这是绝大多数 WSL2 + Docker Desktop 数据问题的首要排查点。

🔧 七、总结

本文讨论的问题根因是 Docker Desktop 在 WSL2 后端初始化时未能正确创建 docker-desktop-data 数据存储实例 ,导致镜像、容器、数据卷等持久化数据被写入 docker-desktop 守护进程实例的内部存储中。由于 docker-desktop 实例被设计为无状态(每次启动时重置),一旦执行 wsl --shutdown 或系统重启,所有临时写入的数据将被清除。

修复的核心思路是手动创建缺失的 docker-desktop-data WSL 实例,为 Docker Desktop 提供一个独立的持久化存储目标。该方案同时解决了数据持久性问题,并允许开发者将 Docker 数据固定到指定磁盘路径。

flowchart LR
    %% ==========================================
    %% 样式定义
    %% ==========================================

    ROOT[Docker Desktop\nWSL2 数据持久化]

    ROOT --> PROBLEM["问题:docker-desktop-data 缺失"]
    ROOT --> ROOT_CAUSE["根因:持久化数据无处存放\n写入 docker-desktop 内部临时存储"]
    ROOT --> SOLUTION["方案:手动创建\ndocker-desktop-data 实例"]
    ROOT --> VERIFY["验证:wsl --shutdown 后\n数据不再丢失"]

    PROBLEM --> SYMPTOM["症状\n• wsl --shutdown 后容器消失\n• docker ps -a 为空\n• 需反复重建容器"]
    ROOT_CAUSE --> MECHANISM["机制\n• docker-desktop:无状态守护进程\n• 数据写在内置临时路径\n• shutdown 触发实例重置"]
    SOLUTION --> STEPS["操作\n• wsl --import 创建实例\n• 指定 VHD 存放路径\n• 重启 Docker Desktop"]
    VERIFY --> RESULT["结果\n• 容器/镜像持久化\n• 数据固定在指定磁盘\n• 可定期备份导出"]
    style ROOT fill:#0f172a,stroke:#3b82f6,stroke-width:2px,color:#ffffff,font-weight:bold
    style PROBLEM fill:#2d1a05,stroke:#f59e0b,stroke-width:2px,color:#ffffff,font-weight:bold
    style ROOT_CAUSE fill:#2d1a05,stroke:#f59e0b,stroke-width:2px,color:#ffffff,font-weight:bold
    style SOLUTION fill:#2d1a05,stroke:#f59e0b,stroke-width:2px,color:#ffffff,font-weight:bold
    style VERIFY fill:#2d1a05,stroke:#f59e0b,stroke-width:2px,color:#ffffff,font-weight:bold
    style SYMPTOM fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style MECHANISM fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style STEPS fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#ffffff,font-weight:bold
    style RESULT fill:#052e16,stroke:#16a34a,stroke-width:1.5px,color:#ffffff,font-weight:bold
关键点说明
问题现象wsl --shutdown 后 Docker 容器、镜像、数据卷全部消失
直接根因docker-desktop-data WSL 实例缺失
与安装路径无关WSL 装在 C 盘还是 D 盘不是问题原因
修复方式使用 wsl --import 手动创建 docker-desktop-data 实例
附带好处数据 VHD 固定在指定路径,可节省 C 盘空间
日常排查遇到 Docker 问题先执行 wsl --list --verbose