dockerコンテナを用いた開発


dockerコンテナを使って開発しよう

環境が汚れないし再現性も高められるので何かと良さそうである。

step1. Dockerrfileを書こう

まずは、基本となるイメージを何にするかを考える。このときには、使いたいライブラリの要件などによって選べばいいと思う。tensorflowが最初から使えるイメージpytorchが使えるイメージが公開されているのでそちらを使えばいいし、特に決まっていないのであればnvidia/cuda:9.0-cudnn7-runtime-ubuntu16.04などを入れれば良い。いずれにせよ、自分がどのバージョンを入れるかを考える時に必要になるのが、CUDAとcuDNNのバージョンである。

CUDAとcuDNNの話

CUDAはNvidiaとかのGPUを使うのに必要だが、これはDockerイメージを引っ張ってくることが出来る。
まずは、

nvidia-smi

を叩いて、出てきた結果の一番上のDriver Versionに着目しよう。

このドライバーはDockerコンテナでどうにか出来るものではないので、これによってバージョンが規定される。
次に、Cuda compatibilityのページを見て、どのバージョンまでのCUDAなら入るかを確認する。この場合は、CUDA10.1までは入ることがわかる。
(2020/01/28時点)

さて、そうしたらDockerのホームページに行って適切なタグを探そう。今回はできるだけ新しいものを入れたかったので、10.1-cudnn7-runtime-ubuntu16.04を使った。

Dockerfile
FROM nvidia/cuda:10.1-cudnn7-runtime-ubuntu16.04
RUN hogehoge

とすれば完成である。
例えば、pytorchの1.1.0じゃなくて1.2.0が使いたい時などは、CUDA>=9.2が要求されるので、このように調べて適切なコンテナ内でインストールする必要がある。

step2. docker-composeを使おう

docker-compose を使わないと、コンテナを作る時に
docker run -it --shm-size=8g -v /home/src:/root/src -p 8080:8080 (image_name)といった感じのコマンドを打つ必要があります。長くてめんどくさいです。ファイルに書いてしまいましょう。

docker-compose.ymlをDockerfileと同じフォルダに作成する。

書こう

下記のものさえ書いてあれば最低限やりたいことはできる。

docker-compose.yml
version: "2.3" #docker-compose のバージョンであって自分が作っている物のバージョンではない
services:
  algorithm_module:
    build:
      context: . #これで同じディレクトリのDockerfileを参照することを指定
    image: IMAGE_NAME #この名前のイメージが、`docker images`で出てくるようになる。
    command: /bin/bash #入った時にどうするか
    volumes: #ディレクトリをマウントする。これは後から変えられないのでとても大事。開発のしやすさはここをしっかり考えることで上がる。
      - .:/root/hoge #現在のディレクトリを/root/hogeにマウント ソースコードフォルダをマウントしよう
      - /datafolder:/root/datafolder #データを置いている場所は忘れずマウント
      - `~/.ssh/id_rsa:/root/.ssh/id_rsa` -> githubで使う
    ports:
      - 8899:8899 #これも書いておかないと後述のJupyter系が使えないので大事。他の人とサーバーを共有している場合は他の人が使わなさそうな番号にしておこう。
    runtime: nvidia #GPUを使うなら書こう
    shm_size: 4g  #メモリのサイズ。GPUのメモリではなくCPUのメモリ

buildしよう

中に色々書き込む。
docker build
をしたらしばらく待つ。

runしよう

docker composeを使うときは多少注意が必要で、
docker-compose.ymlに
-ports 8888:8888
と書いた上で、
docker-compose run -p 8888:8888 module
としなければならない。こうしないとバグる。

--runtime=nvidia を入れないとGPUが使えないので注意

step3. jupyterlab/notebook を使用しよう

jupyter lab --port=8080 --allow-root --ip '0.0.0.0'と打つことで手元のパソコンでlocalhost:8080と打つとJupyter labを開くことが出来ます。
しかし、毎回打つのはめんどくさいですので、設定に書いてしまいましょう。

やること

jupyter notebook --generate-config
でconfigを作成する。パスが表示されるのでそれをエディタで開き、
vim /home/ubuntu/.jupyter/jupyter_notebook_config.py

## Whether to allow the user to run the notebook as root.
#c.NotebookApp.allow_root = False

を探し、その下に
c.NotebookApp.allow_root = True
を書き加える。
②同様に、

## The port the notebook server will listen on.
#c.NotebookApp.port = 8888

c.NotebookApp.port = 8080

## The IP address the notebook server will listen on.
#c.NotebookApp.ip = 'localhost'

c.NotebookApp.ip = '0.0.0.0'

を書き加える。こうすることで、jupyter labのコマンドのみで開けるようになる。

tokenが毎回求められてめんどくさいので、

jupyter notebook password

で設定してしまえば楽。

Jupiter lab extensionを使いこなそう

code foldingはextensionがいらない。

コードの折りたたみはあるとかなり快適です。普通に使っていると出てこなくて、extensionを調べていてもなかなか見つからなかったのですが、どうやら最近 jupyter labの基本に実装されたらしいので是非使って下さい。
やることは、
Settings -> Advanced Settings Editor -> Text Editor を押して、右側の自由に編集できる部分に

{
    "editorConfig": {
         "codeFolding": true
    }
}

を貼り付けるだけです。

ssh 周りの話

ssh -L8888:localhost:8888 username@hostname

vim .ssh/configで開き

Host 分かりやすい名前
    HostName ip.ip.ip.ip
    User YOURNAME
    IdentityFile ~/.ssh/id_rsa
    ForwardAgent yes

などと書き込む。詳しくはこちらを参考にした。

ssh -A で秘密鍵を携えてsshすることができる。これによってサーバーに秘密鍵を置く必要がなくなるので嬉しい。
ssh-add で毎回id_rsa用のパスワードを聞かれることがなくなる。楽である。

また、
ssh -NfL localhost:8889:localhost:8889
をするとポートフォワーディングができる。