はじめに
Docker for Windows と VSCode のリモートコンテナ拡張機能を利用した開発体験はとても素晴らしく、Windows 環境を汚さず開発チーム内で同じ開発環境を瞬時に用意できます。
ただし、Docker for Desktop をやめ、WSL2 上の Ubuntu で実行しているコンテナにアタッチしてデバックするには少しだけ準備が必要です。
この記事では次の2つの方法について説明します。
- WSL2 上で VSCode を起動し WSL2 から改めて Docker コンテナにアタッチする
- Windows で VSCode を起動し、WSL2 上の Docker コンテナにアタッチする
記事を寝かしていたら、Rancher Desktop が出て来て、SSH の設定も個別の docker のインストールもいらないし、あれ?もうあっちじゃいんじゃね?ってなったけれど。せっかくなので放流します。
WSL2 上で VSCode を起動し WSL2 から改めて Docker コンテナにアタッチする
VSCode のコマンドパレットから、Rmote-WSL: New WSL Window
コマンドを実行すると、Windows 側に新しい VSCode が起動し WSL2 上の Ubuntu にリモートで接続します。WSL2 側で code
と入力してもよいですね。
Windows 側の VSCode の拡張機能と Ubuntu 側の拡張機能はそれぞれ異なるものとして管理されているので、Ubuntu 側の VSCode にもリモートコンテナ拡張機能をインストールしてあげれば、Windows と同じように Ubuntu 上で実行している Docker に対し VSCode からコンテナにアタッチして開発することができます。
VSCode の左下には接続先が表示されています。Ubuntu に接続してそのうえで実行中のコンテナの一覧が表示されることと、Docker のコンテナとして動いている.NET 6.0 のコンテナに接続していることが分かります。
特に Windows 上からの操作にこだわらなければ、この方法がお手軽で良いですね。
Windows で VSCode を起動し、WSL2 上の Docker コンテナにアタッチする
Windows 上の VSCode から直に Docker コンテナにアタッチするのはちょっと手順が複雑です。
VSCode のリモートコンテナ拡張機能は、ローカルの docker context の内容を元に接続先の Docker ホストを解決しています。なので、SSH 経由で Ubuntu 上で動作している Docker に接続できるようにした後に、Windows 上に docker コマンドを用意して docker context を作成します。
Windows で利用できる docker コマンドをダウンロードする
Windows で利用できる docker コマンドのバイナリは下記のサイトで配布されています。
ZIP ファイルをダウンロードして展開し、パスを通します。
スクリプトでやるならこんな感じでしょうか。c:\tools\docker
配下に展開されます。
❯ Invoke-WebRequest -Uri "https://download.docker.com/win/static/stable/x86_64/docker-20.10.11.zip" -Outfile ".\docker-20.10.11.zip"
❯ Expand-Archive -Path ".\docker-20.10.11.zip" -DestinationPath c:\tools
❯ [Environment]::SetEnvironmentVariable("Path", $env:Path + ";c:\tools\docker", "User")
docker コマンドが使えるようになりましたが、接続先が無いのでこんな感じでエラーになります。
❯ docker ps
error during connect: This error may indicate that the docker daemon is not running.: Get "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/containers/json": open //./pipe/docker_engine: The system cannot find the file specified.
Windows から WSL2 の Ubuntu に SSH できるようにする
WSL2 上の Ubuntu に Windows から公開鍵で SSH 接続できるようにします。
SSH の設定は次の記事がとても分かりやすかったです。
Windows から Ubuntu に SSH 接続できることを確認したら、Windows 側の ~/.ssh/config に WSL2 の Ubuntu への接続情報を定義します。WSL2 では Windows からローカルの WSL2 のサーバーに SSH する場合は localhost で接続できるので、IP アドレスを調べるなどの手間がなくなってだいぶ楽になりましたね。
Host wsl
HostName localhost
IdentityFile ~/.ssh/WSLのユーザー名
User WSLのユーザー名
TCPKeepAlive yes
Windows 側から接続できるか確認します。
❯ ssh wsl
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.10.60.1-microsoft-standard-WSL2 x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
... 略 ...
$
WSL2 上の ssh の自動起動
不完全ではありますが WSL2 で Docker のデーモンを自動起動するのと同じ方法で、SSH のデーモンも自動起動するようにします。
visudo で service ssh start のパスワード入力を不要にして、
$ sudo visudo
# includedir /etc/sudoers.d
WSLのユーザー名 ALL=NOPASSWD: /usr/sbin/service docker start, /usr/sbin/service ssh start
~/.bashrc
でユーザーが Ubuntu にログインしたときに ssh が起動していなかったら起動するスクリプトを仕込みます。
... 略 ...
if [ $(service ssh status | awk '{print $4}') = "not" ]; then
sudo service ssh start > /dev/null
fi
... 略 ...
一度 wsl を停止し、ログイン後に ssh が起動していれば OK です。
❯ wsl --shutdown
❯ bash
$ service ssh status
* sshd is running
Windows 側で docker コマンドの向け先を WSL2 の Docker にする
SSH 経由で WSL2 に接続する Docker のコンテキストを作成し有効にします。
❯ docker context create wsl --docker "host=ssh://wsl"
wsl
Successfully created context "wsl"
❯ docker context use wsl
wsl
Current context is now "wsl"
Windows 側で docker コマンドが使えるようになります。
❯ docker info
Client:
Context: wsl
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Docker Buildx (Docker Inc., v0.7.1-docker)
compose: Docker Compose (Docker Inc., v2.2.2)
scan: Docker Scan (Docker Inc., 0.9.0)
Server:
... 略 ...
Kernel Version: 5.10.60.1-microsoft-standard-WSL2
Operating System: Ubuntu 20.04.3 LTS
OSType: linux
... 略 ...
もちろん docker の他のコマンドも使えます。
❯ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ea5cfe4ebac6 portainer/portainer-ce:2.11.0 "/portainer" 13 days ago Up 3 hours 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp, 9000/tcp portainer
❯ docker run --rm -it ubuntu
root@7e55bc2db5b5:/#
ただ、ボリュームマウントするときは注意が必要です。あくまで WSL2 側の Docker を Windows 側から触っているだけなので、ボリュームマウントを行う場合は、WSL2 側から見たパスを指定する必要があります。
❯ docker run --rm -it -v C:\Temp\html\:/html ubuntu
docker: Error response from daemon: invalid mode: /html.
See 'docker run --help'
❯ docker run --rm -it -v /mnt/c/Temp/html/:/html ubuntu
root@992079578b12:/# ls /html
index.html
Windows 側の VSCode から WSL2 上で動いている Docker コンテナに接続する
VSCode の コマンドパレットで Remote-Containers: Attach to Running Container
コマンドを実行すれば、次のようにコンテナの一覧が表示されるはずです。接続したいコンテナを選択して接続してみましょう。
おわりに
一度 WSL2 に接続した後に Docker コマンドを利用するのに比べ、Windows から直に Docker コマンドを実行するのは少し手順が複雑になります。
ボリュームマウントのパスの解釈が Windows と Ubuntu で異なるため使いにくかったり、一度 Ubuntu にログインしないと docker が起動しなかったりと少しハマりポイントも残っています。
ただ、一度設定してしまえば慣れた Windows 上で操作できるのはうれしいですね。