目的
Windows Server 2022のWSL2でUbuntuを起動し、外部PCからsshでログインしdocker containerのコントロールを行う。
状況
WSL2は思っていた以上に癖があるが、ネット上の情報をもとにやりたいことはできている。
ただし、WSL2側の設定でPort Forwardingを設定する必要があり、Ubuntuでportのbindを一度手放すと再度bindできない(エラーする)。なので、docker compose downして、再度up -dが通常のUbuntu環境のようにはできない。
これは不便。なので、これを解決する。
*Docker自体のインストールでもいろいろあったがここでは触れない。
*取り急ぎ解決はしたんだが、本当にこんな面倒なことしなければならないんだろうか?
*Docker for windowsは利用しない。
環境
- Windows 2022 Server (21H2 Build 20348.2031)
- Ubuntu 22.04.1 LTS
- Docker 24.0.5
前提
- WSL2がインストール済みである。
- DistributionとしてUbuntuがインストール済みである。
- sshd, docker daemonが自動起動設定済みである。
方針
できるだけWindowsにはログインすることなしに対応したい。
そのため、Ubuntuのスクリプトで対応する。
docker compose起動をラップする
docker compose upする前に、port forwarding設定を一度削除し、container起動後再設定する。
#!/bin/bash
export PATH="$PATH":/mnt/c/Windows/System32/
# WSL自身のIP addressは起動ごとに変わる可能性があるので取得する
IP=$(ip address show eth0 | awk '/inet / {print $2}' | awk -F / '{print $1}')
#
# ここに公開用ポートを列挙します
# 例: LISTENPORTS=(8080 8081)
# 例のように手動指定してもよいが、面倒なのでdocker-compose.ymlファイルのport:指定を自動で読み取る
# ports:の次の行を取得->最初の数字項目を取得->スペースで連結
LISTENPORTS=(`grep 'ports:' -A 2 ./docker-compose.yml | awk 'match($0, /([0-9]+)/,a){print a[1]}' | paste -s -d ' '`)
#-------------------------------------------------------------------------------------
# delete port forwarding
# port forwarding設定を削除しておかないとdocker composeで起動時に失敗します。謎仕様
echo '================================'
echo 'Delete port forwroding'
for port in "${LISTENPORTS[@]}"
do
netsh.exe interface portproxy delete v4tov4 listenport=$port
done
netsh.exe interface portproxy show all
#-------------------------------------------------------------------------------------
# Run docker container
echo '================================'
echo 'Start Docker Containers'
cd /home/username/docker_dir/
docker compose up -d
#-------------------------------------------------------------------------------------
# re-add port forwarding
echo '================================'
echo 'Re-add port forwroding'
for port in "${LISTENPORTS[@]}"
do
netsh.exe interface portproxy add v4tov4 listenport=$port connectaddress=$IP
done
netsh.exe interface portproxy show all
#-------------------------------------------------------------------------------------
# Check docker container
echo '================================'
echo 'Check Docker Containers'
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Networks}}\t{{.Ports}}\t{{.Image}}"
停止時(docker compose down)にport forwardingを止めたければ似た感じでどうぞ。
sshd
sshd自体はUbuntu起動時にsystemdで自動起動する設定にしてあるが、Ubuntu自体(WSL2)の再起動時には同じ問題がある。
こちらは、systemdのスクリプトをフックする。
ExecStartPre行の変更と、ExecStartPost行の追加。他はデフォルトのまま。
実行スクリプトは /usr/local/bin/へ置いた。
...
[Service]
EnvironmentFile=-/etc/default/ssh
#ExecStartPre=/usr/sbin/sshd -t
ExecStartPre=/usr/local/bin/sshd_ExecStartPre.sh
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecStartPost=/usr/local/bin/sshd_ExecStartPost.sh
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
...
#!/bin/bash
export PATH=$PATH:/mnt/c/Windows/System32/
#-------------------------------------------------------------------------------------
# delete port forwarding
PORT=22
netsh.exe interface portproxy delete v4tov4 listenport=$PORT
netsh.exe interface portproxy show all
# Original
/usr/sbin/sshd -t
#!/bin/bash
export PATH=$PATH:/mnt/c/Windows/System32/
# WSL自身のIP addressは起動ごとに変わる可能性があるので取得する
IP=$(ip address show eth0 | awk '/inet / {print $2}' | awk -F / '{print $1}')
#-------------------------------------------------------------------------------------
# re-add port forwarding
PORT=22
echo '================================'
echo 'Re-add port forwroding'
netsh.exe interface portproxy add v4tov4 listenport=$PORT connectaddress=$IP
netsh.exe interface portproxy show all
ちなみに動作確認はsystemdのログを確認する。
sudo journalctl -u ssh --since="yesterday"
おわり。