リモートマシンのWSLにOpenSSHサーバとDockerを入れてVSCodeからリモートアクセスできるようにする

前回、Windows側のOpenSSHサーバを利用してリモートマシンの環境構築をしたことにより、VSCodeの拡張機能経由でコンテナにアタッチすることができました。
ただし、一部の機能が使えなく不便であったため、今度はWSL上でSSHサーバを動かして接続する方法に挑戦してみることにしました。

環境

ホスト

  • OS: Windows 10 Home 21H1
  • VSCode: 1.65.2

リモート

  • OS: Windows 10 Pro 21H2
  • WSLディストリビューション: Ubuntu 20.04.3 LTS (Focal Fossa)
  • ホスト名: DESKTOP-27AIHDU
  • ログインユーザ: dev

設定方法

前回の状態から設定していきます。

Windows側のSSHサーバを停止する

「サービス」から「OpenSSH SSH Server」を探し、ダブルクリックしてプロパティウィンドウを開きます。
「停止」をクリックし、更にスタートアップの種類を「無効」に設定します。

後述しますが、この段階でpingが通るかやポート開放の状態、WSLのバージョンの確認をした方が良かったなと思いました。

WindowsからDocker Desktopを削除する

スタートを右クリックして「設定」ウィンドウを開き、「アプリ」→「アプリと機能」からアンインストールします。

WSLにOpenSSHサーバがインストールされているか確認する

WSLをインストールした時点で、OpenSSHサーバは既に入っているようです。
サービスは停止した状態なので、下記コマンドで起動します。

> sudo service ssh restart

WSLにDockerをインストールする

公式ドキュメントにある通りに進めます。

Dockerリポジトリを設定する

> sudo apt install ca-certificates curl gnupg lsb-release
> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
> echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

DockerEngineをインストールする

> sudo apt install docker-ce docker-ce-cli containerd.io

root以外のユーザーで実行できるようにする

下記コマンドまで実行出来たら、一度PCを再起動しておきます。

> sudo groupadd docker
> sudo usermod -aG docker $USER

サービスを起動する

下記のコマンドでサービスを起動します。

> sudo service docker start

WSL2へ切り替える

通常ではこれで問題ないはずなのですが、私の環境では何度実行しても起動ができませんでした。
/var/log/docker.logにあるログを確認すると、以下のようなエラーが出力されていました。(一部抜粋)

 Err :connection error: desc = \"transport: Error while dialing dial unix:///var/run/docker/containerd/containerd.sock: timeout\". Reconnecting..." module=grpc
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: iptables failed: iptables -t nat -N DOCKER: iptables v1.8.4 (legacy): can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.
 (exit status 3)

このエラーをもとに調べてみると、WSL2で実行していないため発生しているようでした。
どうやらWSLを有効化し、Microsoft StoreからUbuntuをインストールしただけではWSL2に切り替わらないようです。
下記のコマンドを実行して、WSL2を使うよう手動で設定する必要がありました。

> wsl --set-default-version 2
> wsl --set-version Ubuntu-20.04 2

この設定の後、サービスを無事起動させることができました。

SSHサーバの設定を変更する

/etc/ssh/sshd_confignanoコマンドなどで開き、下記の設定をアンコメントアウトで有効化します。

  • AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
  • PubkeyAuthentication yes

WSLに公開鍵を登録する

前回ホストマシンで公開鍵と秘密鍵を作成してあるので、それを利用します。
ホストマシンへは登録済なので、今回はWSLに公開鍵を配置するだけです。
ユーザディレクトリに.sshディレクトリを作成し、公開鍵をauthorized_keysにリネームして配置します。
WSLのディレクトリには、エクスプローラーのアドレスバーに\\wsl$を指定することでWindows側からアクセスできます。

起動設定をタスクスケジューラに登録する

PowerShellスクリプトを作成し、Windowsのタスクスケジューラに登録することで、PCの起動時に自動でスクリプトを実行できます。

PowerShellスクリプトの拡張子はps1で保存します。
スクリプトの保存先は任意です。今回はユーザディレクトリ直下C:\Users\devに配置します。

タスクスケジューラは、スタートを右クリックして「コンピューターの管理」ウィンドウを開き、「コンピューターの管理(ローカル)」→「システムツール」→「タスクスケジューラ」で開くことができます。

タスクを登録するには、タスクスケジューラ→「タスクの作成」で「タスクの作成」ウィンドウを開き、主に「全般」「トリガー」「操作」タブに設定していきます。

SSHサーバの自動起動設定

下記の通り設定します。

スクリプトの内容

wsl -u root -- service ssh restart

全般タブ

  • 名前
    • 任意の名前を設定する
    • 例:WSL2 SSH Service Restart
  • セキュリティオプション
    • 「ユーザーがログオンしているときのみ実行する」を選択
  • 構成
    • 「Windows10」を選択

トリガータブ

