Black lives matter.
We stand in solidarity with the Black community.
Racism is unacceptable.
It conflicts with the core values of the Kubernetes project and our community does not tolerate it.
We stand in solidarity with the Black community.
Racism is unacceptable.
It conflicts with the core values of the Kubernetes project and our community does not tolerate it.
このページでは、Initコンテナについて概観します。Initコンテナとは、アプリケーションコンテナの前に実行され、アプリケーションコンテナのイメージに存在しないセットアップスクリプトやユーティリティーを含んだ特別なコンテナです。
この機能はKubernetes1.6からβ版の機能として存在しています。InitコンテナはPodSpec内で、アプリケーションのcontainers
という配列と並べて指定されます。そのベータ版のアノテーション値はまだ扱われ、PodSpecのフィールド値を上書きします。しかしながら、それらはKubernetesバージョン1.6と1.7において廃止されました。Kubernetesバージョン1.8からはそのアノテーション値はサポートされず、PodSpecフィールドの値に変換する必要があります。
単一のPodは、Pod内に複数のコンテナを稼働させることができますが、Initコンテナもまた、アプリケーションコンテナが稼働する前に1つまたは複数稼働できます。
Initコンテナは下記の項目をのぞいて、通常のコンテナと全く同じものとなります。
もしあるPodの単一のInitコンテナが失敗した場合、KubernetesはInitコンテナが成功するまで何度もそのPodを再起動します。しかし、もしそのPodのrestartPolicy
がNever
の場合、再起動されません。
単一のコンテナをInitコンテナとして指定するためには、PodSpecにそのアプリケーションのcontainers
配列と並べて、initContainers
フィールドをContainer型のオブジェクトのJSON配列として指定してください。
Initコンテナのステータスは、.status.initContainerStatuses
フィールドにコンテナのステータスの配列として返されます(.status.containerStatuses
と同様)。
Initコンテナは、リソースリミット、ボリューム、セキュリティ設定などのアプリケーションコンテナの全てのフィールドと機能をサポートしています。しかし、Initコンテナに対するリソースリクエストやリソースリミットの扱いは微妙に異なり、下記のResourcesにて説明します。また、InitコンテナはそのPodの準備ができる前に完了しなくてはならないため、readinessProbe
をサポートしていません。
もし複数のInitコンテナが単一のPodに対して指定された場合、それらのInitコンテナは1つずつ順番に実行されます。各Initコンテナは次のコンテナが完了できる前に完了しなくてはなりません。全てのInitコンテナが実行完了した時、KubernetesはPodを初期化し、通常通りアプリケーションコンテナを稼働させます。
Initコンテナはアプリケーションコンテナのイメージとは分離されているため、コンテナの起動に関連したコードにおいていくつかの利点があります。
sed
、awk
、python
や、dig
のようなツールを使うための他のイメージから、アプリケーションのイメージを作る必要がなくなります。ここではInitコンテナの使用例を挙げます。
シェルコマンドを使って単一のServiceが作成されるのを待機します。
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
コマンドを使って下位のAPIからこのPodをリモートサーバに登録します。
`curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'`
sleep 60
のようなコマンドを使ってアプリケーションコンテナが起動する前に待機します。
ボリュームにあるgitリポジトリをクローンします。
メインのアプリケーションコンテナのための設定ファイルを動的に生成するために、いくつかの値を設定ファイルに移してテンプレートツールを稼働させます。例えば、設定ファイルにそのPodのPOD_IPを移して、Jinjaを使ってメインのアプリケーションコンテナの設定ファイルを生成します。
さらに詳細な使用例は、StatefulSetsのドキュメントとProduction Pods guideにまとまっています。
下記のKubernetes1.5用のyamlファイルは、2つのInitコンテナを含む単一のシンプルなポッドの概要となります。
最初のInitコンテナの例は、myservies
、2つ目のInitコンテナはmydb
の起動をそれぞれ待ちます。2つのコンテナの実行が完了するとPodの起動が始まります。
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
annotations:
pod.beta.kubernetes.io/init-containers: '[
{
"name": "init-myservice",
"image": "busybox:1.28",
"command": ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
},
{
"name": "init-mydb",
"image": "busybox:1.28",
"command": ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
}
]'
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
古いアノテーション構文がKubernetes1.6と1.7において有効ですが、1.6では新しい構文にも対応しています。Kubernetes1.8以降では新しい構文を使用する必要があります。KubernetesではInitコンテナの宣言をspec
に移行させました。
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
Kubernetes1.5での構文は1.6においても稼働しますが、1.6の構文の使用を推奨します。Kubernetes1.6において、API内でInitコンテナのフィールド作成されます。ベータ版のアノテーションはKubernetes1.6と1.7において有効ですが、1.8以降ではサポートされません。
下記のyamlファイルはmydb
とmyservice
というServiceの概要です。
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
このPodは、下記のコマンドによって起動とデバッグすることが可能です。
kubectl apply -f myapp.yaml
pod/myapp-pod created
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
kubectl describe -f myapp.yaml
Name: myapp-pod
Namespace: default
[...]
Labels: app=myapp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
kubectl logs myapp-pod -c init-myservice # 1つ目のInitコンテナを調査する
kubectl logs myapp-pod -c init-mydb # 2つ目のInitコンテナを調査する
一度mydq
とmyservice
Serviceを起動させると、Initコンテナが完了してmyapp-pod
が作成されるのを確認できます。
kubectl apply -f services.yaml
service/myservice created
service/mydb created
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
この例は非常にシンプルですが、ユーザー独自のInitコンテナを作成するためのインスピレーションを提供するでしょう。
単一のPodが起動している間、ネットワークとボリュームが初期化されたのちに、Initコンテナは順番に起動されます。各Initコンテナは次のInitコンテナが起動する前に完了しなくてはなりません。もしあるInitコンテナがランタイムもしくはエラーにより起動失敗した場合、そのPodのrestartPolicy
の値をもとにリトライされます。しかし、もしPodのrestartPolicy
がAlways
に設定されていた場合、そのInitコンテナのrestartPolicy
はOnFailure
となります。
Podは全てのInitコンテナが完了するまでReady
状態となりません。Initコンテナ上のポートはServiceによって集約されません。初期化中のPodのステータスはPending
となりますが、Initializing
という値はtrueとなります。
もしそのPodが再起動されたとき、全てのInitコンテナは再度実行されなくてはなりません。
Initコンテナのスペックに対する変更はコンテナのイメージフィールドのみに限定されます。 Initコンテナのイメージフィールド値の変更は、そのPodの再起動することと等しいです。
Initコンテナは何度も再起動、リトライ可能なため、べき等(Idempotent)である必要があります。特に、EmptyDirs
にファイルを書き込むコードは、書き込み先のファイルがすでに存在している可能性を考慮に入れるべきです。
Initコンテナはアプリケーションコンテナの全てのフィールドを持っています。しかしKubernetesは、Initコンテナが完了と異なる状態を定義できないためreadinessProbe
が使用されることを禁止しています。これはバリデーションの際に強要されます。
Initコンテナがずっと失敗し続けたままの状態を防ぐために、PodにactiveDeadlineSeconds
、コンテナにlivenessProbe
の設定をそれぞれ使用してください。activeDeadlineSeconds
の設定はInitコンテナにも適用されます。
あるPod内の各アプリケーションコンテナとInitコンテナの名前はユニークである必要があります。他のコンテナと同じ名前を共有していた場合、バリデーションエラーが返されます。
Initコンテナの順序と実行を考えるとき、リソースの使用に関して下記のルールが適用されます。
クォータとリミットは有効なPodリクエストとリミットに基づいて適用されます。
Podレベルのcgroupsは、スケジューラーと同様に、有効なPodリクエストとリミットに基づいています。
単一のPodは再起動可能で、Initコンテナの再実行も引き起こします。それらは下記の理由によるものです。
restartPolicy
がAlways
と設定されているとき、単一Pod内の全てのコンテナが停止され、再起動が行われた時と、ガーベージコレクションによりInitコンテナの完了記録が失われた場合。ApiServerのバージョン1.6.0かそれ以上のバージョンのクラスターは、.spec.initContainers
フィールドを使ったInitコンテナの機能をサポートしています。
それ以前のバージョンでは、α版かβ版のアノテーションを使ってInitコンテナを使用できます。また、.spec.initContainers
フィールドは、Kubernetes1.3.0かそれ以上のバージョンでInitコンテナを使用できるようにするためと、ApiServerバージョン1.6において、1.5.xなどの古いバージョンにロールバックできるようにするために、α版かβ版のアノテーションにミラーされ、存在するPodのInitコンテナの機能が失われることが無いように安全にロールバックできるようにします。
ApiServerとKubeletバージョン1.8.0かそれ以上のバージョンでは、α版とβ版のアノテーションは削除されており、廃止されたアノテーションは.spec.initContainers
フィールドへの移行が必須となります。