Argo Workflows導入事例: 複数システムの開発基盤をマルチテナントで支える!!

はじめに

モノタロウのプラットフォームエンジニアリング部門 コンテナ基盤グループの宋 明起です。

私たちコンテナ基盤グループは、アプリケーション開発者がコンテナシステムの複雑さに悩まされることなく、アプリ開発に専念できる環境を提供しています。コンテナ基盤の構築・改善を通じて、開発者がより簡単かつ安全にアプリケーションをデプロイ・運用できるように支援しています。

今回はモノタロウのシステムが抱えていた課題を Argo Workflows の導入で解決した話をします。導入にあたり、Argo Workflows を複数のチームで共有可能なマルチテナント環境として構築しました。本記事では、Argo Workflows のマルチテナント環境構築とその運用方法について、参考となる情報を詳しく解説します。具体的には、プラットフォームとしてマルチテナント環境を構築する際に検討した内容や、共通設定の詳細についてお伝えします。

背景

ある日、アプリケーション開発者からバッチ運用・保守における課題を解決する手段としてコンテナ導入に関する相談を受けました。相談を受ける中で、別のチームにもヒアリングを行ったところ、バッチ運用において以下のような共通課題が明らかになりました。

共通の課題

  1. バッチ処理自体の複雑性
    • バッチ処理のロジックが複雑化しており、特にEnd of Life(EOL)対応や仕様変更時の手間が大きな負担となっている。また、モダナイズやコンテナ化の必要性は認識されているものの、「どのように開発・運用を進めるべきか」という具体的な指針や知見が不足している。
  2. 運用方法のばらつきによる煩雑さ
    • 各チームでバッチ処理に使用しているツールや運用方法が統一されておらず、ジョブの管理方法や実行スケジュールの運用がチームごとに異なる状況にある。このため、管理作業が煩雑になり、結果として運用・保守コストが増大している。
  3. ジョブ実行状況の可視性やリカバリ対応の欠如
    • ジョブの実行ステータスをリアルタイムで把握できる仕組みが不足しており、失敗時のリトライや対応が効率的に行えない。
  4. VMやクラスタの運用負荷
    • バッチ処理を実行するための従来型のVMやクラスタの維持・管理が運用チームに大きな負荷をかけている。

要するに 「バッチ処理そのものの複雑性」 と 「運用管理方法のばらつき」 がアプリケーションチームの運用・保守コストを高めているということが分かりました。

そこで、これらの課題を解決するために、複数のチームが共通して利用できる統一されたプラットフォームをコンテナ基盤上に構築することを目指し、その一環でワークフローエンジンである Argo Workflows の導入を検討しました。

コンテナプラットフォームでのジョブ運用

コンテナプラットフォーム上でジョブを管理・運用するために、様々なツールを調査した結果、Argo Workflowsを以下の理由から採用し、導入検討を進めることにしました。 

Argo Workflowsを選定した理由

  1. 充実したGUI機能
    • バッチジョブリストの可視化やジョブのリトライ、一時停止(suspend)など、必要な操作をわかりやすいGUI上で簡単に実施可能。
  2. 柔軟で多様なワークフロー実装
    • 複数ステップのジョブやジョブ間の依存関係の管理、条件付きロジックの組み込みなど、複雑なワークフローを柔軟かつ多様に設計できる。
  3. ジョブの進行状況追跡とデバッグの容易さ
    • cronに基づくスケジュールで実行されるジョブの進行状況やエラーの追跡が簡単で、デバッグ作業効率を向上できる。また、これに限らず、ログやメトリック、イベントを活用することで、環境全体のモニタリングやデバッグがしやすい点も大きな利点です。
  4. パラメータとテンプレート機能の充実
    • 柔軟なパラメータ設定とテンプレート化によるジョブロジックの再利用が可能で、開発効率と運用効率を大幅に向上できる。
  5. 活発なコミュニティと他のコンポーネントとの親和性
    • 活動的なコミュニティによる信頼性の高さに加え、Argo CDとの連携が可能で、システム全体の拡張性を確保できる。

