WSL2のUbuntuでDocker compose upとport forwarding設定を同期させたい

# 目的
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が自動起動設定済みである。
  - 参考:[【WSL2】WSL2のUbuntuでsshdの自動起動を有効にする【Ubuntu】](https://qiita.com/tmiki/items/022242af3853cd8e7a6a)
  - 参考：[WSL2のポートフォワードを自動化する](https://zenn.dev/fate_shelled/scraps/f6252654277ca0)
  - 参考：[wsl2でsshサーバを起動し、外部からそこに接続](https://qiita.com/yabeenico/items/15532c703974dc40a7f5)

# 方針
できるだけWindowsにはログインすることなしに対応したい。
そのため、Ubuntuのスクリプトで対応する。

## docker compose起動をラップする
docker compose upする前に、port forwarding設定を一度削除し、container起動後再設定する。

```bash:dc_up.sh
#!/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/へ置いた。

```/etc/systemd/system/sshd.service
...

[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

...
```

```sshd_ExecStartPre.sh
#!/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
```

```sshd_ExecStartPost.sh
#!/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のログを確認する。
```bash
sudo journalctl -u ssh --since="yesterday"
```

おわり。