WSL2のDockerでUbuntu24.04とCUDA12.4の環境を整備

今年Ubuntu24.04がリリースされてしばらくたったので、WSLの環境も24.04にアップデートしようとしたらバグったのでそれを修復した方法を記録します。

今回はdockerfileでWSL2上にUbuntu24.04、CUDA12.4.1のコンテナを作成します。
なお、WindowsへNVIDIA Driverはインストール済みとします。

# dockerfile

まずはベースとしてUbunu24.04を読み込んで、aptの更新をします。
```dockerfile
FROM ubuntu:24.04

# aptの更新など
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y wget
```

次にCUDA12.4.1をインストールします。
[公式サイト](https://developer.nvidia.com/cuda-12-4-1-download-archive?target_os=Linux&target_arch=x86_64&Distribution=WSL-Ubuntu&target_version=2.0&target_type=deb_network)を参考にインストーラの場所やコマンドを記述します。
別バージョンのCUDAをインストールするときはそれに対応した記述に変えましょう。

```dockerfile
# CUDAのインストール
RUN wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb
RUN dpkg -i cuda-keyring_1.1-1_all.deb
RUN apt-get update
RUN apt-get -y install cuda-toolkit-12-4
RUN rm cuda-keyring_1.1-1_all.deb
RUN echo "export PATH=/usr/local/cuda-12.4/bin\${PATH:+:\${PATH}}" >> /root/.bashrc
RUN echo "export LD_LIBRARY_PATH=/usr/local/cuda-12.4/lib64:\${LD_LIBRARY_PATH:+:\${LD_LIBRARY_PATH}}\n"  >> /root/.bashrc
```

ここで、Ubuntu23.04以降のバージョンであるとこれではエラーとなります。
どうやら23.04以降ではlibtinfo5のインストールが未対応だそうです。
そこで下記にように変更します。

```dockerfile
# CUDAのインストール
RUN wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb
RUN dpkg -i cuda-keyring_1.1-1_all.deb
# ↓Ubuntu23.04以降でCUDAのインストールに必要なコマンド
RUN echo "deb http://archive.ubuntu.com/ubuntu/ jammy universe" >> /etc/apt/sources.list.d/jammy.list
RUN echo "Package: *\n\
    Pin: release n=jammy\n\
    Pin-Priority: -10\n\n\
    Package: libtinfo5\n\
    Pin: release n=jammy\n\
    Pin-Priority: 990" >> /etc/apt/preferences.d/pin-jammy
# ↑Ubuntu23.04以降でCUDAのインストールに必要なコマンド
RUN apt-get update
RUN apt-get -y install cuda-toolkit-12-4
RUN rm cuda-keyring_1.1-1_all.deb
RUN echo "export PATH=/usr/local/cuda-12.4/bin\${PATH:+:\${PATH}}" >> /root/.bashrc
RUN echo "export LD_LIBRARY_PATH=/usr/local/cuda-12.4/lib64:\${LD_LIBRARY_PATH:+:\${LD_LIBRARY_PATH}}\n"  >> /root/.bashrc
```

dockerfile全体は以下で例えば`cuda_ubuntu`というファイル名で保存します。

```dockerfile:cuda_ubuntu
FROM ubuntu:24.04

# aptの更新など
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y wget

# CUDAのインストール
RUN wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb
RUN dpkg -i cuda-keyring_1.1-1_all.deb
# ↓Ubuntu23.04以降でCUDAのインストールに必要なコマンド
RUN echo "deb http://archive.ubuntu.com/ubuntu/ jammy universe" >> /etc/apt/sources.list.d/jammy.list
RUN echo "Package: *\n\
    Pin: release n=jammy\n\
    Pin-Priority: -10\n\n\
    Package: libtinfo5\n\
    Pin: release n=jammy\n\
    Pin-Priority: 990" >> /etc/apt/preferences.d/pin-jammy
# ↑Ubuntu23.04以降でCUDAのインストールに必要なコマンド
RUN apt-get update
RUN apt-get -y install cuda-toolkit-12-4
RUN rm cuda-keyring_1.1-1_all.deb
RUN echo "export PATH=/usr/local/cuda-12.4/bin\${PATH:+:\${PATH}}" >> /root/.bashrc
RUN echo "export LD_LIBRARY_PATH=/usr/local/cuda-12.4/lib64:\${LD_LIBRARY_PATH:+:\${LD_LIBRARY_PATH}}\n"  >> /root/.bashrc

# .bashrcの編集
RUN sed -i 1iforce_color_prompt=yes /root/.bashrc
RUN echo alias la="'ls -lah'\n" >> /root/.bashrc

# pyenvのインストール
RUN apt-get install -y curl git build-essential libssl-dev libffi-dev libncurses5-dev zlib1g zlib1g-dev libreadline-dev libbz2-dev libsqlite3-dev make gcc liblzma-dev python-tk tk-dev
RUN curl https://pyenv.run | bash
RUN echo "export PYENV_ROOT=\"\$HOME/.pyenv\""  >> /root/.bashrc
RUN echo "export PATH=\"\$PYENV_ROOT/bin:\$PATH\""  >> /root/.bashrc
RUN echo "eval \"\$(pyenv init -)\""  >> /root/.bashrc
RUN echo "eval \"\$(pyenv virtualenv-init -)\""  >> /root/.bashrc
```

# イメージのビルドとコンテナの作成

`cuda_ubuntu:12.4-24.04`というイメージ名でビルドします。

```bash
docker build -f cuda_ubuntu -t cuda_ubuntu:12.4-24.04 .
```

`cuda124_ubuntu24`というコンテナ名で作成します。

```bash
docker run -itd --gpus all --name cuda124_ubuntu24 -w /work cuda_ubuntu:12.4-24.04
```

# pytorchでCUDAの動作確認

せっかくなのでちゃんと動作確認できるようにpyenvやpytorchの整備をします。

## pyenvの整備

dockerfileでpyenvをインストールします。(ほかにもいろいろ追加してます。)

```dockerfile:cuda_ubuntu
FROM ubuntu:24.04

# aptの更新など
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y wget

# CUDAのインストール
RUN wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb
RUN dpkg -i cuda-keyring_1.1-1_all.deb
# ↓Ubuntu23.04以降でCUDAのインストールに必要なコマンド
RUN echo "deb http://archive.ubuntu.com/ubuntu/ jammy universe" >> /etc/apt/sources.list.d/jammy.list
RUN echo "Package: *\n\
    Pin: release n=jammy\n\
    Pin-Priority: -10\n\n\
    Package: libtinfo5\n\
    Pin: release n=jammy\n\
    Pin-Priority: 990" >> /etc/apt/preferences.d/pin-jammy
# ↑Ubuntu23.04以降でCUDAのインストールに必要なコマンド
RUN apt-get update
RUN apt-get -y install cuda-toolkit-12-4
RUN rm cuda-keyring_1.1-1_all.deb
RUN echo "export PATH=/usr/local/cuda-12.4/bin\${PATH:+:\${PATH}}" >> /root/.bashrc
RUN echo "export LD_LIBRARY_PATH=/usr/local/cuda-12.4/lib64:\${LD_LIBRARY_PATH:+:\${LD_LIBRARY_PATH}}\n"  >> /root/.bashrc

# .bashrcの編集
RUN sed -i 1iforce_color_prompt=yes /root/.bashrc
RUN echo alias la="'ls -lah'\n" >> /root/.bashrc

# pyenvのインストール
RUN apt-get install -y curl git build-essential libssl-dev libffi-dev libncurses5-dev zlib1g zlib1g-dev libreadline-dev libbz2-dev libsqlite3-dev make gcc liblzma-dev python-tk tk-dev
RUN curl https://pyenv.run | bash
RUN echo "export PYENV_ROOT=\"\$HOME/.pyenv\""  >> /root/.bashrc
RUN echo "export PATH=\"\$PYENV_ROOT/bin:\$PATH\""  >> /root/.bashrc
RUN echo "eval \"\$(pyenv init -)\""  >> /root/.bashrc
RUN echo "eval \"\$(pyenv virtualenv-init -)\""  >> /root/.bashrc

RUN apt-get install -y htop vim
```

## PyTorchの整備

pyenvで特定のバージョンのPythonをインストールし、仮想環境を作成し、PyTorchをインストールします。
以下はコンテナ内でのコマンドです。

```bash
# Python3.10.15のインストール
pyenv install 3.10.15
# Python3.10.15を規定バージョンに指定
pyenv global 3.10.15
# 仮想環境の作成
python -m venv test_env
# 仮想環境の有効化
source test_env/bin/activate
# pipのアップグレード
python -m pip install -U pip
# PyTorchのインストール
# https://pytorch.org/ を参照
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
```

## CUDAの動作確認

作成した仮想環境のPyTorchでCUDAが動作するか確認します。
以下はPythonでの実行コマンドです。

```python
import torch

torch.cuda.is_available()
# out: True

torch.Tensor([0, 1, 2]).to('cuda')
# out: tensor([0., 1., 2.], device='cuda:0')
```

ちゃんと動作していますね。