Argo Workflowsは、これら豊富な機能や利点を持つことから、複雑なジョブ管理や効率的なワークフロー構築を求めるプロジェクトに適しているツールとして選びました。

マルチテナント環境でのArgo Workflowsの構築と運用に関する検討

背景で簡単に触れたように、各チームがジョブの運用方法やノウハウを独自に持っていることによる運用・保守上の課題が存在していました。Argo Workflows の導入でそれらの課題を解決しつつも、すべてのチームに対して一貫したサービスとサポートを提供できる状態を構築するために、マルチテナント環境の導入を検討しました。
(* マルチテナント環境とは、ひとつの基盤を複数の利用者やチームで共有しながらも、チームごとのデータや設定を分離して管理できる仕組みを指します。この仕組みにより、共通的な基盤を活用しつつ、それぞれのチームが個別のニーズに対応できる柔軟性を実現します。)

マルチテナント環境における運用上の課題

マルチテナントで運用を行う際に特に考慮しなければならないのは以下の点です

  • Namespaceごとの独立性:各Namespaceが孤立した状態でセキュリティ上の問題がないか。
  • 権限の柔軟な付与:作業制限を設けるために、メンバーごとに異なる権限やRoleを付与できるか。

これらを踏まえ、まず各Namespaceの独立性を確保するための方法について以下の2つのアプローチを検討しました。インターネット上の事例を参考にし、それぞれの方法をテスト環境で実際に試して運用面を評価しました。

  1. Cluster Install
    • 単一のNamespaceにArgo Workflowsをインストールし、全体を共通的に運用する方法。
  2. Managed Namespace Install
    • 各NamespaceごとにArgo Workflowsをインストールし、それぞれ独立して運用する方法。

検討ポイント

運用作業、例えばクラスタのアップグレードやArgo Workflows自体のアップグレード作業を効率的に行う観点からは、1つのArgo-workflowsを運用する「Cluster Install」が最適であると考えられました。しかし、以下の点を踏まえたさらなる検証が必要でした。

  • 各Namespaceごとにユーザー設定やRole設定を柔軟に行えるか。
  • 各Namespaceが独立性を保ちながら、安全で安定した運用が可能か。

これらの課題をクリアするため、SSO(シングルサインオン)やRBAC(ロールベースアクセス制御)に重点を置いて詳細な検討を進めました。

結論

検証の結果、各テナント(ユーザーやチーム)ごとに権限を柔軟に設定し、ユーザーが自分のジョブのみを閲覧・操作できる構成が可能であることが確認できました。この仕組みにより、クラスタ全体に1つのArgo Workflowsを設置して運用する「Cluster Install」方式を採用することを決定しました。 参考リンク

SSO・RBACの検討

Argo WorkflowsのSSO設定

Argo WorkflowsのSSO設定は、既に利用しているArgo CDのDexサーバを活用することで、簡単に導入・設定することができました。この手法により、管理の手間を抑えつつ、SSO環境をスムーズに構築することが可能となりました。

参考リンク

*SSOによるログイン後、ユーザーページにアクセスすることで、取得したユーザー情報を確認することができます。

Argo WorkflowsのRBAC設定

初期設定

Argo Workflowsをセットアップすると、デフォルトで以下の3つのRBAC(Role-Based Access Control)ベースのServiceAccountが作成されます:

  • argo-workflows-admin(管理者用)
  • argo-workflows-edit(編集権限)
  • argo-workflows-view (閲覧専用権限)

初期設定では、以下のように権限を付与しました:

  • 管理者: ClusterRoleBindingでargo-workflows-admin権限を付与。
  • 開発者: 対象Namespaceに紐づくRoleBindingでargo-workflows-edit権限を付与。

課題

