preloader
心得

Fix Docker Upgrade Bug and Recover Images and Containers | Docker Desktop 重裝後, Images 和 Containers 還原了,但 Container 無法啟動:WSL2 VHDX 與 Bind Mount 修復筆記

Fix Docker Upgrade Bug and Recover Images and Containers | Docker Desktop 重裝後, Images 和 Containers 還原了,但 Container 無法啟動:WSL2 VHDX 與 Bind Mount 修復筆記

摘要

Docker Desktop VHDX 還原後,如果 container 因 /run/desktop/.../docker-desktop-bind-mounts 錯誤無法啟動,不要直接 start 舊 container;用 docker compose up -d --force-recreate 重新建立 container,讓 Docker Desktop 重建 bind mount 映射。

背景

我移除 Docker Desktop 並重新安裝新版後,原本的 Docker images 和 containers 消失。幸好我有備份 Docker Desktop 使用的 WSL2 VHDX 檔案,例如 ext4.vhdxdocker_data.vhdx。 還原 VHDX 後,Docker Desktop 裡可以看到舊 container,但啟動某些 container 時出現 bind mount 錯誤。

遇到的錯誤訊息

OCI runtime create failed:
error mounting "/run/desktop/mnt/host/wsl/docker-desktop-bind-mounts/Ubuntu/<hash>"
to rootfs at "/tpe_input.kml":
not a directory:
Are you trying to mount a directory onto a file (or vice-versa)?
error mounting "/run/desktop/mnt/host/wsl/docker-desktop-bind-mounts/Ubuntu/<hash>"
to rootfs at "/etc/nginx/templates/includes/proxy_backend.conf.template":
not a directory

Docker Desktop 的資料大致分兩類:

Docker-managed data:

  • images
  • container metadata
  • volumes
  • layers

Host bind mounts:

  • WSL 資料夾
  • Windows 資料夾
  • 專案原始碼
  • nginx config 檔
  • PostgreSQL data folder

 

以我的案例:
PostgreSQL 資料: /home/me/test_db_for_xxx_system/data_folder

API 專案: /home/me/xxx_system_api

nginx config: /mnt/c/users/me/.../nginx/*.conf

 

真因分析

VHDX 還原讓 Docker 的 image 和 container metadata 回來了,但舊 container 記錄的 bind mount 內部映射路徑已經失效。
Docker Desktop 在 WSL2 backend 下會使用 /run/desktop/mnt/host/wsl/docker-desktop-bind-mounts/... 這類內部路徑來掛載 WSL/Windows 檔案。
重裝 Docker Desktop 或替換 VHDX 後,舊 container metadata 仍指向舊的 hash 路徑,導致 container init 階段 mount 失敗。

修復方向

不要直接 docker start 舊 container。 改用 docker compose up -d –force-recreate 重新建立 container。

原因:
重新 create container 會讓 Docker Desktop 重新產生 bind mount 映射。 只要 compose 掛回同一份 data folder,資料不會消失。

修復 DB container

sudo cp -a /home/me/test_db_for_xxx_system/data_folder /home/me/test_db_for_xxx_system/data_folder.backup.$(date +%Y%m%d_%H%M%S)

注意 ownership

DB data folder 可能長這樣:

drwx------ 19 999 me data_folder

這不一定是錯的。

999 很可能是 container 裡 DB 使用者的 UID。

不要隨便改成:

sudo chown -R me:me data_folder

否則 DB 反而可能起不來。

用原本 project name 重建

cd /home/me/test_db_for_xxx_system

docker compose -p xxx_system -f docker-compose.wsl2.yml up -d --force-recreate db

驗證

docker ps -a --filter name=xxx_system-db-1
docker logs --tail=100 xxx_system-db-1
docker exec -it xxx_system-db-1 pg_isready -U me -d xxx_services

正常訊號:

database system is ready to accept connections

以及:

accepting connections

 

修復 API 與 nginx container

cd "/mnt/c/users/me/docker_projects/nginx"

docker compose -f docker-compose.local.yml config -q

docker compose -f docker-compose.local.yml up -d --force-recreate xxx-system-api-current nginx

驗證 API

docker logs --tail=80 xxx-system-api-current

正常看到:

Server running on port 4000

驗證 nginx

docker exec nginx nginx -t

正常看到:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

驗證 proxy

curl -i http://localhost/api \
  -H 'content-type: application/json' \
  --data '{"query":"{ __typename }"}'

正常看到:

{"data":{"__typename":"QueryRoot"}}

再測:

curl -i http://localhost/api2 \
  -H 'content-type: application/json' \
  --data '{"query":"{ __typename }"}'

正常看到:

{"data":{"__typename":"QueryImportantRoot"}}

 

(這段很重要)不要做的事

docker compose down -v

除非你確定要刪 volume,否則不要用。

也不要刪:

/home/me/test_db_for_xxx_system/data_folder

也不要同時啟動兩個 DB container 掛同一份 data directory。

結論

這次問題不是 DB 資料壞掉,也不是 Docker image 完全遺失,而是 Docker Desktop 重裝與 VHDX 還原後,舊 container 的 bind mount internal mapping 失效。
解法不是直接 start 舊 container,而是用 Docker Compose 重新 create container,讓 Docker Desktop 重新建立 mount mapping,同時掛回原本的資料資料夾。
對有 bind mount 的 container,–force-recreate 比直接 Start 舊 container 更可靠。

附註

在進入修復過程前,我的 WSL 遇到錯誤訊息 Cannot start WSL: Wsl/Service/CreateInstance/CreateVm/MountVhd/HCS/ERROR_FILE_NOT_FOUND

我最後照連結裡的步驟,成功解決問題。

  1. 取得 wsl 程式的版本號。
wsl --version
  1. 下載 WSL2 對應版本號的 .msi installer 安裝檔案,網址是 https://github.com/microsoft/WSL/releases/tag/2.7.8

  2. .msi 安裝檔案按滑鼠右鍵,選擇 修復 (Repair),修復完成會有一些警示訊息, 我看過認為不重要,按 OK 按鈕即可,主要是講找不到當時的捷徑。最終成功修復,我的 Docker Desktop v4.79.0 也正常運作。