init コンテナとサイドカーの仕組み

v1.37 時点(2026年10月23日 確認)

Kubernetes 基本仕様第10回 / 全45回 ・ 第2部 ワークロード
目次

この記事では、準備や補助のために 1 つの Pod に入れるコンテナである init コンテナ と サイドカー の仕組みを、図で説明します。init コンテナはアプリケーションのコンテナより先に動いて終わり、サイドカーはアプリケーションのコンテナの横で動き続けます。2 つの違いと、Pod の中のコンテナが起動して止まる順番、コンテナどうしがファイルや通信を共有する方法がわかります。後半では kind のクラスタで init コンテナとサイドカーを持つ Pod を動かし、起動の順番と共有の様子を確かめる手順を示します。

Pod とコンテナの関係と、Pod の中のコンテナが共有するもの(ネットワークとボリューム)を扱った第8回の内容を前提にしています。restartPolicy による再起動と再起動までの待ち時間を扱った第9回の内容も使います。まだの方は先にこちらをどうぞ。

基本仕様 ・ 第8回 Pod を動かして理解するKubernetes で作って管理できる最小の単位である Pod の仕組みを図で説明します。Pod とコンテナの関係、Pod の中のコンテナが共有するもの、Pod が 1 つのノードに置かれて移らないことを押さえ、kind のクラスタで Pod を直接作って削除し、もう戻らないことを確かめる手順を紹介します。

以下の図は、この回の後半で動かす Pod の中の 3 つのコンテナと、それらが共有するものを表しています。

init コンテナ、サイドカー、アプリケーションコンテナと、それらが共有するボリュームとネットワーク

図の init コンテナ init-content は Pod の起動時にいちばん先に動き、ボリュームにファイルを書いて終わります。そのあとサイドカー sidecar が起動し、続いてアプリケーションのコンテナ nginx が起動します。nginx は init コンテナが書いたファイルをボリュームから読んで配信し、sidecar は同じ Pod の中から localhost で nginx に問い合わせます。init コンテナとアプリケーションのコンテナは同時には動かないので、データの受け渡しはボリュームを通した一方向になります。

参考:Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Pods | Kubernetes

init コンテナとサイドカーとは

第8回で見たとおり、Pod には 1 つ以上のコンテナを入れられます。公式ドキュメントはアプリケーションの処理を動かすコンテナを app container(以下、アプリケーションコンテナ)と呼び、init コンテナと区別しています。Pod にはアプリケーションコンテナのほかに、Pod の起動時に動く init コンテナも入れられます。v1.37 時点で、Pod のマニフェストに書くコンテナは次の 3 種類です。

種類書く場所動く期間
アプリケーションコンテナspec.containersふつうの init コンテナがすべて終わり、サイドカーが起動したあと、Pod が動いているあいだ
init コンテナspec.initContainersPod の起動時に 1 つずつ順に動き、それぞれ終わりまで動いて止まる
サイドカーspec.initContainers(コンテナごとの restartPolicy を Always にする)Pod の起動時に起動し、Pod が動いているあいだ動き続ける

参考:Pods | Kubernetes、Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Glossary | Kubernetes

init コンテナ は アプリケーションコンテナが起動する前に動き、終わりまで動いて止まる、準備のためのコンテナ です。公式ドキュメントによると、init コンテナはアプリケーションコンテナとほとんど同じですが、次の 2 点が違います。1 つは、init コンテナは終わることを前提にした処理を動かし、終わりまで動いて止まることです。もう 1 つは、init コンテナがいくつもあるとき、それぞれが成功して終わってから次の init コンテナが始まることです。init コンテナにはアプリケーションのイメージに入っていない道具や、準備のための処理を入れておけます。

参考:Init Containers | Kubernetes

サイドカーコンテナ(以下、サイドカー)は 同じ Pod の中で、メインのアプリケーションコンテナと一緒に動く、補助のためのコンテナ です。公式ドキュメントによると、サイドカーはログの記録、監視、セキュリティ、データの同期などの機能を、アプリケーションのコードを直接変えずに加えるために使います。公式ドキュメントによると、たいていは 1 つの Pod にアプリケーションコンテナは 1 つだけです。たとえば公式ドキュメントの Pods のページには、共有のボリュームにあるファイルを配信する Web サーバーのコンテナと、そのファイルを外から取ってきて更新するサイドカーの例があります。

参考:Sidecar Containers | Kubernetes、Pods | Kubernetes

Kubernetes はサイドカーを init コンテナの特別な場合として実装しています。spec.initContainers に書いたコンテナに、コンテナごとの restartPolicy として Always を指定すると、そのコンテナはサイドカーとして扱われ、Pod の起動後も動き続けます。公式ドキュメントは起動時にだけ動くふつうの init コンテナを regular init containers と呼んで、サイドカーと区別しています。この回でも、サイドカーではない init コンテナを「ふつうの init コンテナ」と呼びます。v1.37 時点の公式ドキュメントによると、サイドカーの機能(SidecarContainers)は v1.28 で初めて入り、v1.33 から正式(GA)の機能です。今は無効にできません。

参考:Sidecar Containers | Kubernetes、Pods | Kubernetes

公式ドキュメントの Pods のページは、このほかに、動いている Pod の調べものをするために一時的に入れる ephemeral container(エフェメラルコンテナ)も挙げています。公式ドキュメントによると、ephemeral container は pod.spec に直接書いて足すのではなく、API の専用の窓口を通して作るもので、自動では再起動されません。この回では扱いません。Pod の不具合の原因の調べ方は第41回で扱います。

参考:Pods | Kubernetes、Ephemeral Containers | Kubernetes

なぜ init コンテナとサイドカーが必要なのか

