1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker Desktopのvhdx移動に失敗してEngineが起動しなくなった話

1
Posted at

はじめに

今回の事象は私の環境で発生したものであり、すべての事象に当てはまるものではありません。

Windows の Docker Desktop(WSL2 バックエンド)を使っていたところ、仮想ディスク(vhdx)のサイズが 160GB を超えて C ドライブを圧迫してきました。そこで、Docker Desktop の設定画面から vhdx の保存先を D ドライブへ移動しようとしたところ、移動の途中でエラーになり、その後 Docker Engine が一切起動しなくなりました。

この記事では、状況から推測した原因と、実際に解決した方法を先に書き、そのあとで推測に至るまでに試したことを順に紹介します。

記事中のユーザー名・フォルダ名・コンテナ名などは、すべてダミー値に置き換えています。

環境

  • Windows 11
  • Docker Desktop 4.35.1(WSL2 バックエンド)→ 解決時に 4.95.0 へ更新
  • vhdx の保存先:C:\Users\<user>\AppData\Local\Docker\wsl → D:\DockerData

問題

やったこと

Docker Desktop の Settings → Resources → Advanced → Disk image location で保存先を D:\DockerData に変更し、「Apply & restart」を押しました。このとき、いくつかのコンテナが起動したままでした。

起きたこと

移動処理の途中で次のエラーが表示されました。

Docker Desktop - Settings not applied
An error occurred while applying the "Disk image location" setting. The previous value has been restored.

failed to unregister WSL docker-desktop distro: Illegal operation attempted on a registry key that has been marked for deletion.

「元の値に戻した」と表示されたものの、その後は Docker Desktop を再起動しても Windows を再起動しても、Docker Engine が起動しなくなりました。表示されるエラーは次のようなものです。

running engine: waiting for the VM setup to be ready: context canceled
running wsl-bootstrap: exit status 1

画面左下は「Engine starting」のまましばらく待たされ、最終的に「Engine stopped」になります。

解決方法

原因(推測)

ここに書くのは、ログと対処の結果から推測したものです。原因を特定・検証できたわけではありません。

ログから確認できた事実は次のとおりです。

  • vhdx ファイルの移動自体は完了しており、データは読み込めていた
  • VM 内の Docker Engine(dockerd)は、起動処理の完了をログに出していた
  • それにもかかわらず、Windows 側の Docker Desktop から、VM 内の Docker Engine に接続できず、時間切れで停止させられていた

この状況から、問題はデータ側ではなく、**Docker Desktop の「Windows 側と VM 内のエンジンをつなぐ部分」**にあるのではないかと推測しました。さらに、vhdx の移動処理がエラーで中断したことで、この接続に関わる Docker Desktop 側の内部状態が壊れたのではないか、と考えています。

ただし、壊れた箇所そのものは確認できていません。また、上書きインストールで解決したことは、この推測と矛盾しないというだけで、推測が正しいことの証明にはなりません。

対処:Docker Desktop を上書きインストールする

上書きインストールでは Docker Desktop のプログラム部分が入れ替わり、vhdx(イメージ・コンテナ・ボリューム)と設定は保持されます。今回は古いバージョンを使っていたので、最新版で上書きしました。

  1. Docker Desktop を完全に終了します。

    Get-Process *docker* | Stop-Process -Force
    wsl --shutdown
    
  2. 念のため、データ用の vhdx をバックアップします。

    robocopy D:\DockerData\disk D:\DockerBackup docker_data.vhdx
    
  3. Docker 公式サイトから最新のインストーラーをダウンロードし、実行します(「Use WSL 2 instead of Hyper-V」にチェックが入っていることを確認)。

  4. Docker Desktop を起動すると、「Engine running」になり、移動前のイメージやコンテナもそのまま表示されました。

「Reset to factory defaults」と、Troubleshoot 画面の「Clean / Purge data」は押さないでください。 イメージ・コンテナ・ボリュームがすべて削除されます。エラー画面に「Reset to factory defaults」のボタンが表示されますが、データを残したいならまず別の方法を試すべきです。

原因を推測するまでのアプローチ

ここからは、上記の推測に至るまでに試したことを順に紹介します。途中で立てた仮説のいくつかは外れていますが、切り分けの過程として残しておきます。

1. Windows の再起動

最初のエラーメッセージ(registry key that has been marked for deletion)は、WSL の内部状態が不整合になったときに出るもので、多くは再起動で解消します。しかし、再起動後も Docker Engine は起動しませんでした。

2. ファイルと設定の場所を確認する

「元の値に戻した」と表示されたので、ファイルと設定がどちらの場所を指しているかを確認しました。

# vhdx の実体の場所
dir /s "C:\Users\<user>\AppData\Local\Docker\wsl"
dir /s "D:\DockerData"

