NTT DATA TECH
🚗

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に含めたい場合、以下のようにコンテナに関する記述を列挙するだけでサイドカーパターンを実現できます。

サイドカーパターンを実現する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秒後に終了します。

mainコンテナの実行例
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などのシグナルを受けとるとログを出力し、終了します。

mainコンテナの終了ログ
Trapped signal, Sun Sep 7 07:34:00 UTC 2025  
Terminate process, Sun Sep 7 07:34:08 UTC 2025

sidecarコンテナも同様に、起動ログを出力した後にmainコンテナのログを出力し、シグナルを受けとるとログを出力し終了します。

sidecarコンテナのログ
[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コンテナ

Dockerfile
FROM alpine

COPY --chmod=755 entrypoint.sh /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
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コンテナ

Dockerfile
FROM alpine

COPY --chmod=755 entrypoint.sh /entrypoint.sh

CMD ["/entrypoint.sh"]
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を起動し、それぞれのコンテナのログをチェックしてみます。

mainコンテナのログ
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コンテナのログ
[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コンテナはログを取りこぼしてしまったのです。

処理完了時の挙動

処理が完了し、正常終了した場合でも問題がおきます。

mainコンテナのログ
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を削除します。

mainコンテナのログ
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
sidecarコンテナのログ
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 とすることでサイドカーとして動作します。

サイドカーコンテナのPod例
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コンテナを起動することができます。

サイドカーコンテナの挙動

先程と同様に、実際に動かしてみて挙動の違いを見てみます。
起動時のログを見比べてみてください。

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コンテナのログ
[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コンテナの処理が終了する時の挙動も異なります。

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
sidecarコンテナのログ
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コンテナの終了処理に入っていることがログの時刻から読み取れます。

mainコンテナのログ
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
sidecarコンテナのログ
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データ クラウド&データセンタ事業部では、以下の職種を募集しています。

  1. プライベートクラウドコンサル/エンジニア
  2. デジタルワークスペース構築/新規ソリューション開発におけるプロジェクトリーダー
  3. IT基盤(パブリッククラウド、プライベートクラウド)エンジニア
  4. パブリッククラウド/プライベートクラウドを用いた大規模プロジェクトをリードするインフラエンジニア

ソリューション紹介

  1. クラウドプロフェッショナルサービス/クラウドインテグレーションサービス/クラウドマネージドサービス/パートナークラウドサービス
  2. OpenCanvas
NTT DATA TECH
NTT DATA TECH
設定によりコメント欄が無効化されています