しかし、上記の権限設定ではクラスタ全体の操作ができないため、以下の課題が発生しました:

  1. GUIからジョブのログを閲覧できない。
  2. Resubmit機能がPod削除の権限不足で失敗する。
  3. ユーザーごとに権限不足を手動で補完する必要があった。

対応

これらの課題を解決するため、Argo WorkflowsのAggregated ClusterRoles(集約クラスターロール)がクラスタ全体の権限に対応していることを活用しました。特に、edit権限をNamespace単位で付与することで、以下が確認できました:

  • 開発者の操作範囲は、自身がアクセス可能なNamespaceに限定される。
  • 権限はArgo WorkflowsのGUI操作に必要な範囲内に収まる。

そのため、権限設定を以下のように変更しました:

  • 管理者: ClusterRoleBindingでクラスタ全体のadmin権限を付与。
  • 開発者: 対象Namespaceに紐づくRoleBindingでクラスタのedit権限を付与。

結果

これにより、Argo Workflows上での操作(例:ログの閲覧やジョブのResubmitなど)が可能になり、従来、権限不足のために管理者への依頼が必要だった作業が減少しました。その結果、権限を付与する管理者側の手間や対応待ちをする利用者側の負担が大幅に軽減されました。

グローバル設定

運用に必要な設定を全Namespaceに共通して適用するために、グローバル設定を行いました。

Service Accountの統一

Service Account名を「argo-wf-sa」に統一しました。 これは、以下の課題を解決するためです:

  • Workflowマニフェスト内でService Accountを指定し忘れることで発生するエラー
  • 各Namespaceで異なるService Account名を使用する場合、権限付与の設定が手間になる。

そのため、すべてのNamespaceで使用するArgo Workflows用のService Account名を「argo-wf-sa」に統一しました。