第8回で見たとおり、1 つの Pod に複数のコンテナを入れるのは、コンテナどうしが密に結び付いているときだけの、比較的高度な使い方です。公式ドキュメントによると、Pod が複数のコンテナを持てる主な理由は、メインのアプリケーションを手伝う補助のアプリケーションを支えることです。補助のアプリケーションの典型的な例として、データを取ってくるもの、データを送り出すもの、通信を中継するもの(プロキシ)が挙がっています。補助のアプリケーションとメインのアプリケーションは、多くの場合、共有のファイルシステム(ボリューム)か、localhost で互いにやり取りします。

参考:Communicate Between Containers in the Same Pod Using a Shared Volume | Kubernetes、Pods | Kubernetes

補助の処理をアプリケーションとは別のコンテナに分けると、それぞれを別々に扱えます。公式ドキュメントによると、サイドカーはアプリケーションのコードを直接変えずに機能を加えるためのもので、アプリケーションコンテナとは別の、独立したライフサイクルを持ちます。そのため、メインのアプリケーションに影響を与えずに、サイドカーを更新したり保守したりできます。

参考:Sidecar Containers | Kubernetes

init コンテナはアプリケーションの準備を、アプリケーションのイメージから切り離すためにあります。公式ドキュメントによると、init コンテナはアプリケーションコンテナとは別のイメージを使うので、アプリケーションのイメージを作る人と Pod を動かす人は、1 つのイメージを一緒に作らなくても、別々に作業できます。公式ドキュメントは init コンテナを使う利点として、このほかに次の 4 つを挙げています。

  • 準備にだけ使う道具(sed、awk、python、dig など)を、アプリケーションのイメージに入れずに済む
  • アプリケーションコンテナには見せない Secret に、init コンテナだけがアクセスできるようにできる
  • 決まった条件がそろうまで、アプリケーションコンテナの起動を止めておける
  • 要らない道具を分けておき、アプリケーションのイメージの攻撃される箇所(attack surface)を減らせる

参考:Init Containers | Kubernetes

sed、awk、python、dig は一般に、文字の置き換えや加工、スクリプトの実行、名前の問い合わせなどに使う道具です。Secret はパスワードなどの秘密の情報を入れておくリソースで、第18回で扱います。

参考:Init Containers | Kubernetes、Secrets | Kubernetes

公式ドキュメントには init コンテナの使い方の例として、Service(第21回)ができるまで待つ、Git のリポジトリをボリュームにコピーする、設定ファイルの値を埋めて作る、などが挙がっています。

参考:Init Containers | Kubernetes

サイドカーの仕組みが要るのは、補助のコンテナを起動や停止の順番まで含めて扱いたいときです。組み込みのサイドカーができる前は、補助のコンテナもアプリケーションコンテナと同じく spec.containers に並べていました(末尾の補足)。公式ドキュメントもコンテナごとの restartPolicy に対応していない古いバージョンの Kubernetes で動かす必要があるときは、init でもサイドカーでもない複数のコンテナを Pod で動かすこともできる、としています。公式ドキュメントによると、spec.containers に並べたアプリケーションコンテナは、init コンテナが終わったあと、すべて並行して起動できます。また、init でもサイドカーでもない複数のコンテナを Pod で動かすやり方は、どのコンテナが先に起動したり止まったりするかを制御しなくてよい場合に向いている、とされています。たとえば、アプリケーションが起動してすぐにログを書き出したときに、ログを扱う補助のコンテナがまだ受け取れる状態になっていない、ということも起こり得ると考えられます。

参考:Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Adopting Sidecar Containers | Kubernetes

公式ドキュメントは Kubernetes に組み込まれたサイドカーの利点として、次の 3 つを挙げています。

  • ほかの init コンテナより先に起動するようにできる
  • ほかのコンテナがすべて終わってから、最後に止まるようにできる
  • Job(第16回)のように終わりまで動いて止まる Pod で、サイドカーが Pod の完了を妨げない

組み込みではない以前のやり方のサイドカーでは、Job の完了に特別な配慮が要るとされています。

参考:Adopting Sidecar Containers | Kubernetes、Sidecar Containers | Kubernetes

init コンテナとサイドカーの仕組み

マニフェストに書く場所

以下は、冒頭の図の Pod のマニフェストです。init コンテナ init-content がボリュームに index.html を書き、サイドカー sidecar が localhost で nginx に問い合わせ続けます。ボリュームはそのディレクトリをコンテナの中の決まったパスから見えるようにして使います。これを「ボリュームをマウントする」と言います。後半の「手元で試す」でも、このマニフェストを使います。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: multi-demo
spec:
  initContainers:
  - name: init-content
    image: busybox:1.28
    command: ['sh', '-c', 'echo "Hello from the init container" > /work-dir/index.html; sleep 10']
    volumeMounts:
    - name: html
      mountPath: /work-dir
  - name: sidecar
    image: busybox:1.28
    restartPolicy: Always
    command: ['sh', '-c', 'while true; do wget -q -O- http://localhost:80/ || echo "nginx is not ready yet"; sleep 5; done']
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html
    emptyDir: {}

参考:Configure Pod Initialization | Kubernetes、Sidecar Containers | Kubernetes、Pod | Kubernetes API Reference

このマニフェストは公式ドキュメントの 2 つの例をもとに、名前やコマンドなどを変えたものです。Configure Pod Initialization のページの例では、busybox:1.28 の init コンテナが emptyDir のボリュームを /work-dir にマウントして index.html を書き、nginx のコンテナが同じボリュームを /usr/share/nginx/html にマウントして配信します。例の init コンテナは wget で外のサイトからページを取ってきますが、この回では echo で書くことにして、クラスタの外につながらなくても動くようにしました。nginx のイメージは第8回と同じく Pods のページの例のとおり nginx:1.14.2 にしています。Sidecar Containers のページの例は Deployment で、initContainers の項目に restartPolicy: Always を書いてサイドカーにしています。

参考:Configure Pod Initialization | Kubernetes、Sidecar Containers | Kubernetes、Pods | Kubernetes

