Sidecar Containers でサイドカーコンテナが原因で Job が終わらない問題に対処する
こんにちは、SRE 部の松島です。
本記事では、最近 GKE でも利用可能になった Sidecar Containers で Kubernetes で以前から問題のあったサイドカーコンテナが原因で Job が終わらない問題に対処する方法を紹介します。
サイドカーコンテナのせいで Job が終わらない問題について
Kubernetes の Job はコンテナ全てが完了状態となったタイミングで Job が完了されたとみなされます。
そのため、Job でサイドカーとしてコンテナを複数利用している場合、処理を実行している本体のコンテナが終了してもサイドカーのコンテナが残る場合 Job が完了扱いにならない問題が以前から発生していました。
例えばよくあるパターンだと、 GKE で Cloud SQL に接続するために Auth Proxy をサイドカーとして利用しているものの、これが完了しないせいで定時バッチ処理自体は完了しても Job が完了扱いにならず、どんどん実行中の Job が溜まってしまう事象が発生します。
Sidecar Containers について
Kubernetes v1.29 より beta に昇格し、デフォルトで有効になった Sidecar Containers という機能を使うことで、サイドカーコンテナを明示的にサイドカーとして定義することができるようになりました。
これにより、Job で実行したい本体の処理が完了した時点で Job を完了させることができるようになります。
詳細な情報は公式ドキュメントをご参照ください。
設定自体は簡単で、サイドカーコンテナを initContainers に記載し、restartPolicy に Always を設定するだけです。
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
...
spec:
containers:
...
initContainers:
- name: logshipper
image: alpine:latest
restartPolicy: Always # Sidecar Container
GKE で Sidecar Containers を試してみる
GKE でも v1.29 より Sidecar Containers が利用可能となっていますので、これを動かしてみます。
サイドカーとして利用頻度の高い Cloud SQL Auth Proxy について、Sidecar Containers を利用した場合としない場合で動作を比較していきます。
0. 下準備
下記のリソースを作成しておきます。主旨から外れるため、詳細な手順は割愛します。
- GKE クラスタの作成
- Cloud Storage FUSE CSI ドライバの有効化
- v1.29 以降で作成すること
- Workload Identity を有効にする
- AuthProxy の接続先となる Cloud SQL を作成
- k8s サービスアカウントを作成し、Workload Identity を利用して Cloud SQL アクセス権限を付与する
1. Sidecar Containers なしで Job を動かす
以下のような CronJob マニフェストを準備し、apply します。
CronJob マニフェスト
apiVersion: batch/v1
kind: CronJob
metadata:
name: otameshi
spec:
schedule: "* * * * *"
concurrencyPolicy: Allow
startingDeadlineSeconds: 100
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: job
image: ubuntu:latest
args:
- ls
- /
- name: cloud-sql-proxy
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0
args:
- "--structured-logs"
- "--port=3306"
- "<Cloud SQL 接続文字列>"
serviceAccountName: <下準備で作成した k8s サービスアカウント名>
apply 後しばらく経過して様子をみたところ、予想通り、完了しない Job が溜まっている状態を確認できました。
$ kubectl get job
NAME COMPLETIONS DURATION AGE
otameshi-28581128 0/1 4m41s 4m41s
otameshi-28581129 0/1 3m41s 3m41s
otameshi-28581130 0/1 2m41s 2m41s
otameshi-28581131 0/1 101s 101s
otameshi-28581132 0/1 41s 41s
コンソールで Pod の状態を確認すると、本体のコンテナは完了状態になっていますが、Auth Proxy は Running のままとなっていることがわかります。
2. Sidecar Containers を利用して Job を動かす
続いて Sidecar Containers を利用した CronJob を実行してみます。
下記のマニフェストを apply します。
CronJob マニフェスト Sidecar Containers 利用版
apiVersion: batch/v1
kind: CronJob
metadata:
name: otameshi
spec:
schedule: "* * * * *"
concurrencyPolicy: Allow
startingDeadlineSeconds: 100
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: job
image: ubuntu:latest
args:
- ls
- /
initContainers:
- name: cloud-sql-proxy
image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0
restartPolicy: Always # これでsidecarになる
args:
- "--structured-logs"
- "--port=3306"
- "-term_timeout=5s"
- "<Cloud SQL 接続文字列>"
serviceAccountName: <下準備で作成した k8s サービスアカウント名>
今度は Job が完了するようになりました。
kubectl get job
NAME COMPLETIONS DURATION AGE
otameshi-28581151 1/1 12s 2m21s
otameshi-28581152 1/1 10s 81s
otameshi-28581153 1/1 10s 21s
コンソールで Pod の状態を確認すると、job コンテナのみがメインのコンテナと認識されていることを確認できます。
おわりに
これまで Job を完了させるためにはサイドカー側に本体コンテナの終了を検知する処理を実装するなど、やや複雑な制御が必要でしたが、Sidecar Cointainers の登場によりこの問題にシンプルに対応可能となりました。
Job が終わらない問題でお困りの方はぜひ本機能をご利用ください。
Discussion