Service Accountマニフェスト例:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: argo-wf-sa
  namespace: argo
  annotations:
    workflows.argoproj.io/rbac-rule: '''sample-group@monotaro.com'' in groups'
    workflows.argoproj.io/rbac-rule-precedence: "1"

さらに、Global設定でWorkflowのService Accountにデフォルトで「argo-wf-sa」を利用するよう指定しました。 Helm Values例:

controller:
  workflowDefaults:
    spec:
      serviceAccountName: argo-wf-sa

PDB設定とKarpenter用Annotation

DevやStg環境では、spotインスタンスの終了によってノードがdrainされることがあります。また、ノードスケジューリングの影響により、これは全環境で発生する可能性があります。しかし、ジョブ実行中にノードがdrainされると、ジョブ(コンテナ)が途中で停止してしまうという課題が発生しました。

解決方法

spotインスタンスの問題

  • spotインスタンス利用による予期せぬ中断を防ぐため、spotインスタンスを使用しない専用ノード(nodepool)にジョブをデプロイすることで回避しました。

nodeスケジューリングの問題

  • ジョブ実行中のノードdrainを抑制するため、以下の設定をグローバル設定に追加しました:
    • PDB (PodDisruptionBudget) の設定: Podが不必要に中断されないよう制御。
    • Karpenter用do-not-disrupt Annotation: ノードスケジューリング時にジョブ実行中のpodを保護し、ノードdrainを抑制。

Helm Values例:

controller:
  workflowDefaults:
    spec:
      serviceAccountName: argo-wf-sa
      podDisruptionBudget:
        minAvailable: 100%
      templateDefaults:
        metadata:
          annotations:
            karpenter.sh/do-not-disrupt: "true"

LifeCycle 設定

WorkflowのジョブはPodとして実行され、完了後にはその情報(Status、 Metadata)がControl Planeのetcdに保存されます。一方、Pod本体はcompletedまたはfailedの状態で残り続けます。

完了状態のPodの特性

  • 最小限のリソース(MetadataやLogs用のdisk space等)のみ消費。
  • ノードのCPUやメモリは使用しない。

この完了状態のPodはWorkflowのlifecycleとともに管理されます。

etcdに保存される情報 Podが削除されても、以下の情報はControl Plane上のetcdに保存され、Argo WorkflowsのGUIで継続して閲覧可能です:

  • Resource Definitions: Workflowのリソース情報(CRD)。
  • State Metadata: Workflowのステータス(running、 succeeded、 failed)。
  • Event Data: PodやWorkflowに関連するイベントデータ。

解決方法

ttlStrategy設定 ワークフロー情報が永続的に残らないように、Global設定でttlStrategyを設定し、完了したWorkflowを1ヶ月後に削除するようにしました。この設定は、ユーザーが必要に応じて上書きし、カスタム値を設定することも可能です。

Helm Values例:

controller:
  workflowDefaults:
    spec:
      ttlStrategy:
        secondsAfterCompletion: 2592000 # 30日後に削除

モニタリング設定

Argo WorkflowsのメトリクスをOpenMetrics設定を使用してDatadogに送信するようにしました。

Helm Values例:

 controller:
  podAnnotations:
    ad.datadoghq.com/controller.checks: |
      {
        "openmetrics": {
          "init_config": {},
          "instances": [
            {
              "openmetrics_endpoint": "http://%%host%%:9090/metrics",
              "namespace": "argo",
              "metrics": [".*"]
            }
          ]
        }
      }

Datadog側で取得できるMetricsの確認:

Datadog側でメトリクスを取得し、ジョブの実行状況(durationやstatus)を可視化しました。また、開発者が個別に実装する必要がないよう、以下の設定によりGlobalで送信可能にしています。

Helm Values例:

controller:
  workflowDefaults:
    spec:
      metrics:
        prometheus:
          - name: job_status
            labels:
              - key: job_name
                value: "{{ workflow.name }}"
              - key: namespace
                value: "{{ workflow.namespace }}"
              - key: status
                value: "{{ status }}"
            help: "Result status"
            counter:
              value: "1"
          - name: job_duration # 実行時間
            labels:
              - key: job_name # ジョブ名
                value: "{{ workflow.name }}"
              - key: namespace # ネームスペース
                value: "{{ workflow.namespace }}"
              - key: status
                value: "{{ status }}"
            help: "Duration seconds"
            gauge:
              value: "{{ workflow.duration }}"

Status metrics例:

Duration metrics例:

アラート設定

アラートはDatadogからメトリクスを利用して簡単に設定することが可能です。

各ジョブの失敗や実装上の問題(validation)について、開発者が通知設定を手軽に行えるように、以下の仕組みを構築しました。必要な設定として、自分のNamespaceと通知先のSlackチャンネルを登録するだけで、アラート通知が自動的に有効化されるようになっています。

TerraformによるDatadogアラート設定例:

locals {
  # 以下対象環境のリストにnamespace とslack_channelを追加してください。
  dev_targets = [
    {
      # アラート対象のnamespace
      namespace = "argo"
      # アラートするSlackチャンネル (「#」や「@slack-」のprefixは不要)
      slack_channel = "notif-argo-alert-dev"
    },
・・・
  ]

通知例:

まとめ

この記事では、Argo Workflowsの導入に加え、マルチテナント環境での構築・運用に関する検討内容を中心に紹介しました。導入プロセスでは、さまざまな機能の評価やストレステスト、さらに管理者・利用者向けのマニュアル整備も実施しました。その結果、現在ではArgo Workflowsを活用し、ジョブを安定して運用できる環境を構築することができました。

また、マルチテナント環境の運用を進める中で、各開発者やチームから寄せられる問題点やフィードバックを解決していく過程で培った経験やノウハウをサービスに反映させることで、サポート体制を全体的に強化しています。この積み重ねにより、蓄積された知見を活かして各テナントに対し、さらに良質なソリューションを提供できる体制を構築しています。

この記事を通じてMonotaROや私たちの取り組みにご興味をお持ちいただけた方は、ぜひお気軽にカジュアル面談にお申し込みください。また、チームの採用募集も行っていますので、そちらもぜひご覧ください!