sidecar を init-content の後ろに書いたのは、ふつうの init コンテナが終わるまでサイドカーが待つ様子を見るためです。init コンテナは書いた順に動くので、sidecar は init-content が終わってから起動します。公式ドキュメントの利点の 1 つ目のとおり、sidecar を前に書けば、init-content より先に起動します。

参考:Sidecar Containers | Kubernetes、Adopting Sidecar Containers | Kubernetes

この回で新しく使うフィールドを、v1.37 時点の API リファレンスに沿って次の表にまとめます。

フィールド内容
spec.initContainersPod に属する init コンテナの一覧。書いた順に、アプリケーションコンテナより先に動く。項目の書き方は spec.containers と同じ
spec.initContainers[*].restartPolicyコンテナごとの再起動の決まり。init コンテナで Always にすると、そのコンテナはサイドカーになる
spec.volumesPod のコンテナがマウントできるボリュームの一覧
spec.volumes[*].emptyDirPod と同じ期間だけ存在する、一時的なディレクトリのボリューム。{} は一般に、YAML で中身が空の項目を表す書き方で、ここでは emptyDir の設定(medium や sizeLimit)を何も指定しないことを表す
spec.containers[*].volumeMountsコンテナのファイルシステムにマウントするボリューム。name でボリュームを指し、mountPath でコンテナの中のパスを決める

参考:Pod | Kubernetes API Reference、Volumes | Kubernetes

公式ドキュメントによると、ボリュームを使うには、Pod に用意するボリュームを .spec.volumes に書き、コンテナのどこにマウントするかを volumeMounts に書きます。マウントする場所はコンテナごとに別々に指定します。この例では、同じボリューム html を、init-content は /work-dir に、nginx は /usr/share/nginx/html にマウントしています。パスが違っても、中身は同じディレクトリです。sidecar には volumeMounts を書いていないので、sidecar からはこのボリュームが見えません。

参考:Volumes | Kubernetes

emptyDir は名前のとおり空の状態で作られるボリュームです。公式ドキュメントによると、emptyDir は Pod がノードに割り当てられたときに作られ、Pod のすべてのコンテナが同じファイルを読み書きできます。Pod がノードから消えると、emptyDir のデータは完全に消えます。一方で、コンテナが異常終了しても Pod はノードから消えないので、データは残ります。ボリュームの種類は第26回で扱います。

参考:Volumes | Kubernetes

command の書き方は第9回と同じで、sh -c に渡した文字列を、シェルが ; で区切って順に実行します。init-content は echo で 1 行の文字を書き出し、> でその行を /work-dir/index.html に書き込み、10 秒待って終わります。> は一般に、コマンドが書き出す文字をファイルに書き込むシェルの記号です。10 秒待つのは、後半で init コンテナが動いている様子を観察しやすくするためです。sidecar は、while true; do ...; done で同じ処理を繰り返します(一般的なシェルの書き方です)。繰り返す処理は wget で http://localhost:80/ に問い合わせて、受け取った中身を書き出し、5 秒待つことです。wget は一般に、URL を指定してデータを取ってくるコマンドです。localhost は自分自身を指す名前で、同じ Pod のコンテナはネットワークを共有しているので(第8回)、http://localhost:80/ は同じ Pod の 80 番ポート、つまり nginx が待ち受けているポートを指します。wget に付けた -q -O- は公式ドキュメントの別の例でも busybox:1.28 で使われている指定です。一般に、-q は進み具合の表示を止め、-O- は受け取った中身をファイルではなく標準出力に書き出す指定です。問い合わせに失敗したときは、|| の後ろの echo で nginx is not ready yet を書き出します。|| は一般に、前のコマンドが失敗したときだけ後ろのコマンドを動かすシェルの記号です。

参考:Define a Command and Arguments for a Container | Kubernetes、HorizontalPodAutoscaler Walkthrough | Kubernetes、Pod | Kubernetes API Reference、Pods | Kubernetes

コンテナの名前は init コンテナも含めて Pod の中で一意にします。公式ドキュメントによると、ほかのコンテナと同じ名前のコンテナがあると、API がマニフェストを受け付けず、エラーを返します。また API リファレンスによると、Pod を作ったあとで init コンテナを足したり減らしたりはできません。第8回の補足のとおり、作ったあとで変えられるのは spec.initContainers[*].image などに限られます。

参考:Init Containers | Kubernetes、Pod | Kubernetes API Reference、Pods | Kubernetes

init コンテナの動き方

公式ドキュメントによると、Pod の起動時、kubelet はネットワークとストレージの準備ができるまで init コンテナの実行を待ちます。準備ができたら、kubelet は Pod の spec に書かれた順に init コンテナを動かします。それぞれの init コンテナが成功して終わってから、次の init コンテナが始まります。すべての init コンテナが終わると、kubelet はアプリケーションコンテナを用意して、いつもどおり動かします。条件がそろったあとは、Pod のアプリケーションコンテナはすべて並行して起動できます。この節の説明はふつうの init コンテナについてのものです。終わらないサイドカーがあるときは、ふつうの init コンテナがすべて終わり、サイドカーが起動したあとにアプリケーションコンテナが起動します(次の「サイドカーの動き方」で説明します)。

参考:Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Pods | Kubernetes

init コンテナが動いているあいだの Pod の様子を、次の表にまとめます。

項目init コンテナが動いているあいだ
Pod のフェーズ(第9回)Pending
Pod の Initialized の conditionFalse。kubelet は init コンテナがすべて成功して終わったあとに True にする
Pod の Ready の conditionすべての init コンテナが成功するまで Ready にならない
init コンテナの状態status.initContainerStatuses に、コンテナごとに記録される(アプリケーションコンテナの status.containerStatuses と同じ形)

参考:Init Containers | Kubernetes、Pod Lifecycle | Kubernetes

