[python] Dockerでjupyter labの仮想環境構築. 

研究室で共通のOSを用いてなく,細かい場所でエラーが起きることが多発してきたため,環境を均一に出来るDockerを使ってみようと思うに至った.
目標としては,pythonとRをインストール,また,jupyter labを起動出来るようにすることだ.

2020/2/24追記.
docker-composeを用いると更に簡単になります.Dockerfileが具体的に何をやっているか知りたい方は続けて読んでもよいかも.
環境を整えたいだけなら,Dockerでjupyter lab, python, juliaの環境構築 を読むべし.

目標

Dockerは,プロセスとして環境を構築出来る.仮想環境と違い,カーネル部分はホストのものを用いるために軽量かつアプリケーションの環境分離を実現することが可能だ.

そんなDockerをpythonのデータ解析用の仮想環境構築に用いる.
以下の図が,最終的な環境状態になる.

図の説明としては,

1. Docker Engine上にImageとContainerが存在する.ImageはImmutable(変更不可)なオブジェクトであり,テンプレートとして存在する.Imageを用いて,Containerを作成しその上でプログラムを走らせる.

2. Containerの内部には,anacondaを導入する.anaconda内部のパッケージを用いてプログラムを動かす.また,jupyter labをサーバーとして起動させる.

3. 実行用のプログラムが格納されたディレクトリーは,Container内にマウントする.こうすることで,コードの編集環境に関してはDocker上ではなく,Host OS上のものを用いて管理することが可能である.Git/GitHubを用いたバージョン管理などは,Host OS上で行う.

4. Container内で起動したJupyter labにはHost OS上のブラウザーからアクセスする.

まとめると,jupyterlabやパッケージなどの格納場所としてContainerを用意し,解析プログラムはHost OS上で管理する.要するにContainerは本当にプログラムを回す環境として用意することになる.

Dockerでanaconda

以下のサイトで,pythonのコンテナはどんな風に違うか説明している.

仕事でPythonコンテナをデプロイする人向けのDockerfile (1): オールマイティ編

要約すると,用量とか気にしなければpython:3.x-busterを選んでおけば良さそう.
以下のサイトからpythonのDockerコンテナを選ぶことが出来る.
python – Docker Hub

例えば,3.7.9-buster バージョンのpythonコンテナをインストールしたれば,

docker image pull pyton:3.7.9-buster

とすれば良い.

ただ,今回は色々既に準備してあるコンテナを用いたいので,anaconda3のコンテナを用いる.
以下のサイトで提供されている.
continuumio/anaconda3 – Docker Hub
Tagsの中にいろいろなバージョンが記されている.

これをプルするだけで,anacondaを展開することが出来る.

2021/02/14 追記.
Jupyterがdocker imageを公開しており,科学系の解析をするならば是非確認しておいた方が良い.
https://jupyter-docker-stacks.readthedocs.io/en/latest/using/selecting.html
色々詰め込んであるjupter/datascience-notebook というimageだと,python, R, juliaがjupyter labから起動することが出来る.取り敢えずこれを使っておけば問題ないと思うレベルだ.

Dockerでjupyter lab

次にjupyter labの環境設定用のDockerfileを用意する.

参考にしたのは以下の2つのサイトです.
【画像で説明】DockerでAnaconda環境をつくり、コンテナの中でVSCodeを使う
Dockerでデータ分析環境を作ってみる

以下のDockerfileでは,anacondaのコンテナを持ってきて,workdirを作成して,8888でコンテナ側がリッスンして,jupyter labのエクステンションとvimを入れて,最後にaliasを登録する.

FROM continuumio/anaconda3:2020.11

WORKDIR /workdir
EXPOSE 8888

# jupyter lab extensions.
RUN conda install -c anaconda -y nodejs && \
    conda install -c conda-forge jupyterlab-snippets && \
    conda install -c conda-forge jupyterlab-git -y && \
    jupyter labextension install jupyterlab-plotly@4.14.3 --no-build && \
    jupyter labextension install @jupyterlab/toc --no-build && \
    jupyter labextension install @axlair/jupyterlab_vim --no-build && \
    jupyter lab build

