WSL2+Docker+VSCode(+GPU)でコンテナ開発環境を作る

皆さんはDocker使っていますか？
共有サーバをDockerで環境の切り分けをしているエンジニアや研究者も多いのではないでしょうか。
今回はそういうパターンとは少し違って、私用のWindows PCをDockerで切り分けて、ひとりで環境を使い分けられるようにしたお話です。

# 前提環境
- Windows 11 Home
- NVIDIA GeForce RTX 4060 Laptop GPU
- WSL2(インストール済み)
- NVIDIA Driver 546.12(Windowsにインストール済み)
- VSCode(Windowsにインストール済み)

# Docker Desktopのインストール
Windows側にDocker Desktopをインストールします。
[公式サイト(Windows Home版)](https://docs.docker.jp/docker-for-windows/install-windows-home.html)を参考に、インストーラをダウンロードしてインストールします。
(Windows Home以外の場合は[こちら](https://docs.docker.jp/docker-for-windows/install.html))

ダウンロードしたら、スタートメニューからDockerを立ち上げてセットアップを完了させます。

PowerShellで`wsl --list`で↓みたいになっていればOKです。
```
Linux 用 Windows サブシステム ディストリビューション:
Ubuntu (既定)
docker-desktop
docker-desktop-data
```

こうなっていない場合はもう一度スタートメニューからDockerを立ち上げましょう。

#### GPUをDockerに連携したい場合
WSL内で↓のコマンドを打ち込みます。([こちら](https://qiita.com/nabion/items/4c4d4d4119c8586cbd9e)を参考にしました。)
```shell:WSL bash
distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
      && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
      && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
            sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
            sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
```

```shell:WSL bash
sudo apt update
```

```shell:WSL bash
sudo apt install -y nvidia-container-toolkit
```

# コンテナの作成と起動

## GPU無しの場合

↓のdockerfileを任意のディレクトリに配置します。(同じ階層にdockerfile以外は何も置かないのを推奨)
```dockerfile:dockerfile
# 今回はUbuntu22.04をベースにします。
FROM ubuntu:22.04

# aptの更新やopenssh-serverのインストールをします。
RUN apt update
RUN apt upgrade --fix-missing -y
RUN apt install -y openssh-server

# SSH接続のための設定です。
# "password"のところを任意のパスワードへ変更してください。
RUN mkdir /var/run/sshd
RUN echo 'root:password' | chpasswd
RUN echo '\nPermitRootLogin yes' >> /etc/ssh/sshd_config

# runしたときにSSH接続を始められるようにします。
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
```
dockerfileを配置したディレクトリに移動して、↓コマンドでDocker imageを作ります。(`ssh:ubuntu22.04`のimage名の部分は任意のものに設定できます。)
```shell:Windows PowerShell / WSL bash
docker build -t ssh:ubuntu22.04 .
```

作ったimageをコンテナ化して起動します。(`ssh:ubuntu22.04`の部分は↑で設定したimage名にします。`ssh_ubuntu`のコンテナ名の部分とポート番号`10000`は任意のものに設定できます。)
```shell:Windows PowerShell / WSL bash
docker run --name ssh_ubuntu -d -p 10000:22 ssh:ubuntu22.04
```

↓のコマンドで作ったコンテナにSSHログイン出来たらOKです。(ポート番号`10000`の部分は↑で設定したものにします。)
```shell:Windows PowerShell / WSL bash
ssh root@127.0.0.1 -p 10000
```

## GPU有りの場合

↓のdockerfileを任意のディレクトリに配置します。(同じ階層にdockerfile以外は何も置かないのを推奨)
```dockerfile:dockerfile
# 今回はUbuntu22.04、CUDA12.1.0をベースにします。
FROM nvidia/cuda:12.1.0-base-ubuntu22.04

# aptの更新やopenssh-serverのインストールをします。
RUN apt update
RUN apt upgrade -y
RUN apt install -y openssh-server

# SSH接続のための設定です。
# "password"のところを任意のパスワードへ変更してください。
RUN mkdir /var/run/sshd
RUN echo 'root:password' | chpasswd
RUN echo '\nPermitRootLogin yes' >> /etc/ssh/sshd_config

# runしたときにSSH接続を始められるようにします。
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
```
dockerfileを配置したディレクトリに移動して、↓コマンドでDocker imageを作ります。(`ssh:ubuntu22.04-cuda12.1`のimage名の部分は任意のものに設定できます。)
```shell:Windows PowerShell / WSL bash
docker build -t ssh:ubuntu22.04-cuda12.1 .
```

作ったimageをコンテナ化して起動します。(`ssh:ubuntu22.04-cuda12.1`の部分は↑で設定したimage名にします。`ssh_ubuntu_cuda`のコンテナ名の部分とポート番号`10000`は任意のものに設定できます。)
```shell:Windows PowerShell / WSL bash
docker run --gpus all --name ssh_ubuntu_cuda -d -p 10000:22 ssh:ubuntu22.04-cuda12.1
```

↓のコマンドで作ったコンテナにSSHログイン出来たらOKです。(ポート番号`10000`の部分は↑で設定したものにします。)
```shell:Windows PowerShell / WSL bash
ssh root@127.0.0.1 -p 10000
```

この設定でコンテナを起動すれば、NVIDIA DriverやCUDAが整備された状態の環境を使うことができるようになります。

# VSCodeからコンテナにアクセス

Windows側のSSH configファイルに↓を追記します。(configファイルがない場合は作成しましょう。`ssh_ubuntu`の部分は任意の接続名に設定できます。ポート番号`10000`の部分は↑で設定したものにします。)
```sh:Windows $HOME\\.ssh\config
Host ssh_ubuntu
    HostName localhost
    User root
    Port 10000
```

VSCodeの拡張機能「Remote Development」をインストールします。

あとは一般的なリモートサーバへアクセスするときと同じ手順でコンテナへログインすることができるようになります。

これで開発環境の作成は完了です。
ここから先は、この環境を使ってそれぞれの仕事や研究、趣味を頑張りましょう。