init コンテナが失敗したときに kubelet がどうするかは、Pod の spec.restartPolicy(第9回)で決まります。公式ドキュメントによると、ふつうの init コンテナには Pod の restartPolicy が適用されます。ただし Pod の restartPolicy が Always のとき、init コンテナには OnFailure が使われます。公式ドキュメントによると、init コンテナは成功すれば Pod の起動時に一度だけ動きます。Always のまま扱うと、成功して終わった init コンテナまで再起動されてしまうので、OnFailure が使われると考えられます。そのため、0 で終わって成功した init コンテナは、基本的には再起動されません(例外は少し後で説明します)。失敗したときの扱いを次の表にまとめます。

Pod の restartPolicyinit コンテナが失敗したとき
Always成功するまで init コンテナを再起動する(init コンテナには OnFailure が使われる)
OnFailure成功するまで init コンテナを再起動する
Never再起動しない。Pod 全体が失敗したものとして扱われる

参考:Init Containers | Kubernetes、Pod Lifecycle | Kubernetes

失敗を繰り返す init コンテナの再起動にも、第9回で見た待ち時間が入ります。公式ドキュメントによると、最初の失敗のあとの再起動には、倍々に延びる待ち時間が入ります。第9回で引用した kubectl describe pod の例も CrashLoopBackOff になった 2 つ目の init コンテナの表示でした。kubectl get pods の STATUS 列には Init:CrashLoopBackOff が表示されることがあります。init コンテナが成功しないかぎり、アプリケーションコンテナは起動しません。

参考:Pod Lifecycle | Kubernetes、Debug Init Containers | Kubernetes、Init Containers | Kubernetes

公式ドキュメントは、init コンテナがいつまでも失敗し続けないように、Pod の activeDeadlineSeconds を使う方法も挙げています。activeDeadlineSeconds は、Pod の開始時刻(status.startTime。第5回)から数えて、Pod が失敗として扱われてコンテナが止められるまでの秒数の上限です。ただし、activeDeadlineSeconds は init コンテナが終わったあとも効き続け、正しく動いている Pod も止めてしまいます。そのため公式ドキュメントはアプリケーションを Job(終わりまで動いて止まる処理のためのリソース。第16回)として動かす場合だけに使うよう勧めています。

参考:Init Containers | Kubernetes、Pod | Kubernetes API Reference

init コンテナは一度成功しても、また動くことがあります。公式ドキュメントによると、Pod が再起動(restart)されると、すべての init コンテナがもう一度動きます。ここでいう Pod の再起動は第8回で見た Pod の作り直し(別の UID の新しい Pod になること)とは別のものです。同じ Pod のまま、init コンテナから動かし直すことを指すと考えられます。公式ドキュメントは、Pod が再起動される理由として次の 2 つを挙げています。

  • Pod の土台になるコンテナ(Pod infrastructure container)が再起動された。まれなことで、ノードの管理者の権限(root)を持つ人が行う必要がある
  • Pod の restartPolicy が Always のときにすべてのコンテナが終了し、init コンテナが完了した記録もガベージコレクションで消えていた

参考:Init Containers | Kubernetes

ガベージコレクションは、Kubernetes がクラスタの要らなくなったものを片付ける仕組みの総称です。ここでは、終了した init コンテナの記録が片付けられることを指すと考えられます。公式ドキュメントの Garbage Collection のページによると、kubelet は使われていないコンテナを 1 分ごとに片付けます。どちらの理由も、ふだん利用者が自分で起こすものではないと考えられます。それでも init コンテナはもう一度動くことがあるので、公式ドキュメントは、init コンテナの処理は何度動いても同じ結果になるように書く よう求めています。とくに emptyDir に書き込む処理は、書き出すファイルがすでにあるかもしれないことに備える必要があります。この回の init-content は > で index.html を書きます。> は一般に、ファイルがすでにあれば中身を置き換えるので、何度動いても同じ中身のファイルになります。

参考:Garbage Collection | Kubernetes、Init Containers | Kubernetes

ふつうの init コンテナには、lifecycle、livenessProbe、readinessProbe、startupProbe のフィールドを使えません。lifecycle は、コンテナを作った直後や止める直前に決まった処理を動かす設定です。Probe はコンテナが正常かどうかを kubelet が定期的に確かめる仕組みで、第34回で扱います。公式ドキュメントは、init コンテナは Pod が Ready になる前に終わりまで動く必要があり、Pod が動いているあいだ動き続けるサイドカーとは違う、と説明しています。readinessProbe を使えない理由としては、init コンテナでは準備ができたこと(readiness)を、終わったこととは別に決められないから、としています。

参考:Init Containers | Kubernetes、Container Lifecycle Hooks | Kubernetes

サイドカーの動き方

サイドカーも init コンテナなので、ふつうの init コンテナと同じく spec.initContainers の順番に沿って起動します。違うのは、kubelet がサイドカーの終わりを待たずに次へ進むことです。公式ドキュメントによると、サイドカーが動き始めて、kubelet がそのコンテナの started の状態を true にすると、kubelet は一覧の次の init コンテナを起動します。started が true になるのは、startup Probe を定義していなければ、コンテナの中でプロセスが動いているときです。startup Probe を定義していれば、それが成功したときです。

参考:Sidecar Containers | Kubernetes、Pod | Kubernetes API Reference

公式ドキュメントの Pods のページによると、サイドカーとして定義したコンテナは、メインのアプリケーションより先に起動し、Pod が終了するまで動き続けます。Sidecar Containers のページによると、サイドカーはほかの init コンテナやアプリケーションコンテナから独立していて、それらに影響を与えずに起動、停止、再起動できます。たとえば公式ドキュメントによると、サイドカーのイメージを変えると、Pod は再起動されず、サイドカーのコンテナが再起動されます。

参考:Pods | Kubernetes、Sidecar Containers | Kubernetes

第9回で見たとおり、サイドカーは Pod の restartPolicy に関係なく再起動されます。公式ドキュメントによると、サイドカーは Pod の restartPolicy を無視し、コンテナごとの restartPolicy(Always)に従います。第9回では、公式ドキュメントの Pod Lifecycle のページにある終了コードごとの比較の表から、アプリケーションコンテナの部分を引きました。同じ表にはサイドカーの列もあり、合わせると次のとおりです。

