運用で使えるJupyter Notebookコンテナ構築手順まとめ
ここ1年ぐらい、"Literate Computing for Reproducible Infrastructure" という、Jupyter Notebookを使った運用オペレーションなどをやっていたりします。
今回は、このJupyter NotebookサービスのDockerコンテナのビルド手順や、起動方法について書いてみようと思います。
"Literate Computing for Reproducible Infrastructure"というのは、ざっくりいうと、Jupyter Notebookを使って実行可能なドキュメントを実現しよう...というものです。
ここ最近Ansibleを使って、スイッチ制御を含めたシステム運用をすることが流行ってきていますが、playbookの実行手順や実行結果の証跡を残す方法についてはあまり議論されていないと思っています。
この課題についての一つの解として、"Literate Computing for Reproducible Infrastructure"が有効だと考えていたりします。
"Literate Computing for Reproducible Infrastructure"の詳しい内容については、以下のスライドやブログを読んでみてください。
Jupyter notebook を用いた文芸的インフラ運用のススメ
Literate Automation(文芸的自動化)についての考察
enakai00.hatenablog.com
環境構成概要
それでは、これからコンテナ構築手順の説明に入ります。
コンテナを構築するまえに、Jupyter Notebookコンテナを構築するノードなどについて説明します。上の図は、今回私が検証に使っている環境の構成図です。
運用サーバ(cent-dev)は、Jupyter Notebookコンテナが動作するホストノードで、dev01、dev02、dev03は、Ansibleで制御する運用対象ノードになります。
運用サーバのOSとDockerのバージョンは以下の通りです。
OS | CentOS 7.4 |
Docker | CE 17.12 |
Docker Compose | 1.19.0 |
Jupyter Notebookコンテナのビルド手順
それでは、Jupyter Notebookコンテナのビルド手順の説明を始めます。
まず、Jupyter Notebookコンテナ構築に必要なファイルを、NII(国立情報学研究所)のクラウド運用チームが公開しているGitHubから入手します。
github.com
入手は、上記のGitHubからgit cloneするか、zipファイルをダウンロードして、運用サーバ上のhomeディレクトリに展開してください。
私は、以下のようにgitを使って取得しました。
$ git clone https://github.com/NII-cloud-operation/Jupyter-LC_docker.git
取得が完了したら、以下の手順でJupyter Notebookコンテナをビルドします。
まずは取得したDockerfileをカスタマイズします。
$ cd ~/Jupyter-LC_docker
$ vi Dockerfile
普通は、このDockerfileをこのまま使うこともできるのですが、Jupyter Notebookのユーザアカウントの変更や、コンテナにパッケージを追加する手順を説明します。
最初は、Dockerfileにあるユーザアカウント生成処理の設定を変更します。
... # Create 'bit_kun' user ENV NB_USER bit_kun ENV NB_UID 1000 RUN useradd -m -s /bin/bash -N -u $NB_UID $NB_USER && \ mkdir /home/$NB_USER/.jupyter && \ chown -R $NB_USER:users /home/$NB_USER/.jupyter && \ echo "$NB_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$NB_USER ...
ユーザ名称は、ENV NB_USER で設定されています。bit_kun というのは、NIIのマスコットキャラクター(?)ビットくんのことです。
ENV NB_UIDは、ENV NB_USERで指定たユーザのIDを設定します。
あとで説明しますが、ホスト側のディレクトリをコンテナにボリュームマウントするので、ここで指定するユーザ名称やIDは、このコンテナのホスト側のユーザと合わせてください。
次に、コンテナにPythonパッケージの追加です。
特に追加するものがなければこの変更は不要ですが、notebookからSQLを実行する検証がしてみたかったので、今回は追加してみます。
... ## Python kernel with matplotlib, etc... RUN pip --no-cache-dir install jupyter && \ pip --no-cache-dir install pandas matplotlib numpy \ seaborn scipy scikit-learn scikit-image \ sympy cython patsy pymysql psycopg2 \ <---- 51行目 statsmodels cloudpickle dill bokeh h5py && \ apt-get update && apt-get install -yq --no-install-recommends \ git \ ... ### environments for Python3 ENV CONDA3_DIR /opt/conda3 RUN cd /tmp && \ mkdir -p $CONDA3_DIR && \ wget --quiet https://repo.continuum.io/miniconda/Miniconda3-4.2.12-Linux-x86_64.sh && \ echo "c59b3dd3cad550ac7596e0d599b91e75d88826db132e4146030ef471bb434e9a *Miniconda3-4.2.12-Linux-x86_64.sh" | sha256sum -c - && \ /bin/bash Miniconda3-4.2.12-Linux-x86_64.sh -f -b -p $CONDA3_DIR && \ rm Miniconda3-4.2.12-Linux-x86_64.sh && \ $CONDA3_DIR/bin/conda config --system --add channels conda-forge && \ $CONDA3_DIR/bin/conda config --system --set auto_update_conda false && \ $CONDA3_DIR/bin/conda install --quiet --yes \ notebook matplotlib pandas pip pymysql psycopg2 && \ <---- 112行目 $CONDA3_DIR/bin/conda clean -tipsy ...
51行目と112行目にpymysql psycopg2を追加します。
最後に、AWSクライアントの追加です。
これも必要なければ不要です。
... ### aws client RUN apt-get update && apt-get install -y groff && \ pip --no-cache-dir install awscli ### Add files RUN mkdir -p /etc/ansible && cp /tmp/ansible.cfg /etc/ansible/ansible.cfg ...
97行目あたりに、apt-getを呼び出してawscliをインストールする定義を追加します。
以上で、Dockerfileの変更が完了です。
次のコマンドを実行して、コンテナのビルドを行います。
$ sudo docker build -t sys-ope/notebook:1.0 ~/Jupyter-LC_docker/
ビルドが完了したら、以下のコマンドでイメージのビルドに成功したことを確認します。
$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE sys-ope/notebook 1.0 357f73ee4430 7 days ago 4.64GB debian jessie ce40fb3adcc6 4 weeks ago 123MB
これで、Jupyter Notebookコンテナのビルドは完了です。
次に、このコンテナを起動するための事前準備の手順を説明します。
マウント先ディレクトリ作成
ここでは、Jupyter Notebookコンテナからボリュームマウントする、ホスト側のディレクトリ作成を行います。notebookやAnsibleのplaybookといった定義ファイルは、上の図のようにホスト側のディレクトリに配置し、コンテナからマウントして参照する方法にします。
この方が、定義ファイルのバックアップといった運用が簡単になるのと、コンテナの更新作業が簡単になるからです。
※コンテナは使い捨てなので、ステートレスな使い方をするのを前提にした方がよいと考えています。
コンテナ側のディレクトリと、その概要は以下の通り。
コンテナ側 | 概要 |
---|---|
/notebooks | Notebookファイルを保存するディレクトリ |
/etc/ansible | Ansibleのディレクトリ。ansible.cfgを配置する。 |
/home/bit_kun/.ssh | Ansibleのssh実行に使用する秘密鍵を配置するディレクトリ |
ホスト側のディレクトリはコンテナから参照されるので、Dockerfileで指定したユーザのIDと同じユーザIDになるようにしてください。
Ansible実行用鍵ファイル作成と配置
ここでは、Ansibleのssh実行に使用する秘密鍵の作成と配置を説明します。
まずは以下の手順でsshの鍵を生成します。
$ cd ~/sys-ope/.ssh $ ssh-keygen -t rsa -f ansible_id_rsa Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: ...
Ansibleは、パスワード付き鍵ファイルに対応していないので、鍵生成時に入力を要求されるパスワードは未入力(リターンキー入力)にしてください。
次に、生成した秘密鍵と公開鍵のユーザIDとグループIDを設定します。
$ sudo chown 1000:100 ansible_id_rsa $ sudo chown 1000:100 ansible_id_rsa.pub
ユーザIDは、各自の環境に合わせて下さい。
Jupyter Notebookコンテナの実行
ここまでで、コンテナを起動するための事前準備が終わったので、これからJupyter Notebookコンテナを実行します。
まずはdockerコマンドで実行してみます。
$ sudo docker run -it --rm -p 8888:8888 \ > -v ~/sys-ope/notebooks:/notebooks \ > -v ~/sys-ope/ansible:/etc/ansible \ > -v ~/sys-ope/.ssh:/home/bit_kun/.ssh \ > -e PASSWORD=xxxxxx sys-ope/notebook:1.0
環境変数PASSWORDのxxxxxxは、Jupyter Notebookのログイン時に入力するパスワードを設定します。
コンテナの起動に成功すると、以下のようにJupyter Notebookの起動完了と、アクセス先のURLを出力してきます。
... [I 07:43:37.156 NotebookApp] 0 active kernels [I 07:43:37.156 NotebookApp] The Jupyter Notebook is running at: [I 07:43:37.156 NotebookApp] http://[all ip addresses on your system]:8888/ ...
このURLにアクセス(今回の環境では、http://10.0.0.1:8888/)すると、Jupyter Notebookのログイン画面が表示されます。環境変数PASSWORDに設定したパスワードを入力してログインすると、Jupyter Notebookのホーム画面が開きます。これで、Jupyter Notebookコンテナのビルドと動作確認は完了です。
一旦、Ctrl-Cでコンテナを停止させ、このコンテナをdocker-composeで起動するようにします。
docker-composeの定義ファイル作成
まずはviでdocker-compose.ymlを開いて、新規に作成します。
$ vi ~/sys-ope/docker-compose.yml
内容は以下の通りです。
version: "2" services: jupyter: image: sys-ope/notebook:1.0 ports: - 8888:8888 environment: TZ: JST-9 HOST_HOSTNAME: "${HOSTNAME}" hostname: "${HOSTNAME}" PASSWORD: xxxxxx volumes: - ./ansible:/etc/ansible/ - ./.ssh:/home/bit_kun/.ssh/ - ./notebooks:/notebooks logging: driver: journald
PASSWORDのxxxxxxは、Jupyter Notebookのログイン時に入力するパスワードになるので、各自で決めて設定してください。
まずはdocker-compose upで起動します。
$ cd ~/sys-ope $ sudo docker-compose up -d Recreating sysope_jupyter_1 ... done
これで、docker-composeでJupyter Notebookコンテナが起動するようになりました。
あとは、docker-compose start、stopを使って、起動停止を行ってください。
インベントリファイルの作成
ここでは、NotebookからAnsibleを実行するための環境設定や、インベントリファイルの配置の手順を説明します。
まずは、インベントリファイルを配置するディレクトリを作成します。
$ mkdir ~/sys-ope/notebooks/ansible $ mkdir ~/sys-ope/notebooks/ansible/inventory $ mkdir ~/sys-ope/notebooks/ansible/inventory/host_vars $ mkdir ~/sys-ope/notebooks/ansible/inventory/group_vars
次に、ansible.cfgを設定します。
$ vi ~/sys-ope/ansible/ansible.cfg
ansible.cfgには、以下の設定を行います。
[defaults] host_key_checking = False forks = 3 record_host_keys = False remote_user = ansible private_key_file = /home/bit_kun/.ssh/ansible_id_rsa inventory = /notebooks/ansible/inventory/inventory.ini
次は、以下の構成でインベントリファイルを作成します。
~/sys-ope/notebooks/ansible |--inventory | |--group_vars | |--host_vars | | |--cent-dev.yml | | |--dev01.yml | | |--dev02.yml | | |--dev03.yml | |--inventory.ini
まず先に、host_varsの下に、ノードごとの情報を定義するyaml形式のファイルを作成します。
ファイル名称がAnsible内で使用されるホスト名称となり、定義のansible_hostに、ssh接続するIPアドレスを設定します。
例:dev01.yml
--- ansible_host: 10.0.0.10
host_varsに、今回の対象ノードの定義ファイルを作成し終わったら、inventory.iniを作成します。
$ vi ~/sys-ope/notebooks/ansible/inventory/inventory.ini
このインベントリファイルは、先ほど作成したansible.cfgに定義したinventory で設定したファイルになります。
内容は、こんな感じになります。
[dev] dev01 dev02 dev03 [ope] cent-dev
インベントリファイルの作成が終わったら、ファイルの所有者設定を行っておきます。
$ sudo chown 1000:100 -R ~/sys-ope/notebooks/ansible
以上で、Ansibleの設定を含めた、Jupyter Notebookコンテナ構築は完了です。
それでは、Jupyter Notebookから、お試しでAnsibleを実行してみます。
Notebookからansibleを実行してみる
まずは、先ほどのログイン画面からログインしてホーム画面に入ります。ホーム画面の右側にあるNewのプルダウンから、Python2を選択すると、Untitledという名前の、Python2のコードが実行できるNotebookが生成されます。
次に、Notebook上でAnsibleを実行してみます。
まだ、対象のノードに公開鍵配置やAnsible実行用アカウントの生成を行っていないので、パスワード入力のrootでlsコマンドを実行してみます。左側が”In []:”となっているところに、先頭に"!"をつけて実行するコマンドを入力します。
この"!"をつけることで、Jupyter Notebook上でコマンドを実行することができるようになります。
こんな感じです。
!ansible -m shell -a 'ls -la ' -e 'ansible_user=root ansible_ssh_pass=xxxxxxx' all
ansible_ssh_passのxxxxxxxには、rootアカウントのパスワードを入力してください。
【補足】Notebook上で実行するコマンドは、対話形式のものが使用できないので、-kを使うことができません。
コマンドの入力ができたら、上のRunボタンを押してコマンドを実行します。実行すると、コマンドの出力が下の方にリアルタイムに出力されます。
この出力結果は、Notebookファイルに保存されるので、実行結果のエビデンスとして残すことができます :-)
そんなわけで、ちょっと長くなってしまいましたが、運用で使えるJupyter Notebookコンテナの構築手順と、ちょっとだけですがNotebookでAnsibleを実行する手順の説明をしてみました。
次はこの環境に対して、ansible実行ユーザの追加や、パスワードログインが出来ないようにsshdの設定を変更するplaybookを実行する手順などを書いてみようと思います。
それでは :-)