Windowsでwsl2(Ubuntu)上のDockerに外部から接続する

# 環境

作業PC：Windows 10
リモートPC：Windows 10 + SQLServer + WSL2(Ubuntu 20.04LTS) + Docker
（同LAN上）

# やりたいこと

* WindowsのWSL2(Ubuntu)でDockerプロジェクトを起動し、そこに外部のPCからアクセスやSSH接続して作業したい。
* WSL2のDockerプロジェクトから、ホストPCのSQL Serverに接続する。

なぜこのようになったかの経緯としては、Windows上においたDockerのアクセスが毎度遅く、調べているうちにWindows⇔Linux間で変換がかかるとかなんだとかが原因で、Linux上にソースを配置すれば改善されるような記事を見つけたのがひとつと、作業PCとソース管理を分けることになったのが同時期だったので、同時進行で改善してみることに。

もっといい方法があるのかもしれませんが、不勉強で疎いです。
間違っている箇所もあるかもしれませんので、何かあればコメントを頂けると助かります。


# やったこと

* WSL2の有効化
* WSL2にUbuntuを導入し、Docker環境を構築
* 作業PCからUbuntu上のDockerプロジェクトへのアクセス（ポートフォーワード）
* 作業PCからリモート接続したPCへSSH接続
* 作業PCからリモートPC内WSL2,UbuntuへSSH接続

# 作業手順

## WSL2のインストール

