背景
- 前職に引き続き、現職でもArgo Workflowsを使ってデータエンジニアリング系のバッチ処理を行なっている
- 以前にCloud Workflowsを調査したことがあったが、まだちょっと厳しい感があった
- 前職ではCloud Monitoringで監視していたが、現職ではDatadogで監視しているので、全社の体制に合わせてDatadogで監視していきたい
- Argo WorkflowsはPrometheus Metricsに対応しており、Datadogはagent経由でPrometheus Metricsの収集を容易に行なえることが分かった
- 同僚のSREであるtapihさんから教えていただいてました、ありがとうございます
- メトリックの収集や投稿を自前でやるより手軽にいけそうなので、この方法を試してみたというのがこのエントリの内容
- GKEクラスタにdatadog agentを仕込んでもらうところはtapihさんにやってもらっていたので、今回の内容からは省きます
具体的な設定
コントローラーに設定を生やす
datadog agentはArgo Workflowsのコントローラー側に対して、定期的にメトリックを収集しにやってくる。そのためのエンドポイントの設定やどのメトリックの収集を許すかの設定を書く。
具体的にはこういった設定になった。Default Controller Metricsもあるが、それだとworkflow単位の監視には足りないことが多いため、カスタムメトリクスがメインの対象となる。今回はworkflowの実行時間をduration
、workflowの成否をexit_code
として定義した。
controller: podAnnotations: ad.datadoghq.com/controller.checks: | { "openmetrics": { "init_config": {}, "instances": [ { "openmetrics_endpoint": "http://%%host%%:9090/metrics", "namespace": "argo_workflows", "metrics": [ {"argo_workflows_duration":"duration"}, {"argo_workflows_exit_code":"exit_code"} ] } ] } }
workflowを監視するためのカスタムメトリクスを定義する
各workflowに対してカスタムメトリクスを定義していく。基本的には公式ページを参考にするのがよいが、細かいところで罠が色々あった。
- workflowの成否を判定するためのカスタムメトリクスをどう定義するか
- 成否自体は
status
という変数に入っているが、datadogに送るのはメトリクスである必要がある - 定数 +
status
をラベルで送る作戦はうまくいかなかった- ラベルが異なると異なるメトリクスの系列として扱われてしまうため、思ったような監視ができなさそうであった
- 成否自体は
- stepsを使うworkflow*1では
exitCode
が取れないexitCode
をカスタムメトリクスとして送って、0より大きければworkflowが失敗していると判定できるかと思っていたが、それだとダメなケースがある- 単一stepで終わるworkflowであれば問題ないが、複数のstepsからなるworkflowだと
exitCode
が取れない- エラーメッセージ:
MetricsError: unable to substitute parameters for metric 'exit_code': failed to resolve {{ exitCode }}
- 実際の
status.nodes
のyamlを見てみると確かに複数stepsの場合はexitCode
が含まれていなかった
- エラーメッセージ:
以上のことを回避しつつ、監視用のメトリクスを定義しようと試行錯誤した結果、以下のように落ち着いた。exit_code
をwhen
込みで2回定義しているのが気持ち悪いが、メトリクスの系列が別々の扱いにならないようにしようと思うとこうなってしまった(Failedのみだと、Failed => Succeededに切り変わったことがメトリクスとして表現できない)。
apiVersion: argoproj.io/v1alpha1 kind: CronWorkflow metadata: ... spec: workflowSpec: metrics: prometheus: - name: exit_code labels: - key: namespace value: "{{ workflow.namespace }}" help: "Exit code of workflow" when: "{{ status }} == Succeeded" gauge: value: "0" - name: exit_code labels: - key: namespace value: "{{ workflow.namespace }}" help: "Exit code of workflow" when: "{{ status }} != Succeeded" gauge: value: "1" - name: duration labels: - key: namespace value: "{{ workflow.namespace }}" help: "Duration seconds" gauge: value: "{{ workflow.duration }}"
これらのカスタムメトリクスをDatadogに投稿すると、以下のようなグラフが得られる。
これらのグラフにより、以下のような御利益が得られる。
- いつからいつまでWorkflowが落ちていたのかが分かる
- バッチの信頼性を高めるためにSLOを定義したいのであれば、そもそもこういった計測をしていく必要がある
- バッチの実行時間の推移が分かる
- どの時期のdeployから変化があったのかが分かると、パフォーマンス改善もしやすい
各workflowに同様のカスタムメトリクスを定義する
カスタムメトリクスの定義ができたが、これを各workfow毎にコピペして回るのはしたくない。いくつかの方法を検討したので、ログを残しておく。
- 作戦1: Default Workflow Specを使う
- 試行錯誤してみたところ、CronWorkflowではうまく反映されないということが分かった
- Workflowでしかうまく動かず、Workflowの中でもうまく動かないフィールドがあることが分かった
- 例:
ttlStrategy
は動くが、mertics
は動かなかった
- 例:
- 作戦2: Cluster Workflow Templates + Exit handlersを使う
- Cluster Workflow Templatesで共通定義をして、Exit handlersでworkflowsの成否に関わらずmetricsを投稿する作戦
- うまくいきそうではあったが、この方法だとdurationがworkflows全体ではなくexit handlersの実行時間になってしまうため、workflowsの実行時間が取れなくなってしまう
- 作戦3: helmの
toYaml
関数を使い、共通定義を読み取る- 結局、これに落ち着いた
- 共通定義のyamlファイルを置いておき、helmのtoYaml関数でそれを参照する(参考)する
- helm依存なのが微妙な感はあるが、作戦1や作戦2だと動かない or 要件に足りない
最終的には作戦3で、以下のように定義した。
spec: workflowSpec: {{- nindent 4 (toYaml .Values.prometheusMetricsForDataDog) }}
デバッグ方法
「カスタムメトリクスを定義したけど、Datadog上で全然メトリクス流れてこないな...」というときにデバッグ方法で困ったので、それもメモしておく。
そもそもprometheusのエンドポイントに対象のカスタムメトリクスが含まれているかは実際にエンドポイントを叩いてみるとよい。まず、k8sクラスタへのcredentialsがある状態で、port-forwardする。
% kubectl port-forward -n workflows deploy/argo-workflows-workflow-controller 9090:9090
あとはcurlを使って実際にエンドポイントを叩いてみるとよい。正しく動いていれば以下のような出力になる。ここにカスタムメトリクスが含まれていないようであれば定義がおかしいし、ここに含まれているのにDatadog上でメトリクス流れてこないという場合はdatadogのagentのlogを見るとよい。
% curl -s localhost:9090/metrics | grep -e argo_workflows_duration -e argo_workflows_exit_code # HELP argo_workflows_duration Duration seconds # TYPE argo_workflows_duration gauge argo_workflows_duration{namespace="my-workflow"} 208.508275 # HELP argo_workflows_exit_code Exit code of workflow # TYPE argo_workflows_exit_code gauge argo_workflows_exit_code{namespace="my-workflow"} 0
所感
- prometheusは便利
- 名前は聞いたことあるという感じだったが、エコシステムができあがっているので、自前で色々頑張らなくてもさっとできるのは便利
- とはいえ、Workflow単位で成否を見ようとすると色々罠があった
- 必要な変数が参照できないケースなどがあり、バッチの監視に利用しようと思うと一工夫が必要
- まあまあ時間を溶かした...
- やっぱり監視の仕組みがあると、バッチを安心して運用できる感は高い
*1:試してないけど、dagも多分同じ