終了コードPod が AlwaysPod が OnFailurePod が Neverサイドカー
0(成功)再起動する再起動しない再起動しない必ず再起動する(アプリケーションコンテナが動いているあいだ)
0 以外(失敗)再起動する再起動する再起動しない必ず再起動する(アプリケーションコンテナが動いているあいだ)

参考:Pod Lifecycle | Kubernetes

Pod の Always、OnFailure、Never の列は、アプリケーションコンテナの扱いです。公式ドキュメントは Pod のコンテナの再起動に、倍々に延びる待ち時間が入ると説明しており、サイドカーもこれに当たります。API リファレンスによると、サイドカーは、アプリケーションコンテナがすべて終了するまで、終了するたびに再起動されます。アプリケーションコンテナがすべて終わると、サイドカーはすべて止められます。

参考:Pod | Kubernetes API Reference、Pod Lifecycle | Kubernetes、Adopting Sidecar Containers | Kubernetes

Pod が終了するときの順番も決まっています。公式ドキュメントによると、Pod にサイドカーがあると、kubelet は最後のアプリケーションコンテナが止まりきるまで、サイドカーに TERM シグナル(第8回)を送るのを待ちます。そのあとサイドカーは Pod の spec に書かれたのと逆の順番で止められます。サイドカーはほかのコンテナに必要とされなくなるまで動き続けるということです。アプリケーションコンテナが止まるのに時間がかかると、サイドカーが止まるのも遅れます。止まりきる前に猶予の時間(既定は 30 秒。第8回)が過ぎると、Pod は強制的な終了に移ることがあります。このとき、残っているコンテナは一斉に止められます。公式ドキュメントはこのときの猶予の時間を「短い」とだけ説明していて、この場面での長さは書かれていません。

参考:Pod Lifecycle | Kubernetes、Sidecar Containers | Kubernetes

サイドカーは最後に止められるので、止める番が来たときには猶予の時間がほとんど残っていないことがあります。公式ドキュメントによると、ほかのコンテナが猶予の時間を使い切ると、サイドカーは TERM シグナルを受けたあと、きれいに終わる前に KILL シグナル(強制的に止める合図)を受けます。そのため、Pod が終了するときにサイドカーが 0 以外の終了コードで終わっても、多くの場合、問題ではありません。公式ドキュメントは、Pod が終了するときのサイドカーの 0 以外の終了コードはよくあることで、Kubernetes の外のツール(external tooling)では基本的に無視してよい、としています。外のツールには、たとえばコンテナの終了コードを見張る監視のツールなどが当たると考えられます。

参考:Sidecar Containers | Kubernetes

サイドカーはふつうの init コンテナと違って Probe を使えます。公式ドキュメントによると、サイドカーに readiness Probe を定義すると、その結果が Pod の Ready の判断に使われます。また、Job の Pod では、アプリケーションコンテナが終わったあと、サイドカーが Job の完了を妨げることはありません。公式ドキュメントには、Pod の restartPolicy が Never の Job にサイドカーを入れた例があります。

参考:Sidecar Containers | Kubernetes、Init Containers | Kubernetes

起動から終了までの順番

以下の図は、この回のマニフェストの Pod が起動してから削除されるまでに、コンテナが動く順番をコマ送りで表しています。図ではノードと kube-apiserver を省き、Pod の中だけを描いています。どのコンテナも、起動したり止めたりするのはノードの kubelet です。各箱の 3 行目はそのコマでのコンテナの状態です。そのコマで変わったものは緑の太字にし、動いていないコンテナは薄く描いています。

(初期)Pod がノードに割り当てられ、空の emptyDir のボリューム html ができる。コンテナはまだどれも動いていない。sidecar と nginx は、init コンテナが終わるのを待つ
(1/4)kubelet が init-content を起動する。init-content は html に index.html を書く。sidecar と nginx は、init-content が終わるのを待っている
(2/4)init-content が成功して終わると、kubelet が sidecar を起動する。sidecar は終わらずに動き続ける
(3/4)sidecar が起動したあと、kubelet が nginx を起動する。nginx は html の index.html を配信し、sidecar は localhost で nginx に問い合わせる
(4/4)Pod を削除すると、kubelet はまず nginx を止める。nginx が止まりきると、kubelet は sidecar に TERM シグナルを送って止める

ふつうの init コンテナ(init-content)は終わるまで次へ進ませません。サイドカー(sidecar)は起動したところで次へ進ませ、そのあとも動き続けます。止まる順番は起動と逆で、サイドカーはアプリケーションコンテナより後に止まります。

参考:Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Pod Lifecycle | Kubernetes、Volumes | Kubernetes

コンテナどうしが共有するもの

第8回で見たとおり、Pod の中のコンテナはネットワーク(IP アドレスとポート)とボリュームを共有できます。公式ドキュメントによると、init コンテナもアプリケーションコンテナと同じ資源(CPU、メモリ、ネットワーク)を使いますが、アプリケーションコンテナと直接やり取りはしません。init コンテナはアプリケーションコンテナが起動する前に止まるからです。そのため、init コンテナからのデータの受け渡しは一方向で、たとえば emptyDir のボリュームに情報を置く形になります。

参考:Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Pods | Kubernetes

サイドカーはアプリケーションコンテナと同時に動くので、直接やり取りできます。公式ドキュメントによると、サイドカーは init コンテナと同じく常にネットワークを共有し、必要ならボリューム(ファイルシステム)も共有できます。この回のマニフェストでは、sidecar はネットワークを共有しているので、localhost で nginx に届きます。

参考:Sidecar Containers | Kubernetes、Pods | Kubernetes

ここまでの 3 種類のコンテナの違いを、次の表にまとめます。

