
本記事はSansan Advent Calendar 2024の24日目の記事です。
こんにちは。技術本部 Strategic Products Engineering Unit Contract One Devグループの髙野です。2024年4月に新卒で入社し、契約データベース「Contract One」の開発をしています。5人チームのリーダーとして、新規機能開発に向き合っています。
Cloud Run jobsのジョブ構成の管理に、KubernetesのManifest管理ツールであるKustomizeを導入したので紹介します。
バッチ処理実行基盤としてのCloud Run jobs
Contract Oneでは、バッチ処理の実行基盤としてCloud Run jobsを使用しています。基盤上にバッチ処理を実装していき、実行時にジョブ名を指定することで、目的のバッチ処理を動かします。コンテナイメージは1つですが、Google Cloud上では各ジョブが独立したリソースになっています。
ジョブ構成はCloud Run job YAMLで管理されており、gcloud run jobs replaceコマンドの引数にYAMLを指定することでジョブをデプロイできます。Contract Oneの実行基盤では、バッチ処理ごと・環境ごとに実行パラメータが違うCloud Run job YAMLファイルを定義しています。
Contract OneでのYAML管理の課題
事業のグロースとともにバッチ処理が増えていて、新しいバッチ処理を作る際には既存のCloud Run job YAMLファイルをコピペして作られることが多いです。しかし、どのパラメータがそのジョブ固有のものかすぐに判断できず、無駄なパラメータが指定されていることもあったため、Cloud Run job YAMLファイルの管理が課題となっていました。
そこで、KubernetesのManifest管理ツールであるKustomizeを導入し、課題解決に取り組みました。
Kustomizeの導入
次のようなディレクトリ構造で管理をしていきます。
.
├── base
└── overlays
├── production
│ ├── base
│ ├── service-a
│ └── service-b
└── staging
├── base
├── service-a
└── service-b
baseディレクトリ
すべてのジョブの基本となるパラメータを定義していきます。
まずは、cloud-run-jobs.yaml で、次のようにCloud Run job YAMLの雛形を定義します。
apiVersion: run.googleapis.com/v1
kind: Job
metadata:
name: batch-job
spec:
template:
spec:
parallelism: 1 # ジョブ毎にpatchする
taskCount: 1 # ジョブ毎にpatchする
template:
spec:
serviceAccountName: dummy # 環境毎にpatchする
maxRetries: 0 # ジョブ毎にpatchする
timeoutSeconds: "86400" # ジョブ毎にpatchする
containers:
- image: dummy # 環境毎にpatchする
resources:
limits:
cpu: "2" # ジョブ毎にpatchする
memory: 2Gi # ジョブ毎にpatchする
env: [ ] # 環境、ジョブ毎にpatchする
次に、shared-env.yamlで、全環境で共通の環境変数を定義します。
# key value のペアで環境変数を設定する
- op: add
path: /spec/template/spec/template/spec/containers/0/env/-
value:
name: SERVICE_NAME
value: batch-job
# Secret Managerからも値を取ってこれる
- op: add
path: /spec/template/spec/template/spec/containers/0/env/-
value:
name: SERVICE_KEY
valueFrom:
secretKeyRef:
key: latest
name: service-key
最後に、kustomization.yamlで、これら2つのファイルを参照するベースファイルを定義します。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cloud-run-jobs.yaml # 雛形
patches:
- path: shared-env.yaml # 環境変数のパッチ
target:
kind: Job
name: batch-job
overlays/{環境名}/baseディレクトリ
環境毎に固有の値をoverlays/{環境名}/baseの中で定義します。staging環境であればoverlays/staging/baseを、production環境であればoverlays/production/baseを作成します。
まず、patch.yamlでサービスアカウントとコンテナイメージ名を置き換えます。
- op: replace path: /spec/template/spec/template/spec/containers/0/image value: us-docker.pkg.dev/cloudrun/container/job:latest - op: replace path: /spec/template/spec/template/spec/serviceAccountName value: サービスアカウント名
次に、kustomization.yamlで、nameにsuffixをつけたり、上で行った置き換えを適用させるベースファイルを定義します。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
nameSuffix: -prod
resources:
- ../../../base
patches:
- path: patch.yaml
target:
kind: Job
name: batch-job
これで環境毎のベースファイルの定義は完了です。環境固有の環境変数がある場合は、shared-env.yamlと同様にファイルを作成し、patchesに追加します。
overlays/{環境名}ディレクトリ
overlays/{環境名}ディレクトリの下に、各バッチ処理のパラメータを定義していきます。
今回は、環境変数とタスク数/並列数を変更したいservice-aと、環境変数のみを変更したいservice-bがあると仮定します。
このとき、service-aの定義は次のようになります。
# overlays/production/service-a/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: service-a-
resources:
- ../base
patches:
- path: patch.yaml
target:
kind: Job
name: batch-job
- path: env.yaml
target:
kind: Job
name: batch-job
# overlays/production/service-a/env.yaml
- op: add
path: /spec/template/spec/template/spec/containers/0/env/-
value:
name: JOB_NAME
value: JOB_A
# overlays/production/service-a/patch.yaml
- op: replace
path: /spec/template/spec/parallelism
value: 2
- op: replace
path: /spec/template/spec/taskCount
value: 2
service-bの定義は次のようになります。
# overlays/production/service-b/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: service-b-
resources:
- ../base
patches:
- path: env.yaml
target:
kind: Job
name: batch-job
# overlays/production/service-b/env.yaml
- op: add
path: /spec/template/spec/template/spec/containers/0/env/-
value:
name: JOB_NAME
value: JOB_B
最終的なファイル構造
上記の手順を環境毎に行うと、次のようなファイル構造になります。
.
├── base
│ ├── cloud-run-jobs.yaml
│ ├── kustomization.yaml
│ └── shared-env.yaml
└── overlays
├── production
│ ├── base
│ │ ├── kustomization.yaml
│ │ ├── patch.yaml
│ │ └── shared-env.yaml
│ ├── service-a
│ │ ├── env.yaml
│ │ ├── kustomization.yaml
│ │ └── patch.yaml
│ └── service-b
│ ├── env.yaml
│ └── kustomization.yaml
└── staging
├── base
│ ├── kustomization.yaml
│ ├── patch.yaml
│ └── shared-env.yaml
├── service-a
│ ├── env.yaml
│ ├── kustomization.yaml
│ └── patch.yaml
└── service-b
├── env.yaml
└── kustomization.yaml
レンダリング
kubectl kustomize ./overlays/{環境名}/{ジョブ名} コマンドで、最終的なCloud Run job YAMLファイルをレンダリングします。
試しに、production環境のservice-aをレンダリングすると、次のようなYAMLが生成されます。parallelismやenvなどの値が置き換えられていることがわかります。
apiVersion: run.googleapis.com/v1
kind: Job
metadata:
name: service-a-batch-job-prod
spec:
template:
spec:
parallelism: 2
taskCount: 2
template:
spec:
containers:
- env:
- name: SERVICE_NAME
value: batch-job
- name: SERVICE_KEY
valueFrom:
secretKeyRef:
key: latest
name: service-key
- name: JOB_NAME
value: JOB_A
image: us-docker.pkg.dev/cloudrun/container/job:latest
resources:
limits:
cpu: "2"
memory: 2Gi
maxRetries: 0
serviceAccountName: サービスアカウント名
timeoutSeconds: "86400"
Contract Oneでは、レンダリングをCDパイプラインに組み込み、デプロイを自動化しています。
まとめ
Kustomizeを使用して、Cloud Run jobsのジョブ構成を管理する方法を紹介しました。すべての環境に共通なbase overlayを元に、環境ごとに差異がある部分のみのoverlayを作成することで、複数ジョブを複数環境でわかりやすく管理できるようになりました。
実は、Kustomizeの導入検討はオフィスのふらっとした立ち話から始まり、開発チームのフットワークの軽さを感じました。そんなContract Oneでは、プロダクトの価値向上に向き合っていく仲間を募集しています! 詳しくは採用情報をご確認ください。