TL;DR
kube-apiserver に Feature Gates で以下を設定する。
--feature-gates=TTLAfterFinished=true
以下のように Job のマニフェストに .spec.ttlSecondsAfterFinished
を追加する。
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
ttlSecondsAfterFinished: 30 # こちらのフィールドを追加
template:
spec:
containers:
- name: busybox
image: busybox
command: ["date"]
env:
- name: TZ
value: "JST-9"
restartPolicy: Never
はじめに
Kubernetes でのバッチ処理などで Job を利用していて、以下のように実行が完了した Job とそれに依存する Pod が大量に残ってしまっているケースがあるかと思います。
$ kubectl get jobs,pods
NAME COMPLETIONS DURATION AGE
myjob0 1/1 19s 112s
myjob1 1/1 23s 111s
myjob2 1/1 21s 111s
myjob3 1/1 26s 111s
myjob4 1/1 36s 111s
myjob5 1/1 33s 111s
myjob6 1/1 54s 111s
myjob7 1/1 59s 110s
myjob8 1/1 56s 110s
myjob9 1/1 30s 110s
NAME READY STATUS RESTARTS AGE
myjob0-lgx7h 0/1 Completed 0 90s
myjob1-sdbtg 0/1 Completed 0 89s
myjob2-ng5lb 0/1 Completed 0 89s
myjob3-fmmw4 0/1 Completed 0 89s
myjob4-z654m 0/1 Completed 0 89s
myjob5-4scjl 0/1 Completed 0 89s
myjob6-qg5xr 0/1 Completed 0 89s
myjob7-42s7r 0/1 Completed 0 88s
myjob8-7zzmg 0/1 Completed 0 88s
myjob9-hhrjw 0/1 Completed 0 88s
これを気付いた時に毎回手作業で削除するのは面倒なので、今回は Kubernetes で Complete/Failed となった Job を自動削除する方法を紹介します。
Feature Gates TTLAfterFinished
について
TTLAfterFinished
は Kubernetes 1.12 から Alpha で追加された Feature Gates で、これを有効化することで終了したリソースをクリーンアップするための TTL controller が機能するようになります。なお、この機能は Alpha ステージの実験段階のものなのでデフォルトでは有効化されていません。
https://v1-16.docs.kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/
こちらの機能が提供された背景を知るために Design Doc を見てみると Kubeflow, Prow, Apache Spark on Kubernetes, Jenkins Kubernetes plugin などから実行された Job をクリーンアップすることが具体的なユースケースとして挙げられていました。
TTL Controller について
TTL Controller は実行が完了したリソースに TTL の機構を提供するもので、現在は Job のみがサポートされています。
https://v1-16.docs.kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/
TTL Controller が有効な状態で Job Spec の .spec.ttlSecondsAfterFinished
に値を設定する(設定例はこちら)ことで Complete/Failed となった Job を自動削除することが可能になります。リソースの実行が完了して .spec.ttlSecondsAfterFinished
秒後に、そのリソースが TTL Controller によって(依存するリソースと共に)自動削除されるイメージです。
Kubernetes クラスタ管理者向けな情報
Mutating Admission Webhook を使って、作成される Job にデフォルトで .spec.ttlSecondsAfterFinished
を設定する運用も良いとのことでした。
また、TTL Controller はリソースに保存されている時間を元に制御を行うので、厳密な運用をしたければ Kubernetes クラスタの全ての Node で NTP を起動するのが望ましいとのことでした。詳細は #6159 を参照ください。
動作検証
TTLAfterFinished
を有効化して minikube を起動します。
$ minikube version
minikube version: v1.4.0
commit: 7969c25a98a018b94ea87d949350f3271e9d64b6
$ minikube start --kubernetes-version=v1.16.0 --feature-gates=TTLAfterFinished=true
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"13", GitVersion:"v1.13.4", GitCommit:"c27b913fddd1a6c480c229191a087698aa92f0b1", GitTreeState:"clean", BuildDate:"2019-03-01T23:35:19Z", GoVersion:"go1.12", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.0", GitCommit:"2bd9643cee5b3b3a5ecbd3af49d09018f0773c77", GitTreeState:"clean", BuildDate:"2019-09-18T14:27:17Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}
$ kubectl get pods -n kube-system kube-apiserver-minikube -o yaml | grep feature-gates
- --feature-gates=TTLAfterFinished=true
以下のスクリプトで .spec.ttlSecondsAfterFinished
を設定した Job を複数作成します。今回は30秒で削除される設定を適用します。
for i in $(seq 0 4); do
cat << EOM | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: myjob${i}
spec:
ttlSecondsAfterFinished: 30
template:
spec:
containers:
- name: busybox
image: busybox
command: ["date"]
env:
- name: TZ
value: "JST-9"
restartPolicy: Never
EOM
done
上記のスクリプトを実行すると5つの Job 及び、それに依存する Pod が作成されます。
$ kubectl get jobs,pods
NAME COMPLETIONS DURATION AGE
job.batch/myjob0 1/1 8s 23s
job.batch/myjob1 1/1 11s 23s
job.batch/myjob2 1/1 21s 23s
job.batch/myjob3 1/1 13s 22s
job.batch/myjob4 1/1 16s 22s
NAME READY STATUS RESTARTS AGE
pod/myjob0-g9vjm 0/1 Completed 0 23s
pod/myjob1-pfcdt 0/1 Completed 0 23s
pod/myjob2-mf95m 0/1 Completed 0 23s
pod/myjob3-8xv7k 0/1 Completed 0 22s
pod/myjob4-4bfp5 0/1 Completed 0 22s
30秒が経過すると、Job とそれに紐づく Pod が削除されていることがわかると思います。
$ kubectl get jobs,pods
No resources found.
さいごに
今回は Kubernetes で Complete/Failed となった Job を自動削除する方法を紹介しました。CronJob を利用している方には不要かもしれませんが、Job 単体で利用されている方にとっては有効な設定かと思われます。
最近、個人的にカスタムコントローラーを学習していたのもあり、Kubernetes Way(client-go + code-generator)な実装である TTL Controller の実装を読めたことが非常に有意義でした。おしまい。
おまけ: TTL Controller の実装
Kubernetes 1.16.0 の実装を見ていきます。
Reconcile Loop の中で以下の processJob
関数を使って、Job の状態と TTL をチェックして削除するという処理が実行されています。シンプルな実装で自分でも普通に読めたので、ご興味ある方は是非参照ください。
https://github.com/kubernetes/kubernetes/blob/v1.16.0/pkg/controller/ttlafterfinished/ttlafterfinished_controller.go#L186-L238
備考: CronJob を利用している場合
CronJob を利用している場合には .spec.successfulJobsHistoryLimit (デフォルト:3)
と .spec.failedJobsHistoryLimit (デフォルト:1)
をマニフェストに定義することで、CronJob により定期実行される Job 及び、依存する Pod の履歴数を管理することができます。
https://v1-16.docs.kubernetes.io/docs/tasks/job/#jobs-history-limits