🚙

Kubernetes 1.28でFeatureGateになったSidecar containersをJobで試す

2023/08/30に公開

はじめに

こんにちは、三村です。

先日Kubernetes 1.28がリリースされました。
今回のバージョンでSidecar containersの機能がFeatureGateとして追加されました。
従来のKubernetesでは、1つのPodに複数のコンテナを配置することはできましたが、どちらがサイドカーなのかといった区別はなく、Kubernetesの機能としてサイドカーコンテナがあるというわけではありませんでした。
Kubernetes 1.28からは、initContainerのrestartPolicyにAlwaysを指定することでinitContainerがサイドカーコンテナとして動作するようになりました。
今回はこの機能をKind上で試してみたので、その使用方法と挙動を紹介します。

サンプルコードや設定ファイルは以下のレポジトリに置いています。
https://github.com/YZ775/k8s-sidecar-example

Kuberentesクラスタの構築

以下のようなcluster.yamlを作成します。
重要なポイントは2点あり、一つは1.28のバージョンを指定すること、もう一つは最後の行で、Sidecar containersの機能はFeatureGateであるため、設定を入れて有効化する必要があることです。

cluster.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    image: kindest/node:v1.28.0
  - role: worker
    image: kindest/node:v1.28.0
  - role: worker
    image: kindest/node:v1.28.0
featureGates:
  SidecarContainers: true

この設定を元に、kindでクラスタを作成します。

$ kind create cluster --config cluster.yaml

Jobでのサイドカーコンテナの動作確認

次に、Jobを作成して、サイドカーコンテナが動作することを確認します。
メインのコンテナとして30秒後に"main application"と出力するコンテナと、サイドカーコンテナとしてHTTPサーバを起動するコンテナを作成します。
以下にサンプルコードを貼りました。
これらをappとsidecarというイメージ名でDocker imageをビルドし、Kind上にロードしておきます。

app/main.go
package main

import (
	"fmt"
	"time"
)

func main() {
	time.Sleep(30 * time.Second)
	fmt.Println("main application")
}
sidecar/main.go
package main

import (
	"io"
	"net/http"
)

func main() {
	handler := func(w http.ResponseWriter, _ *http.Request) {
		io.WriteString(w, "Sidecar application\n")
	}
	http.HandleFunc("/", handler)
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		panic(err)
	}
}

そして、Jobのマニフェストを作成します。
サイドカーコンテナはinitContainersとして定義し、restartPolicyにAlwaysを指定します。

job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: sample-job
spec:
  template:
    spec:
      containers:
        - name: app
          image: app
          imagePullPolicy: IfNotPresent
      initContainers:
        - name: sidecar
          image: sidecar
          imagePullPolicy: IfNotPresent
          restartPolicy: Always
      restartPolicy: Never

このmanifestをapplyし、Jobを作成します。

kubectl apply -f job.yaml

Jobの状態を確認します。

$ kubectl get job sample-job -w
NAME         COMPLETIONS   DURATION   AGE
sample-job   0/1           1s         1s
sample-job   0/1           3s         3s
sample-job   0/1           33s        33s
sample-job   0/1           35s        35s
sample-job   1/1           35s        35s

期待通りにJobが正常に完了します。
今回、サイドカーコンテナが常駐型プログラムであるにもかかわらず、メインのコンテナが終了すればJob全体が正常に終了しました。(従来のサイドカー構成ではこれでは正常終了しません。)
この挙動については次の章で解説します。

Sidecar containersの何が嬉しいのか

Sidecar containersの機能を使うことで一番嬉しいのは、Jobの終了時にサイドカーコンテナにシグナルを送る必要がなくなることです。
従来のKubernetesでは、サイドカー構成のJobを作成する際、Pod内のすべてのコンテナがexit code 0で終了しないとJobが正常終了しませんでした。そのため、サイドカーコンテナで常駐型プログラムを動かす場合は、何かしらの方法でメインのコンテナが終了する際にサイドカーコンテナを終了する必要がありました。
これには、shareProcessNamespaceを使ってコンテナ間でPID名前空間を共有し、メインのコンテナからサイドカーコンテナにSIGTERMのシグナル送るなどの方法を取る必要がありましたが、自分でプログラムにこれを実装する必要があり非常に煩雑でした。
Sidecar containersの機能を使うと、メインのコンテナが終了するとinitContainersのコンテナにSIGTERMが自動で送られるため、このような特別な設定をせずともJobが完了してくれます。

まとめ

今回の記事では、Kubernetes 1.28でFeatureGateとなったSidecar containersの機能をJobで使う方法とその挙動について紹介しました。
これまでのKurbenetesでサイドカーパターンを使用すると、サイドカーコンテナの終了処理を考慮する必要がありましたが、Kubernetes 1.28からはこのような特別な設定をする必要がなくなりました。

Discussion