Kubernetes 1.33でStableになったサイドカーコンテナとは?
この記事を執筆している2025年9月7日現在、Amazon Elastic Kubernetes Service(EKS)では、Kubernetes 1.33がサポートされる最新の利用可能バージョンです。
Kubernetes 1.33ではサイドカーパターンを実現するための、サイドカーコンテナという機能がStableに昇格しました。
しかし、サイドカーパターン自体は特に目新しいものではありません。サイドカーパターンは分散システムにおけるデザインパターンの中でも初歩的なものの一つであり、Kubernetesが使われるようになった当初から利用されています。
ではなぜ、サイドカーコンテナという機能が出てきたのか、これまでのサイドカーの実装と注意点を見比べながら考察したいと思います。
サイドカーパターンとは
前述の通り、サイドカーパターンは分散システムにおけるデザインパターンのひとつです。
本来、提供したい機能を持つアプリケーションコンテナの隣で、それを補助する機能を持つコンテナを動かすことでPod全体として持たせたい機能を実現します。
下図はサイドカーパターンの例です。角丸の四角がコンテナ、それをグルーピングしている四角がPodを示しています。そして、青色のコンテナがサイドカーコンテナとなり、アプリケーションが出力するログを外部監視ツールに転送したり、アプリケーションの設定を外部のGitリポジトリと同期して設定を最新化する役割を担っています。
サイドカーパターンの例
その他にも、アプリケーションが外部通信をする際にプロキシとして間に入ったり、アプリケーションがhttpで通信を受け付けるためにSSL/TLS終端処理をおこなうコンテナを挟む等のネットワーク処理を仲介するケースもあります。
※厳密には、それぞれのPodに統一した外部インタフェースを持たせるために仲介するコンテナを配置するパターンはアダプタパターンと呼ばれ、別物なのですが、ここでは割愛します。
通信処理に関するサイドカーパターンの例
いずれのケースにおいても、もちろんサイドカーパターンを使わずにアプリケーションコンテナ自体を拡張して必要な機能を持たせてもよいのですが、以下のようなケースでサイドカーパターンを検討します。
- アプリケーション開発者と周辺機能の開発者が異なり、手を入れることが困難
- 複数のアプリケーションに同一の周辺機能の拡張が必要で、再利用性を持たせたい
これまでのサイドカーパターンの実装方法
ここまで紹介してきたサイドカーパターンですが、KubernetesのPodは元から複数のコンテナをグループ化して構成する機能があり、簡単に実現できました。
複数のコンテナをPodに含めたい場合、以下のようにコンテナに関する記述を列挙するだけでサイドカーパターンを実現できます。
apiVersion: v1
kind: Pod
metadata:
name: sleeper
labels:
app: sleeper
spec:
containers:
- name: main
image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/sleeper
volumeMounts:
- name: log-data
mountPath: /var/log
- name: sidecar
image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/sleeper-sidecar
volumeMounts:
- name: log-data
mountPath: /var/log
volumes:
- name: log-data
emptyDir: {}
restartPolicy: Never
こちらのyamlでは main
というコンテナと sidecar
というコンテナが動いていて、 /var/log
を共有しています。
そして、mainコンテナは標準出力とファイルに実行ログを出力して一定時間後に終了する機能、 sidecarコンテナは、mainコンテナのログを収集して処理する機能を有しています(今回はファイルに出力されたログを読み込んで標準出力に出すだけ)。
mainコンテナは起動すると以下のようなログを出力しながら300秒後に終了します。
Initializing (1 / 5), Sun Sep 7 07:23:54 UTC 2025
Initializing (2 / 5), Sun Sep 7 07:23:55 UTC 2025
Initializing (3 / 5), Sun Sep 7 07:23:56 UTC 2025
Initializing (4 / 5), Sun Sep 7 07:23:57 UTC 2025
Initializing (5 / 5), Sun Sep 7 07:23:58 UTC 2025
Starting main process, Sun Sep 7 07:23:59 UTC 2025
Processing (1 / 300), Sun Sep 7 07:23:59 UTC 2025
Processing (2 / 300), Sun Sep 7 07:24:00 UTC 2025
Processing (3 / 300), Sun Sep 7 07:24:01 UTC 2025
(中略)
Processing (298 / 300), Sun Sep 7 07:28:57 UTC 2025
Processing (299 / 300), Sun Sep 7 07:28:58 UTC 2025
Processing (300 / 300), Sun Sep 7 07:28:59 UTC 2025
Completed main process, Sun Sep 7 07:29:00 UTC 2025
また、途中でSIGTERMなどのシグナルを受けとるとログを出力し、終了します。
Trapped signal, Sun Sep 7 07:34:00 UTC 2025
Terminate process, Sun Sep 7 07:34:08 UTC 2025
sidecarコンテナも同様に、起動ログを出力した後にmainコンテナのログを出力し、シグナルを受けとるとログを出力し終了します。
[Sidecar] Entrypoint script started, Sun Sep 7 07:23:55 UTC 2025
[Sidecar] Starting main process, Sun Sep 7 07:24:05 UTC 2025
(この後はmainコンテナのログを出力する)
参考までにそれぞれのソースコードも載せておきます。
(参考) mainとsidecarのソースコード
mainコンテナ
FROM alpine
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
#!/bin/sh
set -e
echo "Entrypoint script started, $(date)" | tee -a /var/log/entrypoint.log
trap 'echo "Trapped signal, $(date)"; sleep 8; echo "Terminate process, $(date)"; exit' 1 2 3 15
for i in $(seq 1 5); do
echo "Initializing (${i} / 5), $(date)" | tee -a /var/log/entrypoint.log
sleep 1
done
touch /tmp/started
echo "Starting main process, $(date)" | tee -a /var/log/entrypoint.log
for i in $(seq 1 300); do
echo "Processing (${i} / 300), $(date)" | tee -a /var/log/entrypoint.log
sleep 1
done
echo "Completed main process, $(date)" | tee -a /var/log/entrypoint.log
sidecarコンテナ
FROM alpine
COPY entrypoint.sh /entrypoint.sh
CMD ["/entrypoint.sh"]
#!/bin/sh
set -e
echo "[Sidecar] Entrypoint script started, $(date)"
trap 'echo "[Sidecar] Trapped signal, $(date)"; sleep 10; echo "[Sidecar] Terminate process, $(date)"; exit' 1 2 3 15
for i in $(seq 1 10); do
sleep 1
done
touch /tmp/started
echo "[Sidecar] Starting main process, $(date)"
tail -F -n 0 /var/log/entrypoint.log &
pid=$!
wait $pid
echo "[Sidecar] Completed main process, $(date)"
これまでの複数コンテナ実行における課題
さて、Podに複数のコンテナを含めることはできたのですが、これまでのKubernetesでは以下の課題がありました。
- コンテナの起動順序・終了順序を制御できない
- そのため、sidecarコンテナが準備できていることがmainコンテナの動作前提だった場合にスリープ処理を入れたり監視処理を入れたり、作り込みが必要
- 特にJobのようなワンショット実行が必要な場合に、mainコンテナが終了してもsidecarコンテナが終了しないとPodが生存し続けてしまう
- そのため、sidecarコンテナを終了させる仕組みが必要
それぞれの課題が何を示すのか、実際の挙動を見ながら確認していきましょう。
課題を実際の挙動で確認
課題の詳細について、先程のふたつのコンテナを含むPodを起動し、それぞれのコンテナのログをチェックしてみます。
Entrypoint script started, Sun Sep 7 07:23:54 UTC 2025
Initializing (1 / 5), Sun Sep 7 07:23:54 UTC 2025
Initializing (2 / 5), Sun Sep 7 07:23:55 UTC 2025
Initializing (3 / 5), Sun Sep 7 07:23:56 UTC 2025
Initializing (4 / 5), Sun Sep 7 07:23:57 UTC 2025
Initializing (5 / 5), Sun Sep 7 07:23:58 UTC 2025
Starting main process, Sun Sep 7 07:23:59 UTC 2025
Processing (1 / 300), Sun Sep 7 07:23:59 UTC 2025
Processing (2 / 300), Sun Sep 7 07:24:00 UTC 2025
Processing (3 / 300), Sun Sep 7 07:24:01 UTC 2025
Processing (4 / 300), Sun Sep 7 07:24:02 UTC 2025
Processing (5 / 300), Sun Sep 7 07:24:03 UTC 2025
Processing (6 / 300), Sun Sep 7 07:24:04 UTC 2025
Processing (7 / 300), Sun Sep 7 07:24:05 UTC 2025
Processing (8 / 300), Sun Sep 7 07:24:06 UTC 2025
Processing (9 / 300), Sun Sep 7 07:24:07 UTC 2025
(後略)
[Sidecar] Entrypoint script started, Sun Sep 7 07:23:55 UTC 2025
[Sidecar] Starting main process, Sun Sep 7 07:24:05 UTC 2025
Processing (7 / 300), Sun Sep 7 07:24:05 UTC 2025
Processing (8 / 300), Sun Sep 7 07:24:06 UTC 2025
Processing (9 / 300), Sun Sep 7 07:24:07 UTC 2025
(後略)
sidecarコンテナのログですが、mainコンテナのログが最初の方が欠損しています。
各コンテナのログの1行目で、それぞれのコンテナの起動時間がわかりますがどちらもほぼ同じです。つまり同時にコンテナが起動したあとsidecarコンテナの準備ができる前にmainコンテナが動きだしてしまったため、sidecarコンテナはログを取りこぼしてしまったのです。
処理完了時の挙動
処理が完了し、正常終了した場合でも問題がおきます。
Processing (298 / 300), Sun Sep 7 07:28:57 UTC 2025
Processing (299 / 300), Sun Sep 7 07:28:58 UTC 2025
Processing (300 / 300), Sun Sep 7 07:28:59 UTC 2025
Completed main process, Sun Sep 7 07:29:00 UTC 2025
メインコンテナは処理を終えて終了しました。
では、このときPodの状態はどうなっているでしょうか? 実際に確認すると以下の結果が得られました。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
sleeper 1/2 NotReady 0 5m40s
READY
の列を見てみると 1/2
となっています。
これはmainコンテナは終了したものの、sidecarコンテナが動作し続けていて、Podとしては起動中の状態が続いていることを示します。
そこで、手動でsidecarコンテナのプロセスを落して終了させると、以下の状態になります。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
sleeper 0/2 Completed 0 8m19s
sidecarコンテナはmainコンテナが動いてなければ何の役にも立たないので終了させたいのですが、それを実現するには何かしら作り込みをして、sidecarコンテナに自分自身を終了させる機能を持たせる必要があります。
Pod削除時の挙動
最後に、実行中にPodを削除したらどうなるでしょうか。
mainコンテナが処理をしている最中に kubectl delete
を使ってPodを削除します。
Processing (19 / 300), Sun Sep 7 07:33:57 UTC 2025
Processing (20 / 300), Sun Sep 7 07:33:58 UTC 2025
Processing (21 / 300), Sun Sep 7 07:33:59 UTC 2025
Trapped signal, Sun Sep 7 07:34:00 UTC 2025
Terminate process, Sun Sep 7 07:34:08 UTC 2025
Processing (20 / 300), Sun Sep 7 07:33:58 UTC 2025
Processing (21 / 300), Sun Sep 7 07:33:59 UTC 2025
[Sidecar] Trapped signal, Sun Sep 7 07:34:00 UTC 2025
[Sidecar] Terminate process, Sun Sep 7 07:34:10 UTC 2025
こちらの場合もmainコンテナとsidecarコンテナが、同じタイミングでSIGTERMのシグナルを受けとっています。
mainコンテナの終了処理においてもsidecarコンテナが動作していることが前提の場合、期待した終了処理ができないケースがあります。対応として、sidecarにスリープ処理を入れておく等の作り込みが必要です。
新しく登場したサイドカーコンテナによる解決
では、ここまでの課題をサイドカーコンテナはどのように解決してくれるのでしょうか?
まずサイドカーコンテナはinitコンテナの拡張として実装されています。
initコンテナは、メインのコンテナの起動前に必要な処理をするものでした。そしてinitコンテナが終了するとメインのコンテナが起動するという順序です。
しかし、サイドカーパターンを実現したい場合はメインのコンテナと共に実行しつづけてほしいですね。サイドカーにしたいinitコンテナは restartPolicy: Always
とすることでサイドカーとして動作します。
apiVersion: v1
kind: Pod
metadata:
name: sleeper-sidecar
labels:
app: sleeper
spec:
containers:
- name: main
image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/sleeper
volumeMounts:
- name: log-data
mountPath: /var/log
initContainers:
- name: sidecar
image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/sleeper-sidecar
startupProbe:
exec:
command:
- ls
- /tmp/started
timeoutSeconds: 30
restartPolicy: Always
volumeMounts:
- name: log-data
mountPath: /var/log
volumes:
- name: log-data
emptyDir: {}
restartPolicy: Never
もう一つの特徴として startupProbe
を追加しています。StartupProbeはコンテナの起動処理が完了したことをチェックするProbeであり、これを利用することでsidecarコンテナの準備ができたことを判定し、その後安全にmainコンテナを起動することができます。
サイドカーコンテナの挙動
先程と同様に、実際に動かしてみて挙動の違いを見てみます。
起動時のログを見比べてみてください。
Entrypoint script started, Sun Sep 7 07:35:54 UTC 2025
Initializing (1 / 5), Sun Sep 7 07:35:54 UTC 2025
Initializing (2 / 5), Sun Sep 7 07:35:55 UTC 2025
Initializing (3 / 5), Sun Sep 7 07:35:56 UTC 2025
Initializing (4 / 5), Sun Sep 7 07:35:57 UTC 2025
Initializing (5 / 5), Sun Sep 7 07:35:58 UTC 2025
Starting main process, Sun Sep 7 07:35:59 UTC 2025
Processing (1 / 300), Sun Sep 7 07:35:59 UTC 2025
Processing (2 / 300), Sun Sep 7 07:36:00 UTC 2025
[Sidecar] Entrypoint script started, Sun Sep 7 07:35:37 UTC 2025
[Sidecar] Starting main process, Sun Sep 7 07:35:49 UTC 2025
tail: can't open '/var/log/entrypoint.log': No such file or directory
tail: /var/log/entrypoint.log has appeared; following end of new file
Entrypoint script started, Sun Sep 7 07:35:54 UTC 2025
Initializing (1 / 5), Sun Sep 7 07:35:54 UTC 2025
Initializing (2 / 5), Sun Sep 7 07:35:55 UTC 2025
Initializing (3 / 5), Sun Sep 7 07:35:56 UTC 2025
Initializing (4 / 5), Sun Sep 7 07:35:57 UTC 2025
Initializing (5 / 5), Sun Sep 7 07:35:58 UTC 2025
以下の違いが見られます。
- sidecarとmainの1行目、プロセス起動時のログの出力日時が異なる。sidecarコンテナが先に起動し、準備ができてからmainコンテナが起動している
- sidecarコンテナはログ欠損なくmainコンテナのログを取得できている
ちなみにPod状態もそれぞれの実行状態に応じて以下のように遷移します。
$ kubectl get pod -w
NAME READY STATUS RESTARTS AGE
sleeper-sidecar 0/2 Pending 0 8s
sleeper-sidecar 0/2 Init:0/1 0 19s
sleeper-sidecar 0/2 PodInitializing 0 37s
sleeper-sidecar 1/2 PodInitializing 0 37s
sleeper-sidecar 2/2 Running 0 38s
終了時の挙動
mainコンテナの処理が終了する時の挙動も異なります。
Processing (299 / 300), Sun Sep 7 07:40:57 UTC 2025
Processing (300 / 300), Sun Sep 7 07:40:58 UTC 2025
Completed main process, Sun Sep 7 07:40:59 UTC 2025
Processing (298 / 300), Sun Sep 7 07:40:56 UTC 2025
Processing (299 / 300), Sun Sep 7 07:40:57 UTC 2025
Processing (300 / 300), Sun Sep 7 07:40:58 UTC 2025
Completed main process, Sun Sep 7 07:40:59 UTC 2025
[Sidecar] Trapped signal, Sun Sep 7 07:41:00 UTC 2025
[Sidecar] Terminate process, Sun Sep 7 07:41:10 UTC 2025
mainコンテナの動きは先程と同様ですが、mainコンテナが終了するとsidecarコンテナがSIGTERMを受けとり終了処理に入ります。実際、Podの状態を見ても、以下のとおり全てのコンテナが終了しCompletedに遷移しています。
$kubectl get pod
NAME READY STATUS RESTARTS AGE
sleeper-sidecar 0/2 Completed 0 6m19s
Pod削除時の挙動
Podを削除したときも同様です。以下のログの通り、mainコンテナが先に終了した上で、sidecarコンテナの終了処理に入っていることがログの時刻から読み取れます。
Processing (19 / 300), Sun Sep 7 07:44:17 UTC 2025
Processing (20 / 300), Sun Sep 7 07:44:18 UTC 2025
Trapped signal, Sun Sep 7 07:44:19 UTC 2025
Terminate process, Sun Sep 7 07:44:27 UTC 2025
Processing (19 / 300), Sun Sep 7 07:44:17 UTC 2025
Processing (20 / 300), Sun Sep 7 07:44:18 UTC 2025
[Sidecar] Trapped signal, Sun Sep 7 07:44:27 UTC 2025
[Sidecar] Terminate process, Sun Sep 7 07:44:37 UTC 2025
注意点
便利なサイドカーコンテナですが、以下のような注意点があります。それぞれのアプリケーションの特性に応じて適切に設計しましょう。
- sidecarコンテナにはStartupProbeの設定が事実上必須
- これが無いと結局mainコンテナがすぐに起動してしまう。サイドカーとなるアプリは準備完了を判定できるように作り込んでおく必要がある
- StartupProbeのTimeoutはデフォルトで1秒
- それを超えるとsidecarコンテナが起動失敗と判定され再起動し、Podが起動できない。十分な猶予時間が必要
- 終了時のタイムアウトである
terminationGracePeriodSeconds
は、それぞれのコンテナではなくPod全体のタイムアウト設定- mainコンテナにSIGTERMが送られた後、デフォルトでは30秒後に残存するコンテナにSIGKILLが送られ、sidecarコンテナの終了処理中に強制終了される可能性がある
- 各コンテナの終了時間の見込みをふまえた十分な猶予時間が必要
まとめ
古くからあるサイドカーパターンですが、意外と作り込みが多く苦労することがありました。Kubernetes 1.33でStableになったサイドカーコンテナの機能により確実にサイドカーの実装がシンプルにできます。
実際には、サードパーティ製品などを使う場合は、利用者は作り込みをそこまで意識せずとも作り込まれた状態で利用でき、自分達でいちからサイドカー設計を考えるケースは少ないかもしれませんが、サイドカーが必要になった場合には、ぜひ活用してみてはどうでしょうか。
仲間募集中です!
NTTデータ クラウド&データセンタ事業部では、以下の職種を募集しています。
- プライベートクラウドコンサル/エンジニア
- デジタルワークスペース構築/新規ソリューション開発におけるプロジェクトリーダー
- IT基盤(パブリッククラウド、プライベートクラウド)エンジニア
- パブリッククラウド/プライベートクラウドを用いた大規模プロジェクトをリードするインフラエンジニア
ソリューション紹介

NTT DATA公式アカウントです。 技術を愛するNTT DATAの技術者が、気軽に楽しく発信していきます。 当社のサービスなどについてのお問い合わせは、 お問い合わせフォーム nttdata.com/jp/ja/contact-us/ へお願いします。