後編①とは
- 内容が濃すぎたため、セッション部分の前編と、ハンズオン部分の後編にわけました。
- が、さらにDockerfileを読んでたら学ぶことがどんどん出てきたので、①②...とわけました(前後とは...)
- 前編はこちらです
- 後編①はこちらです
- 後編②はこちらです
- 後編③はこちらです
- 後編①はハンズオン環境である
Jupyter Notebook
を構築しているDockerfileについて書きたいと思います。
資料のリンク
ハンズオンの概要
- Jupyter Notebookを使ったハンズオン
- Jupyter Notebook上からECSクラスタを起動する
- ECS上で
Clair
とTrivy
をAPIサーバとして起動する - そのサーバを利用してコンテナの脆弱性を診断する
ハンズオン環境の起動
- さらっとコマンドを実行すれば環境が起動するのだが、「どのようにして起動するのか?」というのが気になったので調べる!(コンテナ便利すぎる)
1. アクセスキーをそれぞれ変数に設定します
- これはいつもdirenvで設定しているのでOK
- direnvを知らないと人生の半分を損している
- ローカルPCからawscliで、AWS上のS3やCloudFormationを使うためのアクセスキー/シークレットキーの設定
2. ハンズオン環境の設定置き場を作ります $ docker volume create scan-images
- 設定の置き場・・・?
- コンテナは使い捨てなので、設定などを永続化しておくボリュームを
docker volume
コマンドで作るっぽい
3. ハンズオン環境を起動します $ docker run --rm -it -e AWS_DEFAULT_REGION=ap-northeast-1 \ -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_DEFAULT_PROFILE \ -v /var/run/docker.sock:/var/run/docker.sock \ -v scan-images:/root/config \ -v $HOME/.aws:/root/.aws \ -p 8080:8080 jawsug/container:scan-images-fixed
docker run
:コンテナ起動- オプション関連は公式のリファレンスを見ると良さそう
--rm
:コンテナの終了時に自動的にコンテナをクリーンアップし、ファイルシステムを削除する- デフォルトではコンテナを終了してもコンテナのファイルシステムの内容を保持し続ける
- 短い期間だけフォアグラウンドで動かす場合に適したオプション
-it
:コンテナのプロセスに対してttyを割り当てる(簡単に言うとdocker内にログインして操作できる)-i
:標準入力を開き続ける-t
疑似ttyを割り当てる
-e
:環境変数の組み合わせ-v
:共有ファイルシステム(VOLUME)ホスト側のディレクトリ:コンテナ側のディレクトリ
でマウントを作成/var/run/docker.sock
をコンテナ内で操作できるようにする・・・?- これはいいのかな?わからないけど、ホストマシンのルートを与えることにつながるという記事を見つけた
- ハンズオンなら大丈夫だけど、本番で動かすようなものだと気をつけたほうが良いのかもしれない
scan-images:/root/config
:コンテナ内の/root/configを共有VOLUMEに永続化しておく$HOME/.aws:/root/.aws
:ホストマシンのAWSクレデンシャル情報をコンテナ内に設定- コンテナ内からCloudFormationなどを操作するため
-p
:ホストマシンとコンテナのポートのマッピング- コンテナが8080ポートで受けているのでホスト側の8080とマッピング
jawsug/container:scan-images-fixed
ついでにDockerfileを見てみる
FROM docker:18.06.0-ce-dind
FROM
:コンテナのベースとなるイメージ- Dockerインストール済みのコンテナ
- コンテナからコンテナを操作する
- dindは「Docker in Docker」の略
ENV AWSCLI_VERSION=1.15.66 \ JUPYTER_VERSION=1.0.0
RUN apk --no-cache add python3 git
- Python3とGitのインストール
--no-cache
で不要なファイルを削除できる(イメージを小さくするため)
AWS CLIをインストールするレイヤ
# Install AWS CLI RUN apk --no-cache add groff less jq \ && apk --no-cache add --virtual build-deps py3-pip \
&&
でワンライナーにしているのはイメージのレイヤーを少なくして、イメージの容量を減らすため- 複数行でコマンドを実行するとそれごとにレイヤーができる(=イメージの容量が増える)
- AWSを操作するための
awscli
のインストール 前提として以下をインストール
groff や less は AWS CLI が依存しているライブラリです。less は例えば help コマンドを打った時に必要になるのです。社内リポジトリで恐縮ですが、AWS CLI を単体でいれるときもこれらをインストールしています https://t.co/7qAFlsvfWj
— Ryo Nakamaru (@pottava) 2019年6月2日
&& pip3 install "awscli == ${AWSCLI_VERSION}" \ && pip3 install yq \
- pip3コマンドで
awscli
をインストール - pip3コマンドで
yq
をインストールyq
はYAMLが使えるjqのラッパー
&& find / -type d -name \__pycache__ -depth -exec rm -rf {} \; \
&& rm -rf /root/.cache \
- rootユーザのキャッシュの削除
&& apk del --purge -r build-deps
build-deps
という仮の名前でインストールしたpy3-pipを削除- awscliが入ればpip3自体はいらない
Jupyter Notebookをインストールするレイヤ
RUN apk --no-cache add bash tini \
- 前提として以下をインストール
- bash
- tini
- tiniってなんだ?これかな?
- ゾンビプロセスの生成をおさえるっぽい
(脱線)Dockerのinit processについて
- ここを参考にさせて頂きました!
- Dockerで特に考慮せずにプロセスを実行するとエントリーポイントとして設定したプロセスがPID:1で起動する
- PID:1はdocker stopなどでSIGTERMシグナルを送ってもプロセスが停止しないで一定時間後にSIGKILLで強制終了する
- コンテナの停止に余計な時間がかかったり、graceful shutdownがされないなどの問題がある
- Dockerで使用できてシグナルを適切に処理するinit用プロセスがtini
- Docker 1.13以降は
--init
オプションでdocker runすることでtiniが実行される
- Docker 1.13以降は
&& apk --no-cache add --virtual build-deps build-base python3-dev \
- python3-devはpython拡張ライブラリ
--virtual
で仮の名前を付与しているけど、どこにも使ってない・・・?
&& pip3 install "jupyter == ${JUPYTER_VERSION}" \
- pip3コマンドで
jupyter
のインストール
&& pip3 install backcall bash_kernel \ && python3 -m bash_kernel.install \
- pip3コマンドで
backcall
とbash_kernel
をインストール - backcallは、サーボパーティのコールバック関数に自分のパラメータを追加できる
- bash_kernelを入れてJupyter Notebookコンテナでbashを使えるようにしている?
&& find / -type d -name tests -depth -exec rm -rf {} \; \ && find / -type d -name \__pycache__ -depth -exec rm -rf {} \; \ && rm -rf /root/.cache
- キャッシュの削除など
tests
ってディレクトリがどっかで作られてるのか・・・?- 他プロジェクトからの横展開で消し忘れとのことでした
Dockerfile 内で Git の設定をしたり tests を消しているのは他プロジェクトからの横展開で削除漏れです、すみません。例えばこちらでは git を使っていたのでした。https://t.co/J4UqpBpWv2
— Ryo Nakamaru (@pottava) 2019年6月2日
Gitの設定をするレイヤ
RUN git config --global credential.helper '!aws codecommit credential-helper $@' \ && git config --global credential.UseHttpPath true
- CodeCommitでGitの認証をする際に使用するAWSのプロファイル情報を設定する
Jupyter Notebookの設定
WORKDIR /root/notebook ADD notebooks_config/jupyter_notebook.py /root/.jupyter/jupyter_notebook_config.py ADD notebooks /root/notebook ADD application /root/notebook/application ADD infrastructure /root/notebook/infrastructure
- Jupyter Notebookで必要なファイルなどを配置
ADD notebooks_config/entrypoint.sh / RUN chmod +x /entrypoint.sh
- エントリポイントの設定
VOLUME /root/config
/root/config
でマウントポイントを作る
ENTRYPOINT ["/entrypoint.sh"] CMD ["tini", "--", "jupyter", "notebook"]
- tiniでコンテナ起動
まとめ
- コンテナを作る時に
tini
を使ってゾンビプロセスの生成を防いでいる、という手法があるのを知れた - また、コンテナ関係ないがコールバック関数の上書きなども勉強になった
しかしgroffやbackcall、yqなどをどこで使うのかがまだわかっていない(Jupter Notebook関係)- @pottava さんに回答いただきました!
- groff: AWS- CLIが依存しているライブラリ
- backcall: Jupyter notebookでBashカーネルを有効にするため
- yq: Clair起動時の情報をパースしてい見やすくしている(ありがたや)
- コンテナを通じてインフラを勉強するの良さそう
次回
- ClairとKlarを実際に動かして脆弱性スキャンをやってみたいと思います!
- JAWS-UG コンテナ支部 入門編 #6 コンテナの始め方 後編②(Clairで脆弱性スキャン)