.png?tr=w-1000,h-1000,c-at_max?tr=w-1000,height-1000,c-at_max)
Datadog の Workflow Automation を使って再起不能になった Pod を安全に削除する
Posted on
はじめに
この記事は Datadog Advent Calendar 2025 の3日目の記事です。
こんにちは、プレイドの Developer Experience & Performance チームでエンジニアをしている大矢です。Datadog の好きな機能は CI Visibility と Split Graph です。
Datadog の Workflow Automation は Datadog の Action を組み合わせたワークフローを組むことができる機能です。Datadog の API で提供されているような機能を中心として様々なクラウドプロバイダーや SaaS ツールとも連携できます。
背景:なぜ Pod を削除するのか
私たちが運用しているサービス KARTE は GKE 上に構築されています。普通、Pod にはヘルスチェックが設定されており、サービスが応答できない状態になったらコンテナを再起動するようになっています。しかし、うまくコンテナを再起動するようにコントロールできないケースや、Pod を消して作り直した方が早いケースがこれまでに何度かありました。
例えば、GKE の既知の問題として Image Streaming を有効にしている際に、Image Pull のタイミングによってはファイルが存在せずに実行できないということがありました(https://docs.cloud.google.com/kubernetes-engine/docs/troubleshooting/known-issues?hl=ja#image-screaming-missing-files)。Image Streaming を有効にしているノードの中で、特定のイメージのファイルが欠落することがあるという状態でした。このケースでは、コンテナは再起動されますが同じノードで再起動しようとするため、何度再起動しても正常に起動することはありません。しかし、Pod を削除してしまえば別のノードに配置されるため、起動できる可能性があります。
このように 「Pod を消せば解決する」パターンはいくつかあり、社内では Pod を削除するマニュアルを作って、既知の問題には Pod を削除して解決することがしばしばありました。しかし、Datadog の画面上から問題の Pod 名を抽出した後に、GCP の管理画面もしくは CLI 上から Pod 削除を実行するというもので、地味に面倒くさいというのと決まりきった作業なのに自動化できていないという問題点がありました。
Private Action Runner のセットアップ
今回作成する Workflow では Pod を削除する Action を使用します。Kubernetes Core というカテゴリにあるアクションを使用する場合には Private Action Runner をインストールする必要があります。
App Builder モードと Workflow Automation モードがありますが、今回は Workflow Automation でしか使用しないため Workflow Automation モードを使用します。
https://docs.datadoghq.com/ja/actions/private_actions/#workflow-automation-mode

Datadog の管理画面上から手順を進めていくと、次のようなコマンドを実行するように指示されます。
docker run \
-e DD_BASE_URL=https://us5.datadoghq.com \
-e RUNNER_ENROLLMENT_TOKEN=xxx \
-e STATSD_ENABLED=true \
gcr.io/datadoghq/private-action-runner:v1.14.0 \
--enroll-and-print-config
これを実行すると Helm charts に設定するべき config が生成されます。Pod を削除するアクションのみを許可した場合の config は次のようになりました。
actionsAllowlist:
- com.datadoghq.kubernetes.core.deletePod
allowlist:
- '*'
allowIMDSEndpoint: false
ddBaseURL: https://us5.datadoghq.com
modes:
- pull
port: 9016
privateKey: xxx
urn: xxx
reportMetrics: true
注意点としては3つあります。
まず1つ目は secret の扱いです。Kubernetes を運用する場合 GitOps のように GitHub に Manifest をコミットして管理することが多いと思います。その場合には secret をそのままコミットするわけにはいきません。runnerIdentitySecret を使用して Secret リソースを参照するようにし、Secret リソース自体は External Secrets Operator などのツールを使って管理します。
2つ目にスキーマが違う問題がありました。 下記の設定はエラーになります。
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
helmCharts:
- name: private-action-runner
includeCRDs: true
valuesFile: values.yaml
releaseName: private-action-runner
version: v1.18.0
repo: https://helm.datadoghq.com
# values.yaml
$schema: https://raw.githubusercontent.com/DataDog/helm-charts/private-action-runner-1.18.0/charts/private-action-runner/values.schema.json
runner:
runnerIdentitySecret: "datadog-runner-identity"
# Replace this section with the output of the private action runner enrollment process with the `--enroll-and-print-config` flag
config:
allowIMDSEndpoint: false
ddBaseURL: https://us5.datadoghq.com
modes:
- pull
port: 9016
reportMetrics: true
actionsAllowlist:
- com.datadoghq.kubernetes.core.deletePod
allowlist:
- '*'
$ kustomize build .
Error: Error: values don't meet the specifications of the schema(s) in the following chart(s):
private-action-runner:
- runner.config: Additional property reportMetrics is not allowed
- runner.config: Additional property allowlist is not allowed
allowlist と reportMetrics のパラメータはドキュメントを見る限りすでに許可されていませんでした。そのためこれらのパラメータは消しました。
3つ目に actionsAllowlist についてですが、これを設定するだけでは private action runner が Pod を削除することはできませんでした。理由としては、この Helm charts で作成された Role リソース(private-action-runner に Bind されています)に Pod delete が割り当てられていないからです。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: private-action-runner
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
結局、ドキュメントを見ていると kubernetesActions というパラメータがあったのでこれを設定することで Pod を削除する権限を与えることができました。
# values.yaml
$schema: https://raw.githubusercontent.com/DataDog/helm-charts/private-action-runner-1.18.0/charts/private-action-runner/values.schema.json
runner:
runnerIdentitySecret: "datadog-runner-identity"
# Replace this section with the output of the private action runner enrollment process with the `--enroll-and-print-config` flag
config:
allowIMDSEndpoint: false
ddBaseURL: https://us5.datadoghq.com
modes:
- pull
port: 9016
kubernetesActions:
pods: ["get","list", "delete"]
あとは、Private Action Runner 作成の手順に従って、Connection を作成します。Credentials は Service account authentication を選ぶのがスムーズです。

Private Action Runner をインストールした際には、シンプルに Pod 削除をするだけの Workflow を作って検証するのが良いと思います。まずは pod 名を指定して削除するだけの Workflow を作り、テスト実行しました。

作った Workflow
最終的には次のようなワークフローを作りました。説明しやすさのために4つのセクションに色分けをしています。

- トリガーとパラメータの準備
- 10分以内に同じ Deployment の Pod 削除が実行されていないかのチェック
- Ready Pod が Desired Pod よりも少なくないことのチェック
- 通知と Pod 削除の実行
となっています。それぞれ解説していきます。
1. トリガーとパラメータの準備
Workflow Automation ではトリガーを設定します。いくつかやり方がありますが、今回のように異常を検知してその異常に対して何かアクションをするようなケースでは Monitor が適しています。Monitor の Mention として Workflow を設定できます。
@workflow-pod-delete(pod_name="{{pod_name.name}}",slack_channel="#hogehoge")
Mention にはパラメータを渡すことができます。どの Pod を削除するかというのはどの Pod で問題が起きているかによるので、パラメータとして渡す必要があります。ログやメトリクスのモニターを作る場合には pod_name で Group By して Multi Alert を設定することで、{{ pod_name.name }} を変数展開して渡すことが可能です。他にも、パラメータをうまく活用することで Workflow を汎用化することができます。例えば slack_channel というパラメータを用意していますが、これをすることで様々なチームでこの Workflow を利用することができます。モニターのメンションとして slack チャンネルを指定することもできますが、Workflow のパラメータとして slack_channel を用意している理由については後述します。
トリガーの次に deployment name というステップで Deployment 名を抽出しています。Data Transformation というアクションを使用し、次のような式を書いています。
$.Trigger.pod_name.split('-').slice(0, -2).join('-')
これだけで、Pod 名から Deployment 名を取得することが可能です。Deployment 名をパラメータとして渡すこともできます(モニターを pod_name と deployment_name の Multi Alert にすれば良い)が、使う側でパラメータが増えるというのと無駄な Group By が増えるのでこのようにちょっとしたパラメータの準備をしています。
2. 10分以内に同じ Deployment の Pod 削除が実行されていないかのチェック
Pod を削除する処理が短い時間で何度も行われているということは、何か想定していない事象が起きている可能性が高いです。Workflow や Monitor の設定方法が間違っていた場合、正常に動いているのに Pod を削除し続けてしまい障害になるということもあり得ます。そのような事故を防ぐための予防策として、10分間のクールタイムを設定したいと考えました。
これには Datastore という機能を利用しています。「Get Timestamp」ステップでは Deployment 名をキーとして、その Deployment に対して Pod 削除が実行された最新のタイムスタンプを取得しています。次の「has 10 min passed」では、そのタイムスタンプから10分以上経過しているかを JavaScript でチェックしています。もし10分以内に Pod 削除を実行していなければ、「Put item」で Deployment 名をキーとして現在のタイムスタンプを保存します。
3. Ready Pod が Desired Pod よりも少なくないことのチェック
Desired Pod に対して Running Pod が足りてない場合、Pod 削除を実行することにより Pod が不足し、リクエストを捌ききれなくなる可能性があります。このような場合には Pod 削除を自動で実行することは避けておいた方が無難です。
Desired Pod は Datadog Action の Query scalar data で取得し、Ready Pod は Kubernetes Action の List pod で取得しています。Query scalar data は Datadog の Metrics に対する集計値を取得することができます。Query window の最小値が1分なためどうしてもラグがありますが、 kubernetes_state.deployment.replicas_desired のメトリクスの最大値としています。

Kubernetes Action で Deployment の replicas を直接取得する方法もありそうでしたが、Private Action Runner に Deployment の get の権限をつける必要がありそうで、面倒だったのでこのやり方にしています。
Ready Pod の取得では List pod を叩いた後に、status を確認して Ready なものの数を確認します。List pod では pod の状態が取得できるため、次のようなクエリを書いて Ready なものを抽出します。
$.Steps.List_pod.items.filter(value => value.status.containerStatuses.every(s => s.ready)).length
Desired Pod 数の取得と Ready Pod 数の取得を並列で行い、それらを比較することで自動で Pod を削除できるかの判断をします。
4. 通知と Pod 削除の実行
2, 3 のそれぞれの条件が True であれば自動的に Pod の削除を実行します。「Send pre delete」のステップでは Pod 削除を実行する前のログとしての通知を slack に送信します。次に「Delete pod」で削除を実行します。Pod がすでに存在しない場合など、「Delete pod」が失敗することもあるので、失敗時にも通知されるようにしています。
また、2, 3 の条件のいずれかが False であれば、Pod を削除することのリスクが高い可能性があります。しかし場合によっては Pod を削除した方が良い可能性もあるので、「Make a decision」というアクションを使って Approve されたら「Delete pod」を実行するというようにしています(単純に「Make a decision」を使ってみたかったというのもあります)。
まとめ
この記事では、Datadog の Workflow Automation を使って、安全に Pod を削除する方法を紹介しました。今回作成した Workflow によって問題が起きた Pod を削除するという手間を省くことができるようになりました。
Workflow Automation で使える Action はとても豊富で、他にも色々な活用方法がありそうです。Preview ですが Agent Builder という機能を使うことで AI Agent によるアクションを Workflow に埋め込むこともできそうなので、試してみたいと思います。