そのままの AUTOMATIC1111 版 stable-diffusion-webui を WSL2 + GPU 上のコンテナで動かす

# はじめに
せっかく手元にGPU環境があっても、あれも生成したい、これも生成したいというときに、Pythonやライブラリのバージョン、CUDAのバージョンの組み合わせで動く、動かないというのを考え出すと、気が滅入ってきますよね。

それじゃあ、WSL2ならWindows側のGPUにアクセスできるんだから、コンテナ化して動かせばいいじゃんと考えるのはもっともな話だと思います。例えば、AUTOMATIC1111版 stable-diffusion-webui もforkした上で WSL2 + GPU 上で動作するような変更を加えたバージョンを公開している方もいらっしゃいます。

ここでは、誰かが変更してくれたバージョンではなく、そのままの AUTOMATIC1111 版 stable-diffusion-webui をWSL2 + GPU上のコンテナで動かす方法をご紹介します。Stable Diffusion以外にも応用できるかと思います。

# 用意しておくもの
## 動作環境
本記事を執筆する際には、以下の環境を用意して実行しています。
- Windows 11 Pro 23H2 (22631.4169)
- Windows Subsystem for Linux (5.10.102.1)
- [Ubuntu](https://www.microsoft.com/store/productId/9PDXGNCFSCZV?ocid=pdpshare) (Linux 5.15.153.1-microsoft-standard-WSL2 x86_64)
- Docker Desktop Personal for Windows - AMD64 (v4.34.2)
- NVIDIA GeForce RTX 4060 Laptop GPU
- [Visual Studio Code](https://apps.microsoft.com/store/detail/XP9KHM4BK9FZ7Q?ocid=pdpshare) (1.93.1)
  - Remote Development Plugin (WSL, DevContainers)

## DockerとUbuntu on WSL2の連携
Ubuntu上でDocker for Windowsを利用できるように、Docker DesktopのSettings→Resources→WSL integrationで、Enable integration with additional distrosでUb-untuを指定しておきます(特にこれから試してみようとするディストリビューションがWSL2のデフォルトディストリビューションではない場合)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/2d280b15-6303-3894-80fe-7dc96d0eadf7.png)

正しく設定されていれば、Ubuntuターミナルで`docker --version`を実行できるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/6af92094-7601-7528-45f0-5067f1f4f087.png)

## NVIDIA Container Toolkitのインストール
WSL2はそのままで(CUDA等を介して)Windows側のGPUを利用できるものの、WSL2上で動作するDockerコンテナはそのままではWindows側のGPUを利用できないので、NVIDIA Container Toolkitをインストールします。

WSL2上でUbuntuを実行しているのであれば、[公式インストールガイド](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)の[Installing with Apt](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)をそのまま実行するだけです。

つまり、
1.NVIDIA Container Toolkitのコンテナリポジトリを登録する。
```shell:
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/stable/deb/nvidia-container-toolkit.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
```
2.Ubuntuのパッケージリストを更新する。
```shell:
sudo apt-get update
```
3.NVIDIA Container Toolkitパッケージをインストールする。
```shell:
sudo apt-get install -y nvidia-container-toolkit
```
これで、dockerコマンドに`--gpus all`を指定できるようになりました。正しく動作している(Windows側のGPUにコンテナからアクセスできている)かどうかは、nvidia-smiをコンテナ上で実行することで確認可能です。
```shell:
docker run --rm --gpus all nvidia/cuda:12.3.2-base-ubuntu22.04 nvidia-smi
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/0a644a38-03f4-fd60-5d2e-d66552a79462.png)

## git clone, 設定ファイル(devcontainer.json, Dockerfile)作成, そして起動
WSL２上のUbuntuで stable-diffusion-webui のコードを git clone してローカル環境に持ってきます。

```shell
git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
```

持ってこれたら、ディレクトリを移動して、vscode を起動します。
```shell
cd stable-diffusion-webui
code .
```

コンテナ内の開発環境でStable Diffusionを実行するために、`.devcontainer`ディレクトリを作成し、その中に2つの設定ファイルをそれぞれ用意します。
### .devcontainer/devcontainer.json
devcontainer.jsonでは、基本的なコンテナの設定はDockerfileに逃がしておきます。ただし、GPUをコンテナから使用できるように、前のほうで nvidia-smi コマンドをコンテナから実行した際と同様に、dockerコマンドに引数 `--gpus all` が渡されるようにしておきます。
```json:devcontainer.json
{
	"name": "Python 3",
	"dockerFile": "./Dockerfile",
	"runArgs": [
		"--gpus", "all",
		"--shm-size", "8gb"
	]
}
```

### .devcontainer/Dockerfile
次にDockerfileですが、stable-diffusion-webuiの[README.md](https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/master/README.md)中のAutomatic Installation on Linuxには動作環境や必要な設定が挙げられているので、これらを反映させます。
- 依存関係のあるライブラリ
`sudo apt install wget git python3 python3-venv libgl1 libglib2.0-0`
- Pythonのライブラリ
  python3.11 または python3.10

なお、MS謹製のpythonイメージをここで指定しているのは、コンテナユーザーを(rootではなく)vscodeにしたいからです。

```Dockerfile:Dockerfile
FROM mcr.microsoft.com/devcontainers/python:1-3.10-bullseye
RUN apt-get update && \
    apt-get install -y wget git python3 python3-venv libgl1 libglib2.0-0
RUN pip install --upgrade pip
```

### 起動
さて、devcontainer.json ファイルと Dockerfile が用意できたので、このディレクトリを開発コンテナとして開いてみます。

![スクリーンショット 2024-09-18 150209.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/5e20e11b-e2a9-8e2c-5edf-ebabe08cfa99.png)

次に、ターミナルから `pip install -r requirement.txt` で依存関係のあるPythonライブラリを取得した後、`./webui.sh`を実行します。
![スクリーンショット 2024-09-18 150949.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/6770eb35-679c-8a7d-a771-7bd50215217e.png)

すると、ブラウザが起動し、http://127.0.0.1:7860/ が読み込まれていますので、プロンプトを適当に指定してやれば(画面の例は、Impressionist landscape of a Japanese garden in autumn, with a bridge over a koi pond)、ローカルWSL2環境に特定バージョンのPythonやCUDAをインストールすることなく、stable-diffusion-webuiをインストール、起動することができました。

# おわりに
ご紹介させていただいた
- .devcontainer/devcontainer.json
- .devcontainer/Dockerfile

を使いまわせば(求められるPythonのバージョンに合わせてDockerfile中のイメージは変える必要はあるにせよ)、GPUを活用するさまざまなアプリケーションを実行できそうです。