項目ふつうの init コンテナサイドカーアプリケーションコンテナ
動く期間起動時に 1 つずつ動き、終わる起動時に起動し、Pod の終了まで動き続けるふつうの init コンテナがすべて終わり、サイドカーが起動したあとに起動し、動き続ける
再起動失敗したときだけ(Pod が Never なら再起動しない)終了コードに関係なく必ず再起動するPod の restartPolicy に従う(コンテナごとに指定しなければ)
Probe使えない使える使える
アプリケーションコンテナとのやり取りボリュームを通した一方向だけネットワークで直接。ボリュームも共有できる同じ Pod のほかのコンテナと localhost で通信できる

参考:Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Pod Lifecycle | Kubernetes、Pods | Kubernetes

手元で試す

ここまでの内容を手元の kind のクラスタで試す手順を示します。「マニフェストに書く場所」の Pod を作り、init コンテナ、サイドカー、アプリケーションコンテナが順に起動する様子を観察します。そのあと、init コンテナが書いたファイルを nginx が読めることと、サイドカーが localhost で nginx に届くことを確かめます。コマンドは macOS や Linux のシェル(bash や zsh)で実行する前提で書いています。Windows では WSL(Windows の中で Linux を動かす仕組み)などを使ってください。試す環境は次のとおりです。

項目内容
kindv0.33.0
Kubernetesv1.37.0(kind v0.33.0 の既定のノードイメージ)
ノード構成シングルノード(クラスタ名 kind):コントロールプレーン 1
必要なものDocker、kubectl(v1.36〜v1.38)

参考:Release v0.33.0 · kubernetes-sigs/kind、Version Skew Policy | Kubernetes

kind でクラスタを作る手順は、以下の記事で解説しています。この回ではシングルノードのクラスタを使います。Pod の中のコンテナは同じノードで動くので、この回の内容はノードの数に関係しないからです。

基本仕様 ・ 第2回 kind で検証用のクラスタを作るDocker のコンテナをノードにして、手元のマシンに Kubernetes のクラスタを作るツール kind の仕組みを図で説明します。kind create cluster で何が起きるかを押さえ、シングルノードとマルチノードのクラスタを作って、ノードの正体が Docker のコンテナであることを確かめる手順を紹介します。

シングルノードのクラスタを用意する

まず、前の回のクラスタが残っていないかを確かめます。

console
$ kind get clusters

kind が表示されたら、作り直さずにそのまま使えるので、クラスタを作る次のコマンドは飛ばします。表示されなければ、クラスタを作ってから、もう一度一覧します。

console
$ kind create cluster
$ kind get clusters

kind get clusters に kind が表示されれば、クラスタができています。第3回で決めたとおり、ここからのコマンドには --context kind-kind を付けて、操作するクラスタをはっきりさせます。

参考:Quick Start | kind

続けて、ノードを一覧します。

console
$ kubectl get nodes --context kind-kind

ノードが 1 つ表示され、STATUS 列が Ready になっていれば準備ができています。Ready になっていなければ、少し待ってからもう一度実行します。

参考:kubectl get | Kubernetes、Node Status | Kubernetes

起動の順番を観察する

「マニフェストに書く場所」のマニフェストを、multi-demo.yaml という名前で、コマンドを実行するディレクトリに保存します。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: multi-demo
spec:
  initContainers:
  - name: init-content
    image: busybox:1.28
    command: ['sh', '-c', 'echo "Hello from the init container" > /work-dir/index.html; sleep 10']
    volumeMounts:
    - name: html
      mountPath: /work-dir
  - name: sidecar
    image: busybox:1.28
    restartPolicy: Always
    command: ['sh', '-c', 'while true; do wget -q -O- http://localhost:80/ || echo "nginx is not ready yet"; sleep 5; done']
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html
    emptyDir: {}

参考:Configure Pod Initialization | Kubernetes、Sidecar Containers | Kubernetes

Pod を作り、すぐに Pod の監視を始めます。第3回で見たとおり、--watch を付けると、一覧を表示したあとも変化を追い続けます。

console
$ kubectl apply -f multi-demo.yaml --context kind-kind
$ kubectl get pods --watch --context kind-kind

参考:kubectl get | Kubernetes

multi-demo の行が、状態が変わるたびに書き足されていくはずです。init コンテナを持つ Pod では、STATUS 列に init コンテナの進み具合が表示されます。公式ドキュメントの例(2 つの init コンテナを持つ Pod が、1 つ目の init コンテナを待っているときに、kubectl get -f myapp.yaml で表示した例)では、表示は次のとおりです。

NAME        READY     STATUS     RESTARTS   AGE
myapp-pod   0/1       Init:0/2   0          6m

参考:Init Containers | Kubernetes

公式ドキュメントの Debug Init Containers のページは、init コンテナを調べるときに STATUS 列に表示されることがある値を、次のように説明しています。

STATUS 列の値意味
Init:N/MPod に init コンテナが M 個あり、そのうち N 個が終わった
Init:Errorinit コンテナが失敗した
Init:CrashLoopBackOffinit コンテナが失敗を繰り返している
PendingPod は、まだ init コンテナを動かし始めていない
PodInitializing または RunningPod は、init コンテナを動かし終えた

参考:Debug Init Containers | Kubernetes

第9回で見たとおり、STATUS 列は Pod のフェーズそのものではありません。表の Pending も「init コンテナをまだ動かし始めていない」という kubectl の表示で、init コンテナが動いているあいだも続くフェーズの Pending とは意味が違います。

参考:Pod Lifecycle | Kubernetes、Debug Init Containers | Kubernetes

