要約
- Kubeflow Notebooksで使えるオリジナルのコンテナイメージ(カスタムイメージ)の作成例です
- コンテナイメージならなんでも使える訳ではなく、Kubeflow独自の条件をクリアする必要があり少々ハマりました
ことの経緯
Kubeflow NotebooksではNotebookインスタンスを払い出す際にデフォルトで使えるいくつかのコンテナイメージが組み込まれています
ただ用途によってはライブラリが足りないなど、やはりデフォルトのイメージだけではちょっと物足りなくなる事があります。
また上記のKubeflowデフォルトのイメージでは総じてjovyanという名前の謎のユーザを使う事が強制されるのですが何より困るのがこのjovyan、sudoできないのである。
「まぁちょっとお試しで使うだけのライブラリだから…」というノリでsudo apt-get install
することができません。
(base) jovyan@lab-0:~$ apt-get install hoge
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?
(base) jovyan@lab-0:~$ sudo apt-get install hoge
bash: sudo: command not found
幸いにもKubeflow Notebooksではユーザ独自のコンテナイメージ(=Custom Image)を使う事もできるので、必要なライブラリをかき集めつつ、ついでにsudoできるコンテナイメージを作ってみました。
カスタムイメージの要件
コンテナイメージならなんでもKubeflow Notebooksから扱える訳ではなく、クリアすべき条件がいくつかあります。
以下、意訳です。
- ポート
8888
でHTTPインターフェースを公開すること- Kubeflow Notebook実行時に環境変数
NB_PREFIX
にコンテナが待ち受けるべきURLパスが設定される- (※訳注)Kubeflow Notebookからコンテナアプリケーションにアクセスする際、ドキュメントルート(/)など静的なパス宛てではなく動的に生成されるパスに対してアクセスが行われます(今回はここでハマりました)
- この動的なパスはNotebookインスタンスを払い出す際に環境変数
NB_PREFIX
に設定されるため、アプリケーション側でこの環境変数を使って動的にコンテンツを生成してあげる必要があります# NB_PREFIXの実例 $ kubectl get pod -n kubeflow-user-example-com test-0 -o yaml | grep NB_PREFIX -A 1 - name: NB_PREFIX value: /notebook/kubeflow-user-example-com/test
- Kubeflow NotebookはIFrameを利用してコンテナアプリケーションのコンテンツを投影するため、アプリケーション側で
Access-Control-Allow-Origin: *
をHTTPレスポンスヘッダに設定しておくこと
- Kubeflow Notebook実行時に環境変数
- jovyanというユーザー権限で実行すること
- jovyanのホームディレクトリは
/home/jovyan
であること - jovyanのUIDは
1000
であること
- jovyanのホームディレクトリは
- Kubeflow Notebooksでは/home/jovyanに空のPVCがマウントされた状態で起動される
- kubeflowはPodの再起動後も状態を保持するために
/home/jovyan
にPVCをマウントする - (※訳注)ここちょっと趣旨が読み取りにくいですが「
/home/jovyan
にはPVCがマウントされることになるのでホームディレクトリは空っぽにしておいてね」ぐらいの意味かと思われます。
- kubeflowはPodの再起動後も状態を保持するために
カスタムイメージを作ってみる
上記の条件をクリアするコンテナイメージの作成例です。
Dockerfile
FROM tensorflow/tensorflow:2.11.0-jupyter
ARG DOCKER_UID=1000
ARG DOCKER_GID=100
ARG DOCKER_USER=jovyan
ARG DOCKER_PASSWORD=jovyan
# ポイントその1: jovyanという名前のユーザを作成
# ポイントその2: jovyanのUIDは"1000"を指定
# ポイントその3: jovyanをsudoグループに追加
RUN useradd -m --uid ${DOCKER_UID} -g ${DOCKER_GID} --groups sudo ${DOCKER_USER} \
&& echo ${DOCKER_USER}:${DOCKER_PASSWORD} | chpasswd
# ポイントその4: sudoをインストールしておく
RUN apt-get update && apt-get install -y --no-install-recommends \
sudo \
git \
wget \
libatlas-base-dev \
libgl1-mesa-dev \
libopencv-dev
# pipでインストールするライブラリ群
COPY --chown=jovyan:users requirements.txt /tmp/requirements.txt
RUN python3 -m pip install -r /tmp/requirements.txt --quiet --no-cache-dir \
&& rm -f /tmp/requirements.txt
# ポイントその5: jovyan権限で実行
USER ${DOCKER_USER}
# ポイントその6: 8888番ポートを公開
EXPOSE 8888
# ポイントその7: Access-Control-Allow-Originを設定(--NotebookApp.allow_origin='*')
# ポイントその8: NotebookサーバのベースURLを環境変数"NB_PREFIX"で指定(--NotebookApp.base_url=${NB_PREFIX})
ENTRYPOINT /usr/bin/python3 /usr/local/bin/jupyter-notebook --notebook-dir=/home/${DOCKER_USER} --ip 0.0.0.0 --no-browser --allow-root --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.allow_origin='*' --NotebookApp.base_url=${NB_PREFIX}
- ベースイメージはDockerHubで公開されているtensorflow-notebookのCPU版を使っています
- 上記でポイントとして記載した8点を押さえておけば、その他はお使いの環境や用途に応じてカスタマイズできるはずです。
- 設定は任意ですが、ENTRYPOINTに記載した
--NotebookApp.token
と--NotebookApp.password
を空にしておけばNotebookサーバを開いた際の認証を無効にすることができます(Kubeflow Dashboradにログインする際にも認証されるので二重に認証されるとめんどくさい)
requirements.txt
pipでインストールするライブラリのリストですが、今回の本筋とは関係ありませんのでご参考までに。
pandas
matplotlib
numpy
opencv-python
tqdm
コンテナイメージのビルド
あとはイメージをビルドして任意のリポジトリに格納します。
$ sudo docker build . -t hoge/fuga:v1.0
$ sudo docker push hoge/fuga:v1.0
カスタムイメージをKubeflow Notebooksで使ってみる
上記でビルドしたカスタムイメージをKubwflow Notebookから使ってみます。
New notebookの画面でCustom Image
の欄にチェックを入れ、作成したコンテナイメージのパスを記入します。
以降の設定は通常のNotebook作成時と特に変わりません。
Notebookサーバが起動したらターミナルを開いてsudoのテスト
sudoできたので、目的達成です。お疲れ様でした。
参考資料