運用で使える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を実行する手順などを書いてみようと思います。
それでは :-)
本日届いた本
久しぶりのブログです。
デザインとか色々整理して、少しづつ再開して行く予定です :-)
そんなわけで、今日密林から届いた本
アプリケーションエンジニアのためのApache Spark入門
Apache Spark 単体というより、それを含めたシステム全体について書かれている本だったので購入。
特に、”Chapter 4 Fluentd、Kafka によるデータ収集”と”Chapter 8 Spark SQL によるデータ処理”に興味があったりします。
さよならの朝に約束の花をかざろう 公式設定資料集
- 出版社/メーカー: 玄光社
- 発売日: 2018/02/24
- メディア: 大型本
- この商品を含むブログを見る
現時点で、映画館で2回観ていますw
設定資料集を買うほど入れ込むのは、多分シン・ゴジラ以来です :-)
早く円盤が出てくれないかな...
systemdでのサービス起動シーケンスの確認方法(systemd-analyze)
そんなわけで、久しぶりのブログ更新(∩´∀`)∩
最近、serviseファイルを作ってオリジナルサービスを作ることになって、systemdで起動されるサービスの起動順序を調べる必要が出てきました。
色々調べていたら、systemd-analyzeというコマンドが使えることが分かったので、ちょっと使ってみました。
このsystemd-analyzeは、systemdで起動する各サービスの起動に掛かった時間などを調べて、OS起動速度のボトルネック解析に使うものです。
このコマンド、起動シーケンスやサービスの起動時間を、SVG形式のガントチャート(?)イメージで出力することができます。
以下のように、plot を指定して実行すると、SVG形式のテキストを出力してくれるので、その出力を適当なファイルに保存します。
$ systemd-analyze plot > systemd_plot.svg
保存したSVGファイルをブラウザで表示してみると、サービスの起動順序と時間が一目瞭然で確認できるチャートとして表示できます。
チャート全体のイメージはこんな感じ。
以下のイメージは、ネットワークサービスの起動完了後に実行されるサービス部分を拡大したものです。
赤い色の部分が、起動に掛かった時間を示しています。
試しにnetwork.targetの起動後に起動している、postfixのserviceファイルを確認してみると、以下のようにAfterにnetwork.targetが定義されていました。
[Unit] Description=Postfix Mail Transport Agent After=syslog.target network.target Conflicts=sendmail.service exim.service [Service] Type=forking PIDFile=/var/spool/postfix/pid/master.pid EnvironmentFile=-/etc/sysconfig/network ExecStartPre=-/usr/libexec/postfix/aliasesdb ExecStartPre=-/usr/libexec/postfix/chroot-update ExecStart=/usr/sbin/postfix start ExecReload=/usr/sbin/postfix reload ExecStop=/usr/sbin/postfix stop [Install] WantedBy=multi-user.target
こんな感じで、systemdで制御されているサービスの起動順序をお手軽に(?)確認することができました(`・ω・´)
ぼっちハッカソンの準備(VMwareとCentOS7との相性悪いぞw)
ここ2年ぐらい、OpenStackとかOpenDaylightがらみの仕事が増えてきたのもあって、家で色々調べることも増えてきたりしていますw
で、その調査環境をVMwareを使って構築中だったりします...
ちなみに、以前はVirtualBoxを使っていたけど、ゲストOS上にKVM動作させることができないので、2年ぐらい前にVMwareに切り替えました...orz
今日、VMware上にCentOS7.1使ってOpenStackとOpenDaylightの検証環境を作っていたら、複数NICを認識しないトラブルが....orz
FedoraやCent6.5では起きなかったので、多分VMwareとCentOS7との相性らしい...
色々調べてみて、何とか回避策を見つけたです...
う~ん、かなり時間を無駄にした...
結論から言うと、VMwareの構成定義ファイル(vmx)のNICドライバ設定が、1つ目しか定義されていないことが原因のようでした。
例えはこんな感じ...
ethernet0.present = "TRUE" ethernet0.vnet = "VMnet0" ethernet0.connectionType = "custom" ethernet0.virtualDev = "e1000" ethernet0.wakeOnPcktRcv = "FALSE" ethernet0.addressType = "generated" ethernet1.present = "TRUE" ethernet1.vnet = "VMnet1" ethernet1.connectionType = "custom" ethernet1.wakeOnPcktRcv = "FALSE" ethernet1.addressType = "generated" ethernet2.present = "TRUE" ethernet2.vnet = "VMnet2" ethernet2.connectionType = "custom" ethernet2.wakeOnPcktRcv = "FALSE" ethernet2.addressType = "generated"
ethernet1とethernet2のvirtualDev指定が抜けています。
この定義はゲストOSで変わるものではないので、一つ目の定義だけでも動作するようだけど、CentOS7ではダメっぽいようです...
なんでだ??
なので、CentOS7をゲストOSとして環境を構築するのであれば、CentOS7をインストールする前に、ethernet1とethernet2のvirtualDev指定を追加する必要があります....
今回、イメージファイルを作成している環境にあるKilo-Comp.vmxファイルに、ethernet1とethernet2のvirtualDev指定を追加しました。
... ethernet0.present = "TRUE" ethernet0.vnet = "VMnet0" ethernet0.connectionType = "custom" ethernet0.virtualDev = "e1000" ethernet0.wakeOnPcktRcv = "FALSE" ethernet0.addressType = "generated" ethernet1.present = "TRUE" ethernet1.vnet = "VMnet1" ethernet1.connectionType = "custom" ethernet1.virtualDev = "e1000" ethernet1.wakeOnPcktRcv = "FALSE" ethernet1.addressType = "generated" ethernet2.present = "TRUE" ethernet2.vnet = "VMnet2" ethernet2.connectionType = "custom" ethernet2.virtualDev = "e1000" ethernet2.wakeOnPcktRcv = "FALSE" ethernet2.addressType = "generated" ...
これでインストール時にNICが正しく認識されるようになりました...
さて、これで準備ができたので、これから環境構築を始めますか....
今日は鎌倉散策 :-) という名の ハナヤマタ 聖地巡礼
明日は有休で3連休...ってことで、今日は鎌倉散策に行ってきました :-)
そんなわけで、最初に行ってきたのは鶴岡八幡宮
これが入り口の鳥居
道路が工事中だったのと観光客が思っていたより多くて、真正面アングルで撮ることができず...
神社側から撮ると逆光になったのでやむなしか...
中に入って、お参りして、仕事運のお守り買って...orz
ハナヤマタでは、一話で出ていたところらしい...
そのあと、寿福寺に行く途中のトンネルとか、
佐助稲荷神社...
あとは、御霊神社踏切
七里ヶ浜高校の周辺の踏切とかにも行ってきましたw
もう鎌倉巡りじゃなくなっているw
で、ハナヤマタ以外でもよく出てくる鎌倉高校前
まだ散策してないところがいくつかあるけど、一日で回るのはムリw
ってことで、ここまで
最後は日の傾いたころに撮った由比ヶ浜 :-)
夕日の逆光って、携帯カメラでもコソコソ綺麗に撮れるものです :-)
ほぼ歩き回っていて、足の筋肉が痛いです...orz
さぁ、明日、明後日は自宅に引きこもって、ぼっちハッカソンです。
それでは~~
M3初サークル参加&ブログ再開 :-)
2年ぶりにブログを再開しました(苦笑
この2年、生活の色々な葛藤もあり、日記を書く状況でもなかったのですが、少しだけ落ち着いてきたので(本当に少しだけw)再開してみることにしました。
元々はてなダイアリーを使っていたのですが、こっちのはてなブログの方が使いやすそうなので、再開ついでにこっちに移行しちゃいますw
三日坊主にならないことを祈ろうw
そんな感じで、少しづつ動き出しているのですが、先週、念願のM3にサークル参加してきました ><
ほんと、参加するまでかなり時間がかかったのですが、なんとかミニアルバムも出すこともでき、少しづつ音楽活動を始めようと動き出しました :-)
内容はこんな感じですwww.youtube.com
COCORO SYSTEM 1st mini album "Sea of electron"
サークルスペースはこんな感じで、ちょっと寂しい感じでしたが、10枚ほど売れました :-)
一応ジャンルは Uplifting Tranceでやっていく予定なのですが、根っこが喜多郎とか姫神(親父さんの方)なので、ヒーリング系もできればなぁ...と思っています。
お絵描き活動の方は...なんか縮小してる感じで、このまま音楽活動の比重が高くなると思います。
なぁ、これから色々ありそうですが、元気にコソコソやっていこうと思います :-)
それではまた~