手元では、STATUS 列が Pending や Init:0/2 から始まり、PodInitializing などを経て、Running になると考えられます。Init:0/2 の 2 は initContainers に書いた 2 つ(init-content と sidecar)と考えられますが、表の説明はふつうの init コンテナを前提にしたものです。サイドカーがどう数えられるかは、公式ドキュメントからは確かめられませんでした。そのため、途中で Init:1/2 などが表示されることも、されないこともあると考えられます。途中の値が違っていても、最後に Running になれば問題ありません。READY 列も、サイドカーを数に入れるかどうかが公式ドキュメントで確かめられないので、この手順では見るところにしません。init-content は 10 秒待ってから終わるので、Init:0/2 の行はしばらく続くはずです。クラスタを作り直したばかりなら、busybox:1.28 と nginx:1.14.2 のイメージの取得にも時間がかかります(第9回)。Running になったら、Ctrl+C を押して監視を止めます。

参考:Debug Init Containers | Kubernetes、Init Containers | Kubernetes、Images | Kubernetes

コンテナごとの状態と起動の時刻を確かめる

Pod を詳しく表示します。

console
$ kubectl describe pod multi-demo --context kind-kind

手元では、Init Containers: の下に init-content: と sidecar: が、Containers: の下に nginx: が並ぶと考えられます。公式ドキュメントの例(2 つの init コンテナを持つ別の Pod myapp-pod を表示した例)では、表示の一部は次のとおりです。

Name:          myapp-pod
Namespace:     default
[...]
Labels:        app.kubernetes.io/name=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
[...]

参考:Init Containers | Kubernetes

例は 1 つ目の init コンテナが動いている途中の表示で、Status: は Pod のフェーズの Pending です。init コンテナは Init Containers: の下に、アプリケーションコンテナは Containers: の下に並びます。手元の Pod は Running になったあとなので、表示は例と違うはずです。見るところを次の表にまとめます。

見るところ表示されると考えられること
Init Containers: の init-content:State: が Terminated で、Reason: は Completed、Exit Code: は 0(成功して終わったため)
Init Containers: の sidecar:State: が Running(サイドカーは initContainers に書いたので、ここに並ぶと考えられる)
Containers: の nginx:State: が Running

参考:Debug Init Containers | Kubernetes、Init Containers | Kubernetes、Sidecar Containers | Kubernetes

Completed と Exit Code: 0 は公式ドキュメントの Debug Init Containers のページの例で、成功して終わった init コンテナに表示されている値です。

参考:Debug Init Containers | Kubernetes

次に、起動の順番を時刻で確かめます。init-content が終わった時刻、sidecar が起動した時刻、nginx が起動した時刻を取り出します。-o jsonpath は第5回で使った、フィールドを指定して取り出す出力の形式です。[?(@.name=="init-content")] は、一覧の中から name が init-content の項目だけを選ぶ指定(filter)です。{"\n"} の手前に書いた init-content finished: などの文字はそのまま表示されます。

console
$ kubectl get pod multi-demo -o jsonpath='init-content finished: {.status.initContainerStatuses[?(@.name=="init-content")].state.terminated.finishedAt}{"\n"}sidecar started: {.status.initContainerStatuses[?(@.name=="sidecar")].state.running.startedAt}{"\n"}nginx started: {.status.containerStatuses[?(@.name=="nginx")].state.running.startedAt}{"\n"}' --context kind-kind

参考:JSONPath Support | Kubernetes、Pod | Kubernetes API Reference

取り出しているフィールドを次の表にまとめます。

フィールド表すもの
status.initContainerStatusesinit コンテナ(サイドカーを含む)ごとの状態の一覧
status.containerStatusesアプリケーションコンテナごとの状態の一覧
state.terminated.finishedAt終了したコンテナが、最後に終了した時刻
state.running.startedAt動いているコンテナが、最後に起動(再起動)した時刻

参考:Pod | Kubernetes API Reference、Init Containers | Kubernetes

3 行の時刻は上から順に同じか後になっているはずです。kubelet は init-content が成功して終わってから sidecar を起動し、sidecar が起動してから nginx を起動するからです。sidecar や nginx が再起動していれば、表示されるのは再起動した時刻です。

参考:Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Pod | Kubernetes API Reference

続けて、Pod の Initialized の condition を取り出します。

console
$ kubectl get pod multi-demo -o jsonpath='{.status.conditions[?(@.type=="Initialized")].status}{"\n"}' --context kind-kind

True が表示されると考えられます。公式ドキュメントは Initialized を「すべての init コンテナが成功して終わった」ことを表す condition と説明しています。ただしこの説明は終わらないサイドカーを前提にしていません。サイドカーがあるときに、いつ True になるかは公式ドキュメントに書かれていません。nginx が起動したあとなので True になっていると考えられますが、推測です。

参考:Pod Lifecycle | Kubernetes、JSONPath Support | Kubernetes

ボリュームでファイルを共有していることを確かめる

nginx のコンテナの中で、init コンテナが書いたファイルを表示します。kubectl exec はコンテナの中でコマンドを動かすコマンドで、-c で動かすコンテナを指定します。-- の後ろがコンテナの中で動かすコマンドです。cat は一般に、ファイルの中身を表示するコマンドです。

console
$ kubectl exec multi-demo -c nginx --context kind-kind -- cat /usr/share/nginx/html/index.html

参考:kubectl exec | Kubernetes

Hello from the init container の 1 行が表示されるはずです。init-content が自分の /work-dir に書いたファイルが、nginx の /usr/share/nginx/html から見えています。2 つのコンテナは同じ emptyDir のボリューム html を、別々のパスにマウントしているからです。init-content はもう終わっているので、Pod の中で今も動いているのは sidecar と nginx です。

参考:Volumes | Kubernetes、Configure Pod Initialization | Kubernetes

リファレンスによると、-c を書かなかった場合、kubectl exec は kubectl.kubernetes.io/default-container のアノテーションで指定されたコンテナか、Pod の最初のコンテナ(the first container in the pod)を選びます。コンテナが複数ある Pod では、-c でコンテナを指定するのが確実です。

参考:kubectl exec | Kubernetes

localhost で通信していることを確かめる

サイドカーのログを表示します。kubectl logs の -c もログを表示するコンテナを指定するものです。リファレンスによると、Pod にコンテナが 1 つしかないときは、コンテナの名前を省略できます。この Pod はコンテナが複数あるので、-c sidecar を付けます。

