Podの設計 — ラベル、コマンド、Job、CronJob
目標
Podのメタデータ(ラベル・アノテーション)と実行方法(command/args/env/restartPolicy)を自分で指定し、バッチワークロードであるJobとCronJobの主要なフィールドを埋められるようになります。
なぜ重要なのか
CKADの問題の半分は、「この値をどのフィールドに書くか」で決まります。ラベルとアノテーションはどちらもmetadataの下にある文字列のマップですが、役割は正反対です。ラベルはセレクターが選ぶ値なので、Service・Deployment・NetworkPolicyがすべてこれを見ます。アノテーションはセレクターが決して見ないメモで、ツールが読む設定(change-cause、コントローラーへのヒント)を入れます。この区別を混同すると、Serviceにエンドポイントが付かないという事故が起きます。
commandとargsも同じです。これらはイメージの中のENTRYPOINT/CMDをそれぞれ上書きするものであって、「コマンドと引数」ではありません。commandだけを変えるとCMDがそのまま付いて妙な組み合わせになり、argsだけを変えると元のENTRYPOINTに新しい引数が付きます。
Jobは「成功を数える」コントローラーです。Deploymentが「いま何個起動しているか」を維持するのに対し、Jobは「これまでに何回成功したか」を数えます。そのためPodのrestartPolicyをAlwaysにするとPodがいつまでも終わらず、Jobも終わりません。
ステップ
- ネームスペース
ckad-designを作成し、その中にPodwebを作成してください。イメージはnginx:1.27、ラベルはapp=webとtier=frontendです。 - Pod
webにアノテーションowner=platform-teamを付けてください。同じネームスペースにPodapiを作成してください。イメージはnginx:1.27、ラベルはapp=apiとtier=backendです。 - Pod
runnerを作成してください。イメージはbusybox:1.36、commandは["/bin/sh"]、argsは["-c", "sleep 3600"]です。 - Pod
envtestを作成してください。イメージはbusybox:1.36、ラベルはtier=backendです。環境変数APP_ENV=productionとAPP_TIER=backendを固定値で入れ、POD_NAMEはDownward APIでmetadata.nameを参照させてください。commandは["/bin/sh","-c","sleep 3600"]です。 - Pod
oneshotを作成してください。イメージはbusybox:1.36、restartPolicyはNever、commandは["/bin/sh","-c","echo done"]です。 - Job
batch-sumを作成してください。completions: 4、parallelism: 2、backoffLimit: 3、PodのrestartPolicyはOnFailure、コンテナのイメージはbusybox:1.36です。 - CronJob
nightly-reportを作成してください。schedule: "17 3 * * *"、concurrencyPolicy: Forbid、startingDeadlineSeconds: 120、successfulJobsHistoryLimit: 3、コンテナのイメージはbusybox:1.36、PodのrestartPolicyはOnFailureです。 ckad-designネームスペースでラベルtier=backendのPodの名前だけを、1行に1つずつ/root/ckad-design/backend-pods.txtに保存してください(pod/の接頭辞なしで名前だけ)。
参考
kubectl run web --image=nginx:1.27 -n ckad-design --labels=app=web,tier=frontend --dry-run=client -o yaml > web.yamlでひな形を出力して編集すると速く済みます。kubectl create job/kubectl create cronjobにも--dry-run=client -o yamlがあります。Jobのspecのcompletionsとparallelismにはフラグがないので、YAMLを直接編集します。- よくある間違い1:
restartPolicyをコンテナの下に書くことです。これはPodレベル(spec.restartPolicy)のフィールドです(例外はネイティブサイドカーだけです)。 - よくある間違い2:
argsに文字列1つで"-c sleep 3600"を入れることです。配列の要素単位に分ける必要があります。 - ステップ8で
kubectl get pods -l tier=backend -o nameはpod/apiのように出力されます。cut -d/ -f2や-o jsonpath='{.items[*].metadata.name}'で名前だけを残します。
ネームスペースと最初のPodを作成する
ネームスペースckad-designを作成し、その中にPod webを作成してください。イメージはnginx:1.27、ラベルはapp=webとtier=frontendです。
先にネームスペースを作成し、その中にPodを作成します。ラベルはmetadata.labelsに入れます。kubectl runに--labelsを付けるか、--dry-run=client -o yamlでひな形を出力して編集すると速く済みます。
ラベルとアノテーションを区別する
Pod webにアノテーションowner=platform-teamを付けてください。同じネームスペースにPod apiを作成してください。イメージはnginx:1.27、ラベルはapp=apiとtier=backendです。
ラベルはセレクターが選ぶ値、アノテーションはセレクターが見ないメモです。すでに作成したPodには、kubectl labelとkubectl annotateであとから付けられます。
commandとargsでイメージのデフォルトを上書きする
Pod runnerを作成してください。イメージはbusybox:1.36、commandは["/bin/sh"]、argsは["-c", "sleep 3600"]です。
commandはDockerfileのENTRYPOINT、argsはCMDを上書きします。どちらもYAMLの文字列の配列で、シェルの構文(;、&&)を使うにはシェルを直接呼び出す必要があります。
環境変数とDownward APIを設定する
Pod envtestを作成してください。イメージはbusybox:1.36、ラベルはtier=backendです。環境変数APP_ENV=productionとAPP_TIER=backendを固定値で入れ、POD_NAMEはDownward APIでmetadata.nameを参照させてください。commandは["/bin/sh","-c","sleep 3600"]です。
固定値はenv[].value、Pod自身のメタデータはenv[].valueFrom.fieldRef.fieldPathで取得します。Pod名のフィールドパスはmetadata.で始まります。
restartPolicyで一回限りのPodを作成する
Pod oneshotを作成してください。イメージはbusybox:1.36、restartPolicyはNever、commandは["/bin/sh","-c","echo done"]です。
spec.restartPolicyはPodレベルのフィールドです。デフォルトのAlwaysは長時間実行向けで、1回動いて終わる作業には別の値を使います。このフィールドは作成後に変更できないため、削除して作り直す必要があります。
Jobの完了数と並列度を設定する
Job batch-sumを作成してください。completions: 4、parallelism: 2、backoffLimit: 3、PodのrestartPolicyはOnFailure、コンテナのイメージはbusybox:1.36です。
completionsは合計で何回成功すれば終わりか、parallelismは同時にいくつ動かすかを表します。backoffLimitは失敗時のリトライの上限で、デフォルト値は6です。JobのPodのrestartPolicyに使える値は2つだけです。
CronJobのスケジュールと同時実行ポリシーを設定する
CronJob nightly-reportを作成してください。schedule: "17 3 * * *"、concurrencyPolicy: Forbid、startingDeadlineSeconds: 120、successfulJobsHistoryLimit: 3、コンテナのイメージはbusybox:1.36、PodのrestartPolicyはOnFailureです。
scheduleは5桁のcron式(分 時 日 月 曜日)です。concurrencyPolicyは前回の実行がまだ終わっていないときの動作で、startingDeadlineSecondsは予定時刻を逃したときに何秒までなら遅れてでも開始するかを表します。
ラベルセレクターで一覧を取り出す(総合)
ckad-designネームスペースでラベルtier=backendのPodの名前だけを、1行に1つずつ/root/ckad-design/backend-pods.txtに保存してください(pod/の接頭辞なしで名前だけ)。
kubectl get pods -l key=valueで絞り込み、-o nameまたは-o jsonpathで名前だけを残します。-o nameはpod/이름の形式なので(プレースホルダーはPod名です)、先頭の接頭辞を切り落とす必要があります。ファイルには名前だけが1行ずつ入っている必要があります。