C ドライブ側は空で、D ドライブ側に disk\docker_data.vhdx(データ本体)と main\ext4.vhdx(docker-desktop 環境本体)がありました。つまり、ファイルの移動は完了していました。

# Docker Desktop の設定が指している場所
findstr /i "wsl" "%APPDATA%\Docker\settings-store.json"

"CustomWslDistroDir": "D:\\DockerData" となっており、設定も D ドライブを指していました。

# WSL に登録されている docker-desktop 環境の場所
Get-ChildItem HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss | Get-ItemProperty | Select-Object DistributionName, BasePath

# docker-desktop 環境が単体で起動できるか
wsl -d docker-desktop -e echo ok

WSL の登録も D ドライブを指しており、ok と表示されて単体で起動できました。ここまでで、ファイル・設定・WSL の登録はすべて整合していて、WSL 側も正常だと分かりました。

vhdx のサイズが移動前(約 166GB)と移動後(約 100GB)で違っていましたが、166GB は Docker が稼働中のときの値で、停止後は移動後と同じサイズだったため問題ありませんでした。

3. ログを確認する

Docker Desktop のログは %LOCALAPPDATA%\Docker\log 配下にあります。

ログ 内容
host\monitor.log Docker Desktop の監視役のログ。エラーダイアログの表示記録が中心で、原因の手がかりは少ない
host\com.docker.backend.exe.log Docker Desktop 本体(Windows 側)のログ
vm\dockerd.log VM 内の Docker Engine のログ
vm\init.log VM の起動処理のログ

まず VM 内の Docker Engine のログを見ました。

Get-Content "$env:LOCALAPPDATA\Docker\log\vm\dockerd.log" -Tail 30
level=info msg="Loading containers: done."
level=info msg="Docker daemon" ... version=27.3.1
level=info msg="Daemon has completed initialization"
context deadline exceeded

Docker Engine は起動処理を完了しています。 その直後に context deadline exceeded(時間切れ)が出ています。

次に、エンジン起動完了〜停止までの時間帯の、Windows 側のログを確認しました。

Select-String -Path "$env:LOCALAPPDATA\Docker\log\host\com.docker.backend.exe.log" -Pattern "\]\[E\]|still waiting|deadline|apiproxy" | Select-Object -Last 20
[lifecycle-server.apiproxy][W] Proxy error handling "/_ping": connecting to /run/guest-services/docker.sock: dial unix /run/guest-services/docker.sock: operation was canceled
[lifecycle-server.docker] wait for engine: still waiting for API to respond after 32s
[lifecycle-server.docker] wait for engine: still waiting for API to respond after 1m5s
[lifecycle-server.docker] wait for engine: still waiting for API to respond after 1m38s
[dockerd] context deadline exceeded
[lifecycle-server] dockerd exited

Windows 側の Docker Desktop が、エンジンの応答確認(/_ping)を送り続けているのに応答がなく、最終的にエンジンを停止していることが分かりました。ここで、**「エンジンは起動しているのに、Windows 側から接続できない」**という症状がはっきりしました。

ログを bootstrap|error のような広いパターンで検索すると、monitor.log の行ばかりが出てきて肝心の情報が埋もれます。ファイルを com.docker.backend.exe.log に絞り、still waiting や deadline で検索するのが効率的でした。

4. 仮説①:docker-desktop 環境の登録が壊れている → 外れ

最初のエラーは「docker-desktop 環境の登録解除に失敗した」でした。移動処理は「登録解除 → ファイル移動 → 再登録」の流れなので、登録情報が中途半端に残った可能性を考え、docker-desktop 環境だけを登録し直しました。

wsl --unregister docker-desktop

docker-desktop 環境の本体(ext4.vhdx)は Docker Desktop が起動時に自動で作り直すもので、イメージやコンテナのデータが入った docker_data.vhdx は別ファイルなので消えません(念のため事前にバックアップを取りました)。

環境は作り直されましたが、症状は変わりませんでした。

5. 仮説②:古いネットワーク情報が残っている → 外れ

dockerd のログに、起動のたびに次のような警告が繰り返し出ていました。

level=info msg="Removing stale sandbox ..."
level=warning msg="Error (Unable to complete atomic operation, key modified) deleting object [endpoint ...], retrying...."

移動時にコンテナが動いたまま強制停止されたため、古いネットワーク情報が残っていると考え、ネットワーク情報のファイル(local-kv.db)を退避して作り直させました。

データ用ディスクはエンジン起動中しか接続されないため、Docker Desktop を終了したうえで、wsl --mount で自分で接続して作業しました。

