DockerでPytorch+GPU+Jupyterの開発環境を構築する

# この記事で伝えたいこと
この記事で以下の困りごとにこたえていきたいと思います！

:::note
**Dockerをインストールしたけど、GPUを用いた
機械学習の開発環境の構築方法がわからない**
:::

Dockerをまだインストールしていない方は、以前にDockerのインストール方法について説明した記事があるのでそちらを参考にしてください。

https://qiita.com/hiroakikka/items/b7a63383fb8cb989e722

# Dockerを用いたPytorch+GPU+Jupyter環境構築
ざっくりとした流れは以下の通りです。
**1.** **[(必要に応じて)docker-composeをインストールする](#1必要に応じてdocker-composeをインストールする)**
**2.** **[(必要に応じて)NVIDIA Container Toolkit をインストールする](#2必要に応じてnvidia-container-toolkit-をインストールする)**
**3.** **[作業フォルダ・ファイルの作成](#2作業フォルダファイルの作成)**
**4.** **[必要なPythonライブラリをrequrement.txtにまとめる](#3必要なpythonライブラリをrequirementstxtにまとめる)**
**5.** **[Dockerfileを編集する](#4dockerfileを編集する)**
**6.** **[docker-compose.ymlを編集する](#5docker-composeymlを編集する)**
**7.** **[docker-compose.ymlファイルを実行する](#6docker-composeymlファイルを実行する)**

この手順にしたがって進めていきます。

### 1.(必要に応じて)docker-composeをインストールする
そもそもDocker Composeを使う主な利点は、複数のコンテナをまとめて定義・管理・起動するためです。今回の場合、1つのコンテナしか利用しないので、必要性は小さいと感じますが、複数の設定（ポート、ボリューム、コマンドなど）を1つのYAMLファイル（docker-compose.yml）で定義し、一括で起動・管理できる点もメリットの一つだと思います。そのため、今回は、Docker Composeを用いて、Jpyter環境を簡単に構築していきます。
まず、Docker Composeを用いるために、linux上にdocker composeをインストールするします。なので、私の場合、「Ubuntu24.04」のターミナルを開いて以下のコマンドを実行します。
`sudo apt-get install docker-compose-plugin`
すると以下のような画面が出てくると思います。
```bash
hiro@MAIN:$ sudo apt-get install docker-compose-plugin
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  docker-compose-plugin
0 upgraded, 1 newly installed, 0 to remove and 39 not upgraded.
Need to get 0 B/12.8 MB of archives.
After this operation, 64.3 MB of additional disk space will be used.
Selecting previously unselected package docker-compose-plugin.
```
docker composeがインストールされているか確認のため、以下のコマンドを打ち込みます。
`docker compose version`
以下のような表示がされれば、インストールが完了しています。
```
hiro@MAIN:$ docker compose version
Docker Compose version v2.31.0
```

### 2.(必要に応じて)NVIDIA Container Toolkit をインストールする
Docker で NVIDIA GPU を利用する場合は、NVIDIA Container Toolkit (NVIDIA Docker) が必要になります。（以下のリンクが公式のリンクです。）
https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
「Ubuntu24.04」（ご自身のLinuxで実施ください）のターミナルを開いて
以下のコマンドを実行します。
`sudo apt update`
`sudo apt-get install docker-compose-plugin`
すると以下のような画面が出てくると思います。
```bash
hiro@MAIN:~$ sudo apt update
[sudo] password for hiroaki:
Hit:1 https://download.docker.com/linux/ubuntu noble InRelease
Get:2 https://nvidia.github.io/libnvidia-container/stable/deb/amd64  InRelease [1477 B]
・・・
hiro@MAIN:~$ sudo apt install -y nvidia-container-toolkit
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
・・・
```
Dockerで「NVIDIA GPU を使える設定を追加する」ために以下のコマンドを実行します。
（Dockerのコンフィグレーションファイルをいじっています。）
`sudo nvidia-ctk runtime configure --runtime=docker`
設定を反映させるため、以下のコマンドで再起動します。
`sudo systemctl restart docker`

### 3.作業フォルダ・ファイルの作成
ファイルの構成について説明すると、まず、どこかの適当な場所にプロジェクト用のフォルダを作成してください。
そのフォルダ内に「テキストドキュメント」で新しいファイルを作成し、`Dockerfile`,`docker-compose.yml`,`requirements.txt`を作成します。
`Dockerfile`は拡張子なしで大丈夫です。
`notebooks`の中で作業する感じで考えています。
それぞれのファイルの意味や中身については後で説明します。

```
project
├─ .gitignore            → Gitで追跡しないファイルの指定（今回は必要ないので省略）
├── docker
│   └── dockerfile
├── docker-compose.yml
├── notebooks
├── README.md             → プロジェクト概要や手順説明（今回は必要ないので省略）
├── requirements.txt
└── src　              　→ アプリケーション本体のPythonスクリプトを保存（今回は必要ないので省略）

```
こんな感じですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760884/86686111-08df-45fb-b87f-520e742160f8.png)


### 4.必要なPythonライブラリをrequirements.txtにまとめる
このプロジェクトで必要となるPythonライブラリをrequirements.txtにまとめます。
今回は適当に以下のようなライブラリをインストールするものを考えてみました。
ご自身のプロジェクトに必要なライブラリ名・バージョンへ変更してください。
```requirements.txt
numpy==2.2.1
pandas==2.2.3
matplotlib==3.10.0
seaborn==0.13.2
jupyter==1.1.1
```
上の内容をrequirements.txtに書き込みます。
（requirements.txtのもう少し知りたい方は以下の記事を参考にしてください。）

https://qiita.com/NUNOGAWA/items/2711f5b731f461295388

### 5.Dockerfileを編集する
`Dockerfile`を一言で表すと、「Docker イメージを作成（ビルド）するためのレシピ（設計図）となるファイル」です。
もう少し詳しく知りたいよって方は以下の記事で詳しく説明してあるのでそちらを参照してください。

https://qiita.com/gon0821/items/f9e3bcbb6cb01d4ef7fa

今回は、Python（3.13）をベースとして、`requirements.txt`に記載されているライブラリをインストールし、`jupyter lab`を立ち上げるDockerfileを作成しました。
別のPythonバージョンに変更したい場合は、基本的には`python:<version>`に従って、`version`の部分を変更してください。もう少しこだわりたい方は、以下のリンクを参照に適宜変更してください。

https://hub.docker.com/_/python

```dockerfile:Dockerfile
FROM pytorch/pytorch:2.6.0-cuda12.4-cudnn9-runtime

# 必要な環境変数を設定して非対話的にインストール
ENV DEBIAN_FRONTEND=noninteractive
COPY requirements.txt .

# パッケージのアップデートとインストール
RUN apt -y update && \
    apt -y install libopencv-dev tzdata && \
    apt -y clean && \
    rm -rf /var/lib/apt/lists/* && \
    # Pythonライブラリをインストール
    pip install --no-cache-dir -r requirements.txt 

# Jupyter を起動するエントリポイントを指定
CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root", "--no-browser", "--port=8888"]
```
上のようにDockerfileを編集します。
以下にそれぞれのコマンドのざっくりとした意味を説明します。
`FROM pytorch/pytorch:2.6.0-cuda12.4-cudnn9-runtime`
PyTorchの公式イメージを使用。すでに PyTorchやPythonが入っている環境をベースにするので、自分でPyTorchをインストールする必要はなし！

`ENV DEBIAN_FRONTEND=noninteractive`
apt install などで「タイムゾーンは？」などの質問を自動スキップさせる。Docker内では手入力できないので、この設定が必要

`COPY requirements.txt .`
ホストマシンの requirements.txt を Docker イメージにコピー。

`RUN apt -y update && \...`
Linuxパッケージ & Pythonライブラリのインストール
`EXPOSE 8888`
コンテナ内で使用するポート8888のメタ情報。ホストと接続するには -p オプション等が必要。
`CMD ["jupyter", "lab", ...]`
 Jupyter Notebook を起動するコマンドを指定。
 ```
 --ip=0.0.0.0：外部アクセスを許可
--allow-root：rootユーザーでも起動OK（Dockerではrootが普通）
--no-browser：ブラウザ自動起動なし
--port=8888：8888番ポートで待ち受け（docker-compose.ymlで外に公開される）
```
### 6.docker-compose.ymlを編集する
`docker-compose.yml`を一言で表すと、「コンテナの設定を整理し、複数でも簡単に起動や管理、共有ができるファイル」です。
もう少し詳しく知りたいよって方は以下の記事で詳しく説明してあるのでそちらを参照してください。

https://qiita.com/gon0821/items/77369def082745d19c38

今回は、docker-compose.ymlファイルを用いることで、ホストのポート`8888`を コンテナのポート`8888`に割り当てています。また、ホスト側の `./notebooks` ディレクトリ を コンテナ内の `/workspace` ディレクトリ にマウントしています。


```yaml:docker-compose.yml
services:
  pytorch-gpu:
    build: 
      context: .
      dockerfile: docker/Dockerfile
    image: pytorch_gpu_image
    container_name: pytorch-gpu
    #When using a GPU (Docker Compose v2 or later)
    runtime: nvidia
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
    volumes:
      - ./src:/workspace
      - ./notebooks:/notebooks  # Mount the current host directory into the container
    ports:
      - "8888:8888"
    # tty: true
    # stdin_open: true
    command: jupyter lab --ip=0.0.0.0 --allow-root --no-browser --port=8888 --NotebookApp.notebook_dir=/notebooks
```
上の内容に、docker-compose.ymlファイルを編集します。
以下にそれぞれのコマンドのざっくりとした意味を説明します。



### 7.docker-compose.ymlファイルを実行する

「Ubuntu24.04」を立ち上げると以下のような画面だと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760884/f1ac4470-c34d-05e8-9df6-1dc08edad88d.png)
ここから、docker-compose.ymlファイルがある`project`のフォルダに移動します。
今回はホストPCのNドライブに格納したので、`cd /mnt/n`をコマンドとして打ち込みます。
`mnt`を使用することで、ローカルフォルダにアクセスできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760884/5c8c592f-0b1c-125c-8592-dbb7b9be44df.png)
移動できました。
確認のため、フォルダ内に何が入っているのか、`dir`コマンドで確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760884/996e33de-8b2f-8b19-49d7-34c0fc5bca40.png)
先ほど作成した`project`フォルダがありますね。
`cd project`でフォルダ内に移動します。
`dir`コマンドでフォルダの中身を確認し、先ほど作ったファイルがあることを確認します。
ここのディレクトリで`docker compose up`を打ち込みます。
そうすると、以下のような画面となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760884/ee6c2c56-969d-d6f7-172a-07855e564761.png)
後ろのほうを見ると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760884/2b559110-6183-5e93-3db4-49d517230d89.png)

2つあるうちのどちらでもいいのですが、`http:~`のリンクにWebブラウザを用いて、アクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760884/2563e6a2-5306-8546-7610-7af44b476362.png)

