ArgoWorkflow + Events を導入して撤退した話 - SRE的振り返り

目次

はじめに

こんにちは。saorioと申します。普段はDevOpsを担当しています。最近、一度は使ってみたものの、運用を続ける中でビジネス要件や再現性の低い失敗対応に苦しみ、最終的にリプレースしたシステムの話をしたいと思います。

SRE的な観点も交えつつ、導入当時の判断、運用中に露呈した問題、そして撤退という意思決定までを振り返ります。

学んだこと

  • Argo Workflow には CronWorkflow はあるが、PubSub トリガー構成では Job 発火と Node 確保のタイミングを揃える標準機能がない
  • RAM が多い GCE Node を Cluster Autoscaler で 0 -> 1 起動すると、公式記載の 80 〜 120 秒に加えてイメージ Pull でさらに時間がかかる
  • 運用がつらくても「やめたい」と言い出しづらい。だからこそ、思い切って言語化することが重要
  • Observability を後付けするのは高コスト。失敗原因を追える設計は導入時に行うべきだった
  • Bus Factor = 1 のシステムは崩れやすい。推進者が抜けた瞬間に ownership が消える

前提となるシステム

このシステムは PubSub から Job 起動メッセージを受け取り、GKE 上で重量級のデータ処理を Job 実行していました。

利用技術としては、Argo WorkflowsArgo Events を採用していました。

利用していた構成は次の通りです。

PubSub -> Argo Events(Sensor) -> Argo Workflow(Workflow起動) -> Pod(GKE Node起動) -> Job実行

RAM が多い Compute Engine を必要とするため、コスト最適化として NodeSelector + Cluster Autoscaler で Node を 0 から起動する構成にしていました。

タイムライン

  • 2023年前半: 最初の Argo Workflow manifest を導入
  • 2023年後半: Role/ServiceAccount 整備、PubSub -> Argo Sensor 経由の起動体制を構築
  • 2024年: メインアプリケーションエンジニア 2 名 + 私で運用継続
  • 2024年後半: 導入推進エンジニアが退職。引き継ぎ・ドキュメントはほぼ無し
  • 2025年: Job 数増加とアプリケーション heavy 化により運用問題が顕在化
  • 2025年中旬: retryStrategy 追加(効果は限定的)
  • 2025年後半: node affinity 更新、Slack 通知修正など断続的にパッチ
  • 2025年末: Argo Events の NATS から JetStream への切り替えを試行
  • 2026年前半: Datadog metrics 統合を追加、撤退提案を開始
  • 2026年中旬: retry 回数調整、Slack 通知削除、autoscalingpolicy 見直し
  • 2026年6月: Argo 関連 manifest 全削除
  • 2026年7月: Argo helm/role 一式削除。撤退完了

導入から撤退まで実質約 3 年半、私が主に対応してから約 1 年運用しました。

運用中に露呈した問題

問題1: Node 起動タイミングと Workflow スケジュールが噛み合わない

結論として、Argo Workflow(+Events) と Cluster Autoscaling はタイミング次第で Workflow がスケジュール失敗することがありました。

NodeSelector を使って Pod をスケジュールしたい場合、Cluster Autoscaler で 0 -> 1 起動すると、立ち上げに時間がかかり、Scheduler が対象 Node を見つけられないことがありました。

Predicate NodeAffinity failed
didn't match Pod's node affinity/selector

GKE 公式には Cluster Autoscaler の反映目安が 80 〜 120 秒とあります。

Provision extra compute capacity for rapid Pod scaling  |  Google Kubernetes Engine (GKE)  |  Google Cloud Documentation Reserve extra compute capacity in your clusters to improve Pod scaling times. Google Cloud Documentation

実際には heavy なイメージの Pull 時間が上乗せされ、120 秒を超えるケースが常態化していました。

また、この現象は私たち固有ではなく、Argo Workflows の issue でも同系統の問題として報告があります。

GKE Pod/Node Exhaustion Resulting in Failed Workflows · Issue #4794 · argoproj/argo-workflows Summary We're evaluating utilizing Argo (Workflows and Events) to replace our current utilization of Airflow. We have some fairly high volume requirements, starting at around 100 Workflows/minute a... GitHub

問題2: retryStrategy を書いても効かなかった

2025 年 7 月に次の設定を導入しました。

retryStrategy:
  limit: 3
  retryPolicy: "OnFailure"
  backoff:
    duration: "20s"
  expression: |
    lastRetry.message.contains("Predicate NodeAffinity failed") ||
    lastRetry.message.contains("didn't match Pod's node affinity/selector")

しかし効果は限定的でした。

  • backoff.duration: 20s は短い。20 秒 x 3 回 = 60 秒では Node 起動完了を待てない
  • expression が文字列一致依存で、環境差分に弱い
  • retryStrategy の適用境界と scheduling failure の関係で、期待通りに効かないケースがある

問題3: 失敗原因通知が空になる

Argo Workflow 失敗時に Slack 通知していましたが、本文が空の通知が多発しました。

修正を重ねても、workflow status と通知テンプレートの整合が安定せず、結局 kubectl logs を毎回確認する運用が続きました。

SRE 的には、これは「actionable でないアラート」であり、Observability failure です。

問題4: NATS のハートビート問題で Argo Events Pod が消える

Argo Events の EventBus は当初 NATS (stan.go) を使っていましたが、ハートビート由来で Pod が一時消失する事象がありました。

Nats Streaming Client Disconnect Issue · Issue #159 · nats-io/stan.go I posted this on google groups as well so putting it verbatim: I am using Golang streaming client and have a following topology: -- service 1 --- establishes NatsConnection during startup -- servic... GitHub

stan.go は deprecated であり、Argo Events 側も JetStream への移行を推奨していたため、切り替えを試しました。

# 変更前
nats:
  native:
    replicas: 3
    auth: token

# 変更後
jetstream:
  version: 2.10.10
  replicas: 3
  persistence:
    ...

ただし検証結果と移行コストを踏まえ、本番採用は見送りました。

撤退の意思決定

次の観点を Issue に整理し、アプリケーションメンバーへ提案しました。

  • Job fail 原因調査の運用負荷が高い
  • Cluster Autoscaling 頼りの構造的失敗リスクが消えない
  • 観測性の後付けコストが見合わない

結果として、予想より早く撤退方針に合意できました。

SRE 的には次の要因が大きかったと考えています。

  • Ownership が薄れたシステムに unresolved な critical 問題が積み重なっていた
  • 心理的安全性があり、撤退提案を出せた
  • 可逆性を持った構成だったため、Kubernetes Job へ移行しやすかった

撤退後

  • Argo 関連 manifest を削除
  • Argo helm/role を削除

SRE 的教訓

  1. 観測性は導入時に組み込む
  2. Bus Factor を意識する
  3. Toil を数値化して可視化する
  4. 可逆性を保つ設計を選ぶ
  5. 心理的安全性は技術的意思決定を速くする
  6. 導入時テストには限界がある。だから戻せる設計が必要
  7. E2E テスト結果と運用設計はレビュー責務を明確にする

おわりに

Argo Workflow + Events は多くの現場で成功しているツールです。

今回の問題は「Cluster Autoscaling 0 -> 1」「Heavy なイメージ」「NodeSelector 必須」という条件での組み合わせに起因していました。ツールが悪いのではなく私たちのユースケースに合わなかったのです。

この振り返りは Argo 批判ではなく、導入時想定の甘さ、運用変化、そして撤退判断を含めた SRE 的学びとして残しておきます。