# 管理者の PowerShell で実行
wsl --mount --vhd "D:\DockerData\disk\docker_data.vhdx" --name dockerdata
# Ubuntu を root で使って退避(削除ではなく名前を変えるだけ)
wsl -d Ubuntu-22.04 -u root -e sh -c "mv /mnt/wsl/dockerdata/data/docker/network/files/local-kv.db /mnt/wsl/dockerdata/data/docker/network/files/local-kv.db.bak"
# 管理者の PowerShell で接続を解除(忘れると Docker Desktop がディスクを使えない)
wsl --unmount "D:\DockerData\disk\docker_data.vhdx"

Docker Desktop 起動中にデータ用ディスクの接続先を調べるには、wsl -d docker-desktop -e sh -c "mount | grep -iE 'docker|sd[a-z]'" が便利です。今回の環境では /mnt/docker-desktop-disk に接続され、Docker のデータは /mnt/docker-desktop-disk/data/docker にありました。find / でディスク全体を検索すると、イメージの中身まで調べて終わらなくなるので注意してください。

古いネットワーク情報の警告は消えましたが、やはり接続できませんでした。

自分で作成した Docker ネットワーク(docker compose が作るものを含む)の定義が消えるので、この方法を試す場合は注意してください。compose を使っていれば、あとで作り直せます。

6. 仮説③:移動時に動いていたコンテナの自動再起動 → 外れ

ネットワーク情報を作り直したあと、今度は移動時に動いていた 3 つのコンテナが、自動再起動(restart ポリシー unless-stopped)の際に「ネットワークが見つからない」と失敗し、その後片付けで dockerd が内部エラーを出していました。

level=error msg="failed to start container" container=<コンテナID> error="network <ネットワークID> not found"
level=error msg="An attempt to decrement a zero mount count" ...

これが原因で固まっている可能性を考え、5. と同じ方法でディスクを接続し、3 つのコンテナの hostconfig.json をバックアップしたうえで、自動再起動の設定を no に変更しました。

# Ubuntu に root で入って実行
cd /mnt/wsl/dockerdata/data/docker/containers
for id in <ID1> <ID2> <ID3>; do
  f=$(ls -d $id*)/hostconfig.json
  cp $f $f.bak
  sed -i 's/"RestartPolicy":{"Name":"unless-stopped"/"RestartPolicy":{"Name":"no"/' $f
done

その結果、dockerd のログはエラー・警告なしの完全に正常な状態になり、7 秒で起動完了しました。それでも Windows 側からは接続できませんでした。

7. 推測:データ側は正常に見えるので、問題は Docker Desktop 側ではないか

ここまでで、データ側(vhdx・ネットワーク情報・コンテナ設定)で見つかった異常はすべて解消し、dockerd のログもエラー・警告のない状態になりました。それでも接続できないことから、原因は**データではなく、Docker Desktop のプログラム側の「Windows 側と VM 内エンジンをつなぐ部分」**にあるのではないかと推測し、上書きインストールを試したところ解決しました。

最終的に効いたのは上書きインストールですが、4.〜6. の対処も同時に効いていた可能性は否定できません。同じ症状の方は、まず上書きインストールを試し、それでも直らなければ 4.〜6. を検討するのがよいと思います。

ハマりどころ

調査中に戸惑った点もまとめておきます。

  • wsl --shutdown を Docker Desktop 起動中に実行すると、Docker Desktop が自動で再起動しようとします。 「WSL distro terminated abruptly」というダイアログも出ます。WSL を止めたいときは、先に Docker Desktop と関連プロセス(タスクマネージャーの「Docker Desktop Backend」など)をすべて終了してください。
  • Restart を押していないのに、勝手にエンジンの起動・停止が始まることがあります。 Resource Saver(使っていない間エンジンを止め、docker コマンドなどの呼び出しがあると自動で起動する機能)が有効だと、VS Code や WSL 側のツールが Docker を呼び出すだけで起動が始まります。
  • 社内プロキシの認証ダイアログが繰り返し出ていましたが、今回の事象とは無関係だと考えています。 移動前の正常な頃から出ていたためです。入力を繰り返すと社内アカウントがロックされるおそれがあるので、閉じてかまいません。

おわりに

vhdx の移動は Docker Desktop の設定画面から簡単にできますが、移動処理が途中で失敗すると、データは無事なのに Docker Engine が起動しないという分かりにくい状態になることがあります。

今回の反省点は次の 2 つです。

  • vhdx を移動する前に、すべてのコンテナを停止しておく。 動いたまま移動すると、強制停止されたコンテナの残骸が残ります。
  • Docker Desktop を古いまま使わない。 今回は 2 年近く前のバージョンでした。

また、ログを読むと「エンジンは起動しているのに接続できない」のように、症状を一段細かく言い換えられます。エラーダイアログの文言だけで判断せず、dockerd.log と com.docker.backend.exe.log を突き合わせるのがおすすめです。

参考

JISOUのメンバー募集中!

プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてください!
▼▼▼
https://projisou.jp

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?