これでJupyter環境の構築は終了です。
先ほどの`notebooks`のフォルダ内を見ている状態なので、作成したフォルダ・ファイルは、先ほどの`notebooks`内に保存されていきます。
最後に作業が終了した後は、まずは、ブラウザ上でjupterをシャットダウンさせます。
その後、`docker compose down`でコンテナを閉じるようにしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760884/b0ac931e-08f0-ba5b-3fe7-675f1836e69e.png)

何か不明点あれば、コメント欄に記載いただければと思います。

# おまけ
JupyterLabの画面がダークモードになっています。上のコードを実行するだけでは、ダークモードにはなりません。
この設定は以下の方法で行っています。
下のような構成となるようにファルダを作成します。
(Dockerfileもいじる必要があります。)

```
docker
└── .jupyter
    └── lab
         └── user-settings
                 └── @jupyterlab
                         └── apputils-extension
                                  └── themes.jupyterlab-settings 　←このファイルをいじります。
```
```json:themes.jupyterlab-settings
{
  "theme": "JupyterLab Dark"
}

```

そんなのどこでわかるんだよと思う方もいるかもしれません。
公式のdocumentにやり方が書いてあるのです。
気になる方もいると思うのでリンクを張っておきます。
https://jupyterlab.readthedocs.io/en/stable/user/directories.html#advanced-usage
dockerfileの中身も変える必要があるので、ダークテーマにできるものを以下のgitリンクに格納してあるので必要に応じて使ってみてください。
https://github.com/hiroakikka/Pytorch_GPU

## 参考文献

https://qiita.com/hiroakikka/items/b7a63383fb8cb989e722

https://qiita.com/NUNOGAWA/items/2711f5b731f461295388

https://hub.docker.com/_/python

https://qiita.com/gon0821/items/77369def082745d19c38

https://jupyterlab.readthedocs.io/en/stable/user/index.html