# install vim 
RUN apt-get update && \
    apt-get install -y vim

RUN echo "alias jpt_lab='jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root'" >> /root/.bashrc


最後のalias 部分は,jpt_labというaliasに,jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root を登録している.

Dockerfileは,buildするとimageを作成することが出来ので以下のコマンドを回す.ここではイメージとして,イメージネームをtest, バージョンをv01とした.

docker build -f ./Dockerfile -t test:v01 .

あとは,imageの確認とrunは以下のコマンドで行う.コンテナの名前は,test_container にした.

docker image ls
docker run -it -p 8888:8888 \
    --name test_container \
    test:v01

これでjupyter labを起動した際に,表示されるhttp://127.0.0.1:8888/?token=${token} をコピーしてhost OS側のブラザーに入力することで,jupyter labにアクセス出来る.

Containerにファイルをマウント

前に紹介した方法だと,jupyter labを起動出来るが,ファイルを持ち込めていない.
そこで,ファイルをマウントする.

docker run -it -p 8888:8888 \
    --name test_container \
    --mount type=bind,src=`pwd`,dst=/workdir \
    test:v01

これで,Dockerのコンテナを起動 -> jpt_labでjupyter labを起動 -> マウントしたファイルにjupyte labでアクセス可能となる.

最後に,現在は,コンテナを起動する度に,jpt_labと打たなければいけないが,コンテナ起動時に自動的にjupyter labも起動するようにしたい.その際は,runをする際に以下のようにコマンドを打つ. Dockerのimage名の後にソースファイルを指定するとそのコマンドが実行される.

docker run -it -p 8888:8888 \
    --name test_container \
    --mount type=bind,src=`pwd`,dst=/workdir \
    test:v01 \
    /bin/bash -c "jupyter-lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root" 

まとめ

最後に今まで説明してきた内容をまとめる.

Docker fileの一例.
このDocker fileでは,Rとrpy2のインストールも行っている.

FROM continuumio/anaconda3:2020.11

WORKDIR /workdir
EXPOSE 8888

# jupyter lab extensions. 
RUN conda install -c anaconda -y nodejs && \ 
    conda install -c conda-forge jupyterlab-snippets && \
    conda install -c conda-forge jupyterlab-git -y && \
    jupyter labextension install jupyterlab-plotly@4.14.3 --no-build && \
    jupyter labextension install @jupyterlab/toc --no-build && \
    jupyter labextension install @axlair/jupyterlab_vim --no-build && \
    jupyter lab build

# python package installation. 
RUN pip install --upgrade pip && \
    pip install japanize-matplotlib && \
    pip install plotly && \
    pip install ipynb_path && \
    pip install pymc3


# install R 
RUN apt-get update && \
    apt-get install r-base -y && \ 
    pip install rpy2 && \
    Rscript -e "install.packages(c('dplyr','surveillance'))"


# install vim 
RUN apt-get update && \
    apt-get install -y vim

RUN echo "alias jpt_lab='jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root'" >> /root/.bashrc

Dockerの使用方法の一覧.

# docker イメージの一覧
docker image ls 

# dockerコンテナの一覧.-aオプションで起動していないものも表示する.
docker container ls -a 

# docker imgaeのpull 
docker image pull ${image_name}

# dockerfile のビルド
docker -f ${Dockerfile} -t {image_name}:{version} .

# コンテナを起動して名前を付けて,インタラクティブなモードに入る.
docker -it --name ${container_name} ${image_name}

# 作成したコンテナを起動してインタラクティブモードに入る.
docker start -i ${container_name}

# バックグラウンドで動いているコンテナに入る.
docker attach ${container_name}

# jupyter labをファイルをマウントして起動する.
docker run -it -p 8888:8888 \
    --name ${container_name} \
    --mount type=bind,src=`pwd`,dst=/workdir \
    ${image_name}

