エラーの内容
failed to register layer: symlink /usr/bin/python3 /usr/bin/python: operation not permitted
error pulling image configuration: failed to register layer
真夜中のこと。PythonやNodeのベースイメージをプルしようとしたところ、Dockerがこの謎めいたメッセージを残して途中で止まってしまいました。同じマシンで昨日は動いていたのに、という場合もあります。あるいはWindowsをクリーンインストールしたばかりで、いきなりこのエラーに遭遇したという場合もあるでしょう。どちらにしても、イメージのダウンロードは完了せず、それを参照するdocker buildもすべて失敗します。
根本原因
本質的な問題は次の点にあります。Dockerはイメージレイヤーを展開する際に、実際のファイルシステムのシンボリックリンクを作成しなければなりません。ところがWindowsのファイルシステムであるNTFSは、シンボリックリンクをサポートしていないか、WSL2セッションが持っていない管理者権限を必要とします。
このエラーが発生するシナリオは主に2つあります。
- プロジェクトが
/mnt/c/や/mnt/d/以下にある — WSL2はWindowsドライブを9Pプロトコルブリッジ経由でマウントします。このブリッジを通じたシンボリックリンクの作成はブロックされるか、不安定な動作になります。 - Dockerのdata-rootがWindowsのパスを指している — Dockerが
/mnt/c/Users/yourname/.dockerのような場所にイメージレイヤーを保存しており、そこにはLinuxのシンボリックリンクを作成できません。
どちらも根本原因は同じで、解決策も同じです。すべてをNTFSマウントから切り離し、WSL2のネイティブなext4ファイルシステム上に移動することです。
修正1: プロジェクトをWSL2ファイルシステムに移動する(最も手軽な修正)
/mnt/c/の中からdocker buildやdocker pullを実行していませんか?それが原因です。プロジェクトをLinuxのホームディレクトリにコピーしましょう。
# WSL2ターミナルの中から実行
cp -r /mnt/c/Users/yourname/projects/myapp ~/myapp
cd ~/myapp
docker build .
~/や/home/yourname/といったパスはWSL2の内部仮想ディスク(ext4.vhdx)上に存在します。完全なLinuxのセマンティクスが使えるため、シンボリックリンクも問題なく機能します。
これだけで、約80%のケースでエラーが解消されます。
修正2: DockerのData-Rootを確認して移動する
プロジェクトをLinuxファイルシステム上に置いていても、DockerがイメージレイヤーをWindowsドライブにF保存していると、まったく同じエラーが発生します。まずDockerがデータをどこに保存しているか確認しましょう。
docker info | grep 'Docker Root Dir'
出力が/mnt/c/...や/mnt/d/...を指していれば、保存先を変更する必要があります。
(Docker Desktopではなく)WSL2内のDocker Engineを使っている場合は、デーモンの設定ファイルを編集します。
sudo mkdir -p /etc/docker
sudo nano /etc/docker/daemon.json
data-rootを追加または更新します。
{
"data-root": "/home/yourname/.docker-data"
}
その後、Dockerを再起動します。
sudo systemctl restart docker
修正3: Docker Desktop — WSL2インテグレーション設定を確認する
WSL2バックエンドを使用するDocker Desktopは、独自の仮想ディスクを管理しています。よくある原因は、Docker Desktop自体の問題ではなく、WSL2ターミナルでWindowsマウントのパスからDockerコマンドを実行していることです。
Docker Desktop → 設定 → リソース → WSLインテグレーション を開き、使用しているWSL2ディストリビューション(Ubuntu、Debianなど)のインテグレーションを有効にしてください。
その後、WSL2の中でDockerのルートが仮想ディスク上にあることを確認します。
docker info | grep 'Docker Root Dir'
# 次のように表示されるはず: Docker Root Dir: /var/lib/docker
/var/lib/dockerと表示されていますか?data-rootに問題はありません — ビルドコンテキストが原因です。修正1の手順に従って~/に移動してください。
修正4: NTFSマウントでシンボリックリンクを有効にする(最終手段)
どうしても/mnt/c/から作業しなければならない場合は、NTFSのシンボリックリンクサポートを有効にする方法を試すことができます。ただし、これにはWindowsの開発者モードの有効化と、WSL2の設定変更が必要です。
まず、開発者モードを有効にします。設定 → システム → 開発者向け → 開発者モード → オン。
次に、WSL2ディストリビューション内の/etc/wsl.confを編集します。
sudo nano /etc/wsl.conf
[automount]
options = "metadata"
metadataオプションを指定することで、WSL2がNTFSボリューム上にLinuxのファイルメタデータ(シンボリックリンクを含む)を保存できるようになります。PowerShellからWSL2をシャットダウンして再起動します。
# PowerShell(管理者)で実行
wsl --shutdown
# その後、WSL2ターミナルを再度開く
NTFSマウント上でシンボリックリンクが機能するようになったかテストします。
cd /mnt/c/Users/yourname/
ln -s test_target test_link
ls -la test_link
ln -sが成功したら、Dockerのビルドを再試行してください。それでも失敗する場合は、Dockerのレイヤー展開が内部的に異なるコードパスを使用しているためです。修正1または修正2の方が確実です。
動作確認
修正が正しく適用されたか確認しましょう。まず壊れたイメージを削除してから、クリーンな状態でプルします。
# 途中までプルされた・壊れたイメージをまず削除
docker rmi python:3.11-slim 2>/dev/null || true
# 新たにプル
docker pull python:3.11-slim
シンボリックリンクのエラーが出なければ成功です。ついでにフルビルドも確認しておきましょう。
docker build --no-cache -t myapp:test .
docker run --rm myapp:test python3 --version
--no-cacheフラグを指定することで、Dockerはすべてのレイヤーを強制的に再展開します。これはまさに以前失敗していた操作です。
予防策
- DockerプロジェクトはDockerは
~/に置く —/mnt/c/には置かないようにしましょう。Dockerを使う際はWSL2のホームディレクトリをメインの作業場所として使います。必要であれば、Windows Explorerから\\wsl$\Ubuntu\home\yourname\経由でファイルを参照できます。 - WSL拡張機能付きのVS Codeを使う — Windowsから編集しながら、WSL2のファイルシステム内のファイルを透過的に扱えます。
data-rootにWindowsのマウントパスを設定しない — Dockerのストレージ場所を変更する場合は、常に/home/または/var/以下のパスを指定してください。
すべてに通じる鉄則があります。WSL2上のDockerは、すべてのものがLinux仮想ディスク上にある限り完璧に動作します。イメージレイヤーやビルドコンテキストがNTFSマウントに触れた瞬間、シンボリックリンクが壊れ、気がつけば深夜2時にデバッグしている羽目になります。