WSLのインストールについては[Microsoftの記事](https://docs.microsoft.com/ja-jp/windows/wsl/install#manual-installation-steps)を読んだ方が早いです。

## WSL2にUbuntuをインストール

LinuxディストリビューションとしてUbuntuを選択します。
他のディストリビューションは試していないため、他を使用する場合は自己判断でお願いします。

Microsoft Storeで「Ubuntu 20.04LTS」を探してインストールします。
インストールが終わり起動するとコンソールが開き、Ubuntuのインストールが始まります。
usernameはリモートPCにアクセスするものと一緒にします。
（異なるものにしても問題ありませんが、別途同名ユーザを作成する必要があります）

インストールが終わったら、管理者権限でPowerShellを起動しWSLのバージョンを確認します。

```powershell:PowerShell
$ wsl -l -v
  NAME                   STATE           VERSION
  Ubuntu                 Running         1

# VERSIONが1になっている場合は2に変更します。
$ wsl --set-version Ubuntu 2
```

## UbuntuにDockerおよびdocker-composeをインストール

```shell:Ubuntu
# パッケージを更新する
sudo apt-get update
sudo apt-get upgrade

# Dockerのインストールに必要なパッケージをインストールする
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

# DockerのGPG鍵を登録する
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# DockerのPPAを登録する
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

# Dockerのインストール
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

# sudoなしでdockerコマンドを使えるようにする
sudo usermod -aG docker $USER

# ここまでで一旦シェルを抜けます
exit
```

再びシェルを起動

```shell:Ubuntu
# Dockerがインストールされたか確認
docker -v

# Dockerデーモンを起動
sudo service docker start

# 次のコマンドは、実行ファイルを/usr/local/bin/docker-composeに保存することで、
# このソフトウェアをdocker-composeとしてグローバルにアクセス可能にします。
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 次に、docker-composeコマンドが実行可能になるように、正しい権限を設定します。
sudo chmod +x /usr/local/bin/docker-compose

#インストールが成功したことを確認するには、以下を実行します。
docker-compose --version
```

リリースページで利用可能な最新バージョンは[こちら](https://github.com/docker/compose/releases)で確認できます。ここでは1.26.0を使用します。

## Ubuntu上にDockerプロジェクトを構築

「\\\\wsl$」にアクセスすることで、Explorer上からソースを閲覧することができます。
各自のやり方でプロジェクトをビルドしてください。
（権限問題が付きまとうのでrootユーザで作業した方がいいかも）

プロジェクトにはポート番号が割り振られているものとします。

## WSL2で起動したサーバーに外部の端末からアクセスする


####WSLとホストPCのipアドレスを確認
ローカルマシン(Windows)

```shell:cmd
ipconfig
```

wsl2(Ubuntu)

```shell:Ubuntu
ip addr show
# または
hostname -I
```

####ローカルマシンからwslのipアドレスを用いてアクセスできるか確認

* http://＜wslのipアドレス＞:＜ポート番号＞

アクセスできない場合はwsl内かWSLのイーサネットアダプター周りで問題が起きてる可能性があるらしいです。
私の環境ではプロキシ設定でエントリを追加する必要があったので追加します。


####ローカルマシンのipアドレスでwslのサーバーにアクセスできるようにポートフォワーディングの設定を行う

PowerShell（管理者権限）で以下コマンドを実行し、ポートフォーワードを設定します。

```powershell:PowerShell
# ローカルPCのポートXXXXに来たパケットをwsl2のポートXXXXに転送（XXXXはDockerで使用するポート番号）
netsh.exe interface portproxy add v4tov4 listenaddress=＜ローカルPCのIPアドレス＞ listenport=＜ポート番号＞ connectaddress=＜WSLのIPアドレス＞ connectport=＜ポート番号＞

# 設定を確認する場合
netsh.exe interface portproxy show v4tov4

# 設定を削除する場合
netsh.exe interface portproxy delete v4tov4 listenport=＜ポート番号＞ listenaddress=＜ローカルPCのIPアドレス＞
```

####ローカルマシンのipアドレスを用いてwslのサーバーにアクセスできるか確認

* http://＜ローカルマシンのipアドレス＞:＜ポート番号＞

これでアクセスできない場合は、ポートフォワーディングがうまくいっていない。
（WSLを再起動するとIPアドレスが変わってしまうのですが、設定したまま上書きしたところ設定は正しいのに接続できないことがあったので、リッスンするIP,ポート番号が同じ場合でも一度削除してから再設定した方がいいかもしれない）

####外部の端末からローカルマシンのipアドレスを用いてwslのサーバーにアクセスできるか確認
同一ネットワークに所属する外部端末を使ってアクセスできるか確認

* http://＜ローカルマシンのipアドレス＞:＜port＞

ここでアクセスできない場合はファイヤーウォールにブロックされてる可能性が高いのでファイヤーウォールの設定から、「詳細設定」に進み「受信の規制」に新しい規則を作ってportを開ける。
（後々必要になるので、22と1433もあけておく）


####PCを再起動するとWSLのIPアドレスが変わってしまう問題

自動で割り振るように設定するか、IPアドレスを固定化できるか。
また、sshとdockerサービスの起動も必要そう。何か対策を打てたら追記する。

（追記）
以下のPowerShellを実行する。自動で実行したい場合はタスクスケジューラ等を使用すればよい。

```powershell:PowerShell
#パスワードは手入力
#wsl -d Ubuntu-20.04 exec sudo service ssh restart
#wsl -d Ubuntu-20.04 exec sudo service docker start

#rootで実行
wsl -d Ubuntu-20.04 -u root exec sudo service ssh restart
wsl -d Ubuntu-20.04 -u root exec sudo service docker start

### WSLのIPアドレス取得（複数とれたので半角スペースで区切って1個目だけ）
$hostname = wsl -d Ubuntu-20.04 exec hostname -I
$IP,$dummy = $hostname.Split(" ")

### ホストPCのIPアドレス取得
$HostIP = (
    Get-NetIPConfiguration |
    Where-Object {
        $_.IPv4DefaultGateway -ne $null -and
        $_.NetAdapter.Status -ne "Disconnected"
    }
).IPv4Address.IPAddress

##########################
# ポートフォーワード設定 #
##########################
# 22だけ2022から繋ぐ（22はホストPC自体に接続したいので）
netsh interface portproxy add v4tov4 listenaddress=$HostIP listenport=2022 connectaddress=$wslIP connectport=22
$ports = @(1433, ほか)
$ports += 8080 # 別途追加
foreach($port in $ports){
	netsh interface portproxy delete v4tov4 listenaddress=＜リモートPCのIPアドレス＞ listenport=$port
	netsh interface portproxy add v4tov4 listenaddress=＜リモートPCのIPアドレス＞ listenport=$port connectaddress=$IP connectport=$port
}
```


## WSL2のsshサーバに外部PCから接続

####「OpenSSH サーバー」をインストール

以下のどちらかの手順でOpenSSH サーバーをインストール

* 設定 > Windows の設定 > アプリと機能 > オプション機能の管理 > 機能の追加
* PowerShell を 管理者モード で開き、次のコマンドを実行

```powershell:PowerShell
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
```

エラーが出て失敗する場合はローカルグループポリシーエディターの設定を確認する。

* PowerShellで「gpedit.ms」を実行。ローカルグループポリシーエディターが開く
* 「コンピューターの構成」→「管理用テンプレート」→「システム」と展開
* 「オプションコンポーネントのインストールおよびコンポーネントの修復のための設定を指定する」をダブルクリック
* ウインドウ左上の「有効」ラジオボタンをクリックし、左下の「Windows Server Update Service (WSUS) の代わりに、Windows Update から修復コンテンツとオプションの機能を直接ダウンロードする」にチェックを入れます。
* PowerShellで「gpupdate /force」を実行。
* 再度インストールを試行して成功すればOK。

####SSHサーバーの起動

```powershell:PowerShell
Start-Service sshd

# サービスを自動起動したい場合
Set-Service -Name sshd -StartupType 'Automatic'
```

## Ubuntuにssh接続する

```shell:Ubuntu
# openssh-serverが入ってなければインストールする（入ってるはず）
sudo apt install openssh-server
# パスワードでのログインを有効にしておく。（PasswordAuthentication yes）
sudo vi /etc/ssh/sshd_config
# RSAキーを作成
sudo ssh-keygen -A
# sshサービスを起動
sudo service ssh restart
```

```shell
# ローカルPCからSSH接続確認
ssh ＜ユーザ名＞@＜WSLのIPアドレス＞
```

※SSH接続の鍵設定などは省略します。参考にしたサイトを後述しますので、そちらを参考してください。

```shell
# 作業PCからSSH接続確認
ssh ＜ユーザ名＞@＜リモートPCのIPアドレス＞
```

## WSL（上のDocker）からSQL Serverに接続する。

「SQL Server 構成マネージャー」（C:\Windows\System32\SQLServerManager14.msc）で以下の設定を行う。

* SQL Serverネットワーク構成の「サーバー名」のプロトコルを選択
* TCP/IPが「無効」になっている場合は「有効」にする
* タブの「IPアドレス」を選択し、最後の「IPAII」のTCPポートに「1433」を設定
* 適用し、SQL Serverを再起動


（次の設定は、必要があったのかどうか今一わかりませんが念のため記述）

* WSL上で以下のコマンド編集をして、ネットワーク設定を変更する。


```shell:Ubuntu
sudo nano /etc/resolve.conf
```

```
nameserver 8.8.8.8
```
（Ctrl+o で保存して、 Ctrl+Xで閉じる。） 

* 同様に以下を編集

```shell:Ubuntu
sudo nano /etc/wsl.conf
```

```
[network]
generateResolvConf = false
```

* WSLを閉じて、再度開く

## Visual Studio Code から SSH接続する

これはおまけですが、作業PCで作業をするのだから個人的にやりたい。

* 拡張機能「Remote Development」をインストール
* ~/.ssh/configに以下を設定

```
Host RemotePC
  HostName ＜リモートPCのIPアドレス＞
  IdentityFile ~/.ssh/id_rsa
  User ＜ユーザ名＞
```

* VSCodeのリモートエクスプローラーで「SSH Targets」を選択し、上で設定した「RemotePC」を右クリックして作業ウィンドウを選択する。
* 対象のOSをきかれるので「Linux」を選択する。
* あとは作業したいフォルダを選択すればOK。

接続先は一見リモートPCですが、ポートフォーワードを設定しているため、WSL上のUbuntuへアクセスされます。

# 参考サイト
[WSL2 のDocker for Windowsで動作が重い時の原因と対処方法](https://qiita.com/BlueBaybridge/items/c1adcf1dab5da2b40b4f)
[WSLのインストール](https://docs.microsoft.com/ja-jp/windows/wsl/install#manual-installation-steps)
[WSL2内で立ち上げたサーバにWindows側からlocalhostで接続する](https://qiita.com/snaka/items/a8eee4cfc8f7d733e6ab)
[Ubuntu 20.04へのDocker Composeのインストールおよび使用方法](![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1474749/32cddc60-e48a-942f-7783-93f9ec83c06d.png)
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-20-04-ja)
[WSL2で起動したサーバーに外部の端末からアクセスする](https://gunmagisgeek.com/blog/other/7171)
[wsl2でsshサーバを起動し、外部からそこに接続](https://qiita.com/yabeenico/items/15532c703974dc40a7f5)
[SSH公開鍵認証で接続するまで](https://qiita.com/kazokmr/items/754169cfa996b24fcbf5)
[家の中で別PCにSSH接続して開発](https://www.lisz-works.com/entry/ssh-remote-dev-win2linux)
[[VSCode] Remote-SSH でサーバ上のファイルを直接編集する方法](https://webbibouroku.com/Blog/Article/vscode-remote-ssh)
[VS Codeでリモートサーバに接続する](https://create-it-myself.com/know-how/connect-remote-server-in-vscode/#i-3)
[Windows 10 に OpenSSH サーバをインストールする](https://qiita.com/iShinkai/items/a12c9d26f8f4264897f9)