みなさんはKubernetesでPodを作成するときに、アプリケーションのgit cloneなどPodの初期化処理はどのように行っていますか?Kubernetesにはinit Containersと呼ばれる初期化専用のコンテナがあります。
本記事では、init Containersを利用して、Pythonの仮想環境(venv)とモジュールのインストール(pip install)を行い、Python環境の初期化処理を行ってみます。
init Containersとは?
init ContainersはPodの初期化処理を行うために、一度だけ起動されるPod初期化専用のコンテナです。Podには複数のコンテナを動かすことができますが、コンテナが起動する順番を制御することはできません。init Containersはアプリケーションのコンテナが起動する前に起動するので、Podの初期化処理を行わせることができます。init Containersは通常のアプリケーションコンテナと同様に複数のinit Containerを動かすことができます。ただし、アプリケーションコンテナとは異なり、起動順番が制御されていて、1つのinit Containerの完了をまってから次のinit Containerが起動します。
init Containerの順番が制御されているのか、確認をしてみましょう。確認のため、2つのinit Containerを含むPodを作成します。初期化処理として単純に5秒間sleepを行います。
kubectl apply
コマンドでPodを作成します。
コンテナの起動順番が制御されているかの確認を行います。Podの詳細情報で、コンテナの起動日時をみてみます。Podの詳細情報を確認するにはkubectl describe
コマンドを利用します。以下の実行例はコンテナの起動日時の部分だけを抜粋したものです。
コンテナの起動日時を見てみると、init1 → init2 → test-podの順番に起動されていて、コンテナの起動順番は守られていることが確認できます。init Containersであるinit1とinit2が平行に起動されていなく、init1の完了を待ってinit2が起動されています。アプリケーションコンテナであるtest-podは、すべてのinit Containerが完了したあとに起動していることが確認できました。
containers.lifecycle.postStartとの違いは?
コンテナのライフサイクルフックにpostStartがあります。postStartはコンテナが作成された直後に何かしらの処理を実行させることができます。ただし、"コンテナが作成された直後"のため、コンテナのENTRYPOINTの実行前にpostStartが実行される保証はありません。つまり、ENTRYPOINT実行前に初期化処理をする目的でpostStartを実行するには、ENTRYPOPINTが実行されたかの確認をpostStartのコマンド内で実装する必要があります。
これに対してinit Containersはアプリケーションコンテナの起動前に実行されるので、確実にアプリケーションコンテナのENTRYPOINT実行前に初期化処理を行うことができます。
Pythonの仮想環境をinit Containerで作ってみる
検証構成
検証にはDocker Desktop for WindowsのKubernetes環境を利用しました。
Pythonを動作させるアプリケーションサーバにはNginx Unitを利用しました。https://www.nginx.com/products/nginx-unit/
初期化処理の流れ
以下の初期化処理を行うPodを作成します。
init Conteiners
- GitHubからアプリケーションをcloneする。
- Pythonの仮想環境(venv)を作成する。
- Pythonの仮想環境を有効にする。
- pipでPythonのモジュール(Flask)をインストールする。
containers.lifecycle.postStart
- curlでNginx Unitの設定を反映する。
init Containerとアプリケーションコンテナで同じEmptyDirのボリュームをマウントすることで、init Containerで初期化した環境とアプリケーションをアプリケーションコンテナでも利用できるようにします。
ConfigMapを作成する
Nginx Unitの設定はConfigMapで定義しています。Pythonのアプリケーションは"path"に指定したディレクトリに配置します。今回の検証ではアプリケーションの配布をPodのinitContainersのgit cloneコマンドで行います。また、Python仮想環境のパスを"home"に設定しますが、Pythonの仮想環境もPodのinitContainersのコマンドで作成します。
ファイルを作成したら、kubectl apply
コマンドでConfigMapを作成します。
Podを作成する
Podの定義を行います。Podには初期化用のinit Containerとアプリケーション用のコンテナが含まれています。
init Containerで利用したpythonのベースイメージにはEntrypointは設定されていません。Entrypointが設定されていないので、initContainers.commandにPodの初期化処理を記述していきます。Gitのクローン元や必要なPythonパッケージは、利用する環境に合わせて修正してください。初期化処理の概要は、以下のコメントを参照してください。
init Containerでの初期化が完了した後、アプリケーションのコンテナが起動します。アプリケーションコンテナが起動するタイミングで、lifecycle.postStartでNginx Unitの設定を反映させています。postStartはコンテナのEntrypoint(プロセス実行)の前に実行される保証がないため、postStart内でNginx Unitの起動をwhileループで確認しています。Nginx Unitの起動を確認した後に、curlコマンドでNginx Unitへ設定を反映させます。
ファイルを作成したら、kubectl apply
コマンドでPodを作成します。
init ContainersによるPodの初期化処理が最初に実行されるため、Podの起動までに多少の時間がかかります。kubectl get pods
コマンドのSTATUSがInitの時は、初期化処理の実施中です。STATUSがRunningになれば、Podの起動が完了しています。
Serviceを作成する
アクセス確認をするためのServiceの設定を行います。今回の検証ではNodePortを利用しています。
ファイルを作成したら、kubectl apply
コマンドでServiceを作成します。
動作確認
http://localhost:30080にアクセスして、動作確認をしてみます。画面に'Hello, World!'と表示されれば、init Containersの初期化処理で作成したPythonの仮想環境上のFlaskアプリケーションが正常に動作しています。
Helm Chart
本記事ではPythonアプリケーションを直接kubectlコマンドでインストールする方法を紹介しました。別の方法としてHelmを利用してKubernetesにアプリケーションをインストールする方法もあります。
GitHub上にNginx Unit + PHPアプリケーション(Adminer)を、本記事と同様にinit Containerで初期化するHelm Chartを公開しています。Helm Chartを使ってinit Containerを実装する際の参考にしてください。
https://github.com/easydoggie/EasyDoggie/tree/master/adminer/adminer
Helmのインストール方法は、別記事を参照してください。
さいごに
KUbernetesのアプリケーション初期化処理の一つの方法として、init ContainersとpostStartの利用例を紹介しました。postStartは処理が実行されるタイミングがコンテナ作成直後で、Entrypointの前に実行される保証がないことに注意が必要です。Podの初期化処理は、確実に起動順番が制御できるinit Containersで実装できれば確実です。コンテナのライフサイクルや実行順番の保証などを意識して、安全かつ安心して運用できるコンテナを作っていきましょう。
投稿者プロフィール
最新の投稿
AWS2021年12月2日AWS Graviton3 プロセッサを搭載した EC2 C7g インスタンスが発表されました。
セキュリティ2021年7月14日ゼロデイ攻撃とは
セキュリティ2021年7月14日マルウェアとは
WAF2021年7月13日クロスサイトスクリプティングとは?