UbuntuでChainer用のGPU環境を分ける方法

Ubuntuにおいて、nvidia-docker2を用いて、Chainer用のGPU環境を分ける方法についてまとめます。

# 前提
* Compute Capability 3.0以上のNvidia製GPU ([CUDA GPUs | NVIDIA Developer](https://developer.nvidia.com/cuda-gpus)参照) が搭載されている
* OSはUbuntuである
* プログラムはPythonによって記述されている
* プログラム内ではChainerを用いている
* プログラムによって、必要とされるCUDAやcuDNN、Chainerのバージョンが異なる

# 必要なソフトウェアのインストール方法
2. `sudo apt update`コマンドを実行します。
1. `sudo apt install ubuntu-drivers-common`コマンドを実行し、`ubuntu-drivers`をインストールします。
2. ``sudo apt install `ubuntu-drivers devices | grep driver | grep recommended | awk '{print $3}'` ``コマンドを実行し、GPUドライバをインストールします。
1. [Get Docker CE for Ubuntu | Docker Documentation](https://docs.docker.com/install/linux/docker-ce/ubuntu/)に従って、Docker CEをインストールします。
1. [Install Docker Compose | Docker Documentation](https://docs.docker.com/compose/install/#install-compose)に従って、docker-composeをインストールします。
1. [Installation (version 2.0) · NVIDIA/nvidia-docker Wiki](https://github.com/nvidia/nvidia-docker/wiki/Installation-(version-2.0)#installing-version-20)に従って、nvidia-docker2をインストールします。

# 環境作成方法
1. ディレクトリを作成します。
2. 作成したディレクトリに移動します。
1. 動かしたいプログラムの`requrements.txt` ([Python Tips：ライブラリをまとめてインストールしたい - Life with Python](https://www.lifewithpython.com/2014/03/python-install-multiple-modules-.html)参照) を配置します。
1. `TODO`部のコメントに従って編集した`Dockerfile`を作成します。

    ```Dockerfile
    #TODO: 以下の{}部を記述し、コメントアウトを解除 (タグ ({CUDAのバージョン}-cudnn{cuDNNのバージョン}-devel-ubuntu{Ubuntuのバージョン}) については、 https://hub.docker.com/r/nvidia/cuda/tags/ に該当するタグが存在するかを確認すると良い)
    #FROM nvidia/cuda:{CUDAのバージョン}-cudnn{cuDNNのバージョン}-devel-ubuntu{Ubuntuのバージョン}
    #MAINTAINER {作成者氏名} <{作成者メールアドレス}>
    
    #APTのリポジトリ情報を更新
    RUN apt update
    
    #APTで必要なパッケージをインストール
    #TODO: APTでインストールするパッケージがある場合、以下に追加
    RUN apt install -y --no-install-recommends unattended-upgrades \
    #                                          TODO: Pythonで日本語を処理する場合、以下のコメントアウトを解除
    #                                           language-pack-ja \
    #                                          TODO: Python2を使用する場合、以下のコメントアウトを解除
    #                                           python-setuptools \
    #                                           python-dev \
    #                                           python-pip
    #                                          TODO: Python3を使用する場合、以下のコメントアウトを解除
    #                                           python3-setuptools \
    #                                           python3-dev \
    #                                           python3-pip
    
    #セキュリティアップデートを適用
    RUN unattended-upgrades
    
    #APTで不必要なパッケージをアンインストール
    RUN apt purge -y unattended-upgrades
    RUN apt autoremove -y
    
    #APTのキャッシュをクリア
    RUN apt clean
    
    #pythonコマンドとpipコマンドのシンボリックリンクを作成
    #TODO: Python3を使用する場合、以下のコメントアウトを解除
    #RUN echo "python" "pip" | xargs -n 1 sh -c 'ln -s /usr/bin/${0}3 /usr/bin/${0}'
    
    #必要なパッケージをpipでインストール
    COPY requirements.txt /
    RUN pip install -r requirements.txt
    
    #ホストでログインしているユーザーと同じユーザーを作成
    #TODO: 以下の{}部を記述し、コメントアウトを解除
    #RUN useradd -u {現在ホストでログインしているユーザーのユーザーID (『id -u ${USER}』コマンドで取得)} -o -m {現在ホストでログインしているユーザーのユーザー名}
    #RUN groupmod -g {現在ホストでログインしているユーザーのグループID (『id -g ${USER}』コマンドで取得)} {現在ホストでログインしているユーザーのユーザー名}
    
    #Python実行時にWarningが表示されるように設定
    #TODO: 以下の{}部を記述し、コメントアウトを解除
    #RUN echo "export PYTHONWARNINGS=default" >> ~{現在ホストでログインしているユーザーのユーザー名}/.bashrc
    
    #使用言語を日本語に設定
    #TODO: Pythonで日本語を処理する場合、以下のコメントアウトを解除
    #ENV LANG ja_JP.UTF-8
    
    #TODO: その他必要な処理を以下に記述
    
    #キャッシュや不必要なファイルを削除
    #TODO: 不必要なファイルがある場合、以下に追加
    RUN rm -rf /var/lib/apt/lists/* \
               /var/cache/apt/archives/* \
               .cache/pip/* \
               requirements.txt
       ```

1. `TODO`部のコメントに従って編集した`docker-compose.yml`を作成します。

    ```docker-compose.yml
    version: '2.3'
    
    services:
      main:
        build: .
        runtime: nvidia
    #   TODO: 以下の{}部を記述し、コメントアウトを解除
    #    command: {実行コマンド}
    #    container_name: {コンテナ名 (自由に指定可能)}
    #    user: {現在ホストでログインしているユーザーのユーザー名}
    #    environment:
    #      - NVIDIA_VISIBLE_DEVICES={使用するGPUのID}
    ```

1. `docker-compose build`コマンドを実行します。

# 実行方法
2. 作成したディレクトリに移動します。
1. `docker-compose up -d`コマンドを実行します。

# 実行ログ閲覧方法
2. 作成したディレクトリに移動します。
1. `docker-compose logs -f`コマンドを実行します。

# 終了方法
2. 作成したディレクトリに移動します。
1. `docker-compose stop`コマンドを実行します。
1. `docker-compose rm`コマンドを実行します。

# 補足
* Python3を用いる場合、コンテナ内では`python`でも`python3`でも動作するようになっています。

# 関連記事
* [Ubuntu 18.04 LTS上のIntelliJ IDEAにDocker integrationプラグインを導入する方法 - Qiita](https://qiita.com/SUZUKI_Masaya/items/5d43ad25187a3e46f009)

# 参考文献
* [nvidia-docker2をUbuntuにインストールしてdocker-composeから実行する。 - Qiita](https://qiita.com/sabaku2017/items/f789a3c2b2e879e2804f)
* [dockerでvolumeをマウントしたときのファイルのowner問題 - Qiita](https://qiita.com/yohm/items/047b2e68d008ebb0f001)
* [Python 3で日本語をprintする際のUnicodeEncodeErrorはLANGに気をつける - Qiita](https://qiita.com/toshihikoyanase/items/47407551d8f3d4e8c39a)
* [Bashのfor文をワンライナーへ書き換える - Qiita](https://qiita.com/SUZUKI_Masaya/items/a58523c4e4c8b3a2958c)
* [Python 開発者は -W default オプションを使おう - Qiita](https://qiita.com/methane/items/35ac132798051c7f9573)
* [Docker: コンテナのlocaleを設定したい - Qiita](https://qiita.com/suin/items/856bf782d0d295352e51)
* [How to install the NVIDIA drivers on Ubuntu 18.04 Bionic Beaver Linux - LinuxConfig.org](https://linuxconfig.org/how-to-install-the-nvidia-drivers-on-ubuntu-18-04-bionic-beaver-linux)