# jupyter labをjupyterlab-snippetsも使えるように起動する.
docker run -it -p 8888:8888 \
    --name ${container_name} \
    --mount type=bind,src=`pwd`,dst=/workdir \
    --mount type=bind,src=${host_snippet_path},dst=/root/.local/share/jupyter \
    ${image_name}

# jupyter labをcontainer起動時に動かすようにする.
docker run -it -p 8888:8888 \
    --name ${container_name} \
    --mount type=bind,src=`pwd`,dst=/workdir \
    ${image_name} \
    /bin/bash -c 'jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root'


# コンテナの削除
docker container rm ${container_name}

# イメージの削除
docker image rm ${image_name}

# imageにが出てきたときの消去方法.
docker image prune 

# containerで起動していないものを全て削除する方法.
docker container prune

また,jupyter lab用のcontainerを作成する際に,いちいち上記のコマンドを打つのも面倒だから,.bashrcか,.bash_aliasesなどに以下のfunctionを登録しておく.

function jpt_container(){
    if [ $# -ne 2 ]; then 
        echo -e "Usage : jpt_container <container_name> <image_name>" 
    else
        container_name=$1
        image_name=$2
        docker run -it -p 8888:8888 \
            --name ${container_name} \
            --mount type=bind,src=`pwd`,dst=/workdir \
            ${image_name}
    fi
}

function jpt_container_auto(){
    if [ $# -ne 2 ]; then 
        echo -e "Usage : jpt_container_auto <container_name> <image_name>" 
    else
        container_name=$1
        image_name=$2
        docker run -it -p 8888:8888 \
            --name ${container_name} \
            --mount type=bind,src=`pwd`,dst=/workdir \
            ${image_name} \
            /bin/bash -c 'jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root'
    fi
}

Dockerで手間取った箇所

OSごとのDockerの導入に手間取った部分や困り事があったので,覚えている限りで記入する.
Ubuntuだと,何の不自由もなく導入,実行することが出来たのだが...

Mac

jupyter labのbuildの段階でデフォルトだと落ちた.Dockerの設定からリソースのメモリーを5GBまで上げたら成功した.

Windows

最終的には,Docker Desktop for Windowsで起動することを諦め,VMwareでLinuxの仮想環境を立ち上げ,そこでDockerを動かすこととした.安定して動作させることが出来た.

Docker Desktop for windowsの参考サイトを載せておく,が,まだ安定して使うには,Docker Desktop for windowsは早いのかなと思った.
WSL 2 対応 Docker Desktop for Windowsを使うための手順
Windows Subsystem for Linux 2でDocker for WSL2を使う
Docker for Windowsの挙動がおかしい時の対処
Docker for Windowsは不安定?
Docker for Windowsで快適な環境を得るまでの そこそこ長い闘い
Docker Desktop for WindowsのバックエンドとしてWSL2を使用する
Windows Subsystem for Linux 2(WSL 2)をセットアップしてみた

その他

・Dockerで起動したjupyter labで.ipynbを編集すると,その後の管理者権限が,rootユーザーしか編集が出来なくなってしまった.
・Anacondaの容量が大きい.一応,–rm オプションを付けて,コンテナの終了時にコンテナを消去するようにすれば,多数のコンテナの作成は可能.
・jupyterlabのextensionの1つであるkite autocompletionの自動設定が出来なかった.
・マウントしたファイルが同期されない.これに関しては,stack overflowで説明あり.
https://stackoverflow.com/questions/53547973/files-within-docker-bind-mount-directory-not-updating
・アクセストークンを無しにすると,ipynb_pathでエラーが表示された.そのため,tokenありでの起動をするように変更したら解決.

———-雑感(`・ω・´)———-
これで,Dockerでpython環境の構築が出来たので,pyenvなどの仮想環境構築ツールを全部,Dockerに受け渡すことが出来る? 
pyenvだと,compile部分を工夫してるpypyやjythonなどをインストール出来るので,Docker内でpyenvの起動方法も探求の必要はありそう. 

コメント

タイトルとURLをコピーしました