console
$ kubectl logs multi-demo -c sidecar --context kind-kind

参考:kubectl logs | Kubernetes

Hello from the init container の行が、5 秒ごとに書き足されて並んでいるはずです。sidecar が localhost:80 に問い合わせ、nginx が index.html の中身を返しているからです。最初の何行かは nginx is not ready yet などの失敗の行になっていることもあると考えられます。sidecar は nginx より先に起動するので、nginx がまだ待ち受けていないうちに問い合わせることがあるからです。サイドカーがアプリケーションコンテナより先に動くことを前提に、補助の処理を書く必要があるとわかります。

参考:Pods | Kubernetes、Sidecar Containers | Kubernetes

このログには init コンテナ、ボリューム、アプリケーションコンテナ、サイドカーの 4 つがすべて関わっています。init-content がボリュームに書いたファイルを、nginx が読んで返し、それを sidecar が localhost で受け取っています。sidecar にはボリュームをマウントしていないので、sidecar がファイルの中身を知る方法は、nginx に問い合わせることだけです。ログを追い続けたいときは、-f を付けると新しい行が出るたびに表示されます。止めるときは Ctrl+C を押します。

参考:kubectl logs | Kubernetes、Volumes | Kubernetes

片付け

作った Pod を、マニフェストを指定して削除し、消えたことを確かめます。

console
$ kubectl delete -f multi-demo.yaml --context kind-kind
$ kubectl get pods --context kind-kind

削除すると、kubelet は先に nginx を止め、nginx が止まりきってから sidecar を止めます。kubectl delete は既定では、Pod が消えるまで待ってから終わります。猶予の時間(既定では 30 秒)が過ぎるまで待つことがあります。kubectl get pods の一覧に multi-demo が無ければ、削除できています。Pod がノードから消えたので、emptyDir のボリュームのデータも消えています。

参考:Pod Lifecycle | Kubernetes、kubectl delete | Kubernetes、Volumes | Kubernetes

最後に、クラスタを削除し、消えたことを確かめます。

console
$ kind delete cluster
$ kind get clusters

kind delete cluster は存在しないクラスタを指定してもエラーを返しません。kind get clusters に kind が表示されなくなったことを確かめます。kubeconfig に kind-kind のコンテキストが残っていたら、第3回の片付けと同じく kubectl config delete-context kind-kind で消します。

参考:Quick Start | kind、kubectl config | Kubernetes

注意点

init コンテナとサイドカーでつまずきやすい点と、後から変えられない点、バージョンで変わる点を、次の表にまとめます。

項目内容
サイドカーは initContainers に書くcontainers に並べたコンテナは、起動や停止の順番を制御しない。サイドカーにするには initContainers の項目に restartPolicy: Always を書く
init コンテナは何度も動くことがあるPod が再起動されると、すべての init コンテナがもう一度動く。何度動いても同じ結果になるように書き、emptyDir に書くときはファイルがすでにある場合に備える
init コンテナが失敗するとアプリケーションは起動しない成功するまで再起動される。Pod の restartPolicy が Never なら、Pod 全体が失敗として扱われる
ふつうの init コンテナは Probe を使えないlifecycle、livenessProbe、readinessProbe、startupProbe を書けない。サイドカーは Probe を使える
サイドカーはアプリケーションより先に動くサイドカーはアプリケーションコンテナより先に起動する。アプリケーションコンテナがまだ待ち受けていないことがあると考えて、補助の処理を書く
終了時のサイドカーの終了コードは気にしないPod が終了するとき、ほかのコンテナが猶予の時間を使い切ると、サイドカーは強制的に止められる。0 以外の終了コードはよくあること
コンテナの一覧は後から変えられないinit コンテナもアプリケーションコンテナも、Pod を作ったあとで足したり減らしたりはできない
資源の計算は、コンテナを足し合わせるだけではないinit コンテナは順に 1 つずつ動くので、Pod の資源の要求は、おおまかには、init コンテナの中の最大値と、アプリケーションコンテナとサイドカーの合計の大きいほうで計算される(第29回)
サイドカーは v1.33 から GAv1.28 で初めて入った機能。古いバージョンのクラスタや、新しいフィールドに対応していないツールでは、正しく動かないことがある

参考:Init Containers | Kubernetes、Sidecar Containers | Kubernetes、Pod Lifecycle | Kubernetes、Pod | Kubernetes API Reference、Adopting Sidecar Containers | Kubernetes

関連記事

Pod の数を一定に保つ ReplicaSet と、ReplicaSet が Pod を選ぶラベルセレクタについては、以下の記事で解説しています。

基本仕様 ・ 第11回 ReplicaSet を動かして理解する同じ Pod を指定した数だけ動かし続ける ReplicaSet の仕組みを図で説明します。ReplicaSet がラベルセレクタで Pod を選んで数える決まり、自分のものにする Pod の条件、数を減らすときに消す Pod の選び方を押さえ、kind のクラスタでラベルを書き換えた Pod が管理から外れる様子を観察する手順を紹介します。

Pod のフェーズ、コンテナの状態、restartPolicy による再起動の仕組みについては、以下の記事で解説しています。

基本仕様 ・ 第9回 Pod のライフサイクルと再起動の仕組みPod のフェーズ、コンテナの 3 つの状態、restartPolicy によるコンテナの再起動の仕組みを図で説明します。CrashLoopBackOff の意味と、再起動までの待ち時間が延びていく仕組みを押さえ、kind のクラスタでわざと失敗するコンテナを動かして、状態の移り変わりを観察する手順を紹介します。

この回で使った emptyDir などのボリュームの種類については、以下の記事で解説しています。

基本仕様 ・ 第26回 ・ 準備中 emptyDir と hostPath の違い 公開したら、ここから読めるようになります。

Kubernetes 基本仕様の目次へ