「新規」から「新しいトリガー」ウィンドウを開きます。

  • タスクの開始
    • 「ログオン時」を選択
  • 設定
    • 「特定のユーザー」を選択

操作タブ

「新規」から「新しい操作」ウィンドウを開きます。

  • 操作
    • 「プログラムの開始」を選択
  • 設定
    • プログラム/スクリプト
      • PowerShellの実行ファイルのパスを指定する
      • C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    • 引数の追加(オプション)
      • 任意のディレクトリに配置したスクリプトのパスを指定する
      • ExecutionPolicy Bypassでスクリプトの実行がブロックされないように実行ポリシーを指定する
      • -ExecutionPolicy Bypass "C:\Users\dev\restart_wsl_ssh_service.ps1"

ポートフォワーディングの自動設定

Windows側のポート22をWSLにポートフォワーディングします。
下記の通り設定します。

スクリプトの内容

$IP = (wsl -d Ubuntu-20.04 exec hostname -I).Split(" ")[0]
netsh.exe interface portproxy delete v4tov4 listenport=22
netsh.exe interface portproxy add    v4tov4 listenport=22 connectaddress=$IP

全般タブ

  • 名前
    • 例:SSH port foward to WSL2
  • セキュリティオプション
    • 「ユーザーがログオンしているかどうかにかかわらず実行する」を選択
    • 「最上位の特権で実行する」にチェックを入れる

トリガータブ

  • タスクの開始
    • スタートアップ時

操作タブ

  • 操作
    • プログラムの開始
  • 設定
    • プログラム/スクリプト
      • C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    • 引数の追加(オプション)
      • -ExecutionPolicy Bypass "C:\Users\dev\portfoward_wsl.ps1"

Dockerの自動起動設定

下記の通り設定します。

スクリプトの内容

wsl -u root -- service docker start

全般タブ

  • 名前
    • 例:WSL2 Docker Service Start
  • セキュリティオプション
    • 「ユーザーがログオンしているときのみ実行する」を選択
  • 構成
    • 「Windows10」を選択

トリガータブ

  • タスクの開始
    • ログオン時
  • 設定
    • 特定のユーザー

操作タブ

  • 操作
    • プログラムの開始
  • 設定
    • プログラム/スクリプト
      • C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    • 引数の追加(オプション)
      • -ExecutionPolicy Bypass "C:\Users\dev\start_wsl_docker_service.ps1"

ポートの設定を変更する

ここまで設定すればリモート接続が可能になるのですが、ポート開放などをしていなかったのでWindowsファイアウォールの設定を変更します。

スタートを右クリックして「設定」ウィンドウを開き、「更新とセキュリティ」→「Windowsセキュリティ」→「ファイアウォールとネットワーク保護」で「Windowsセキュリティ」ウィンドウを開きます。
更に「詳細設定」から「セキュリティが強化されたWindows Defenderファイアウォール」ウィンドウを開きます。

pingが通るように設定する

「受信の規則」に表示される一覧から、下記の条件の項目を探します。

  • 名前:ファイルとプリンターの共有(エコー要求 - ICMPv4受信)
  • グループ:ファイルとプリンターの共有
  • プロファイル:プライベート, パブリック

項目を見つけたら右クリック→「規則を有効化」を選択して、有効化します。
同様に「送信の規則」からも同じ項目を探して、有効化します。

SSH接続ができるようポートを開放する

受信の規則と送信の規則を新たに作成することで、ポート開放ができます。

「受信の規則」→「新しい規則」から、「新規の受信の規則ウィザード」ウィンドウを開きます。
下記のように設定します。
送信の規則についても同様に設定します。

  • 規則の種類
    • 「ポート」
  • プロトコルおよびポート
    • 「TCP」を選択
    • 「特定のローカルポート」に22を入力
  • 操作
    • 「接続を許可する」を選択
  • プロトコル
    • そのままの設定にしておく
  • 名前
    • 任意の名前を設定する

VSCodeからリモート接続する

前回では「Remote-Containers」拡張機能でコンテナの一覧を表示できませんでしたが、ここまで設定したことにより無事表示されるようになりました。

また、コンテナにアタッチしてコンテナの中にアクセスすることもできました。

開発環境を作成してみる

Remote-Containersでは、コマンドパレットから「Remote-Containers: Try a Development Container Sample…」を選択することで開発用コンテナを作成することができます。
しかしコンテナを構築中にエラーが発生してしまい、このコマンドからのコンテナ構築はできませんでした。

この問題は、必要なファイル群を手動で配置してからフォルダをVSCodeで開く事で回避できました。
具体的には、GitHub(Node.jsの場合)で公開されているリポジトリの.devcontainerフォルダをプロジェクトフォルダとなるフォルダにコピーして配置し、このプロジェクトフォルダをVSCodeで開くことでコンテナを構築できます。

(2022/04/03追記) 開発用コンテナの構築方法と使い方は、改めて下記にまとめました。
Node.jsの開発環境をDockerコンテナに構築する - てのひら

参考