注意 この記事はWIPのPRに基づいて書かれているためリリース版と大きく仕様が異なる可能性があります。(2019/12/1現在)
はじめに
ArgoはKubernetes上でジョブを制御することを目的としたコンテナネイティブなワークフローエンジンです。ジョブの並列制御やリトライ設定ができるのはもちろんのこと、必要な時だけコンテナが立ち上げるのでリソースを専有するなく効率的に実行することができます。Argoにはその他にも様々な機能がありますが今回は割愛します。
筆者が担当しているプロダクトでは当初、他のワークフローエンジンを導入しましたがKubernetesとの相性が悪かったためArgoに乗り換えました。しかし、いざ運用しようとすると所々に辛い部分がありました。その辛みの一つがスケジュール実行機能が無いことです。
このスケジュール実行機能がArgoのネイティブとしてサポートされそうです。2019/12/1現在、WIPのPRの状態ですが待ちきれずローカルでビルドして触ってみました。
Argoのスケジュール実行の現状
Digdagなどのワークフローエンジンではスケジュール実行をサポートしていますが、Argoは単体でこれをサポートしていません。Argoをスケジュール実行させる方法は主に2つ紹介されています。
KubernetesのCronJob
KubernetesのCronJob内でargo submit
コマンドを実行することでキックします。詳しくはこちらの記事で紹介されています。
Argo EventsのCalendar
Argo EventsはArgo Projectの一つであり、さまざまイベントソースをきっかけにArgoをキックすることができます。その中にCalendarというイベントソースがありCron形式でスケジュール実行を定義することができます。筆者のプロダクトではCloud Pub/Subをきっかけにトリガーしたいワークフローもあったためこちらの方法を取りました。しかし、最初にGatewayやSensorといった特有の概念を理解する必要があり、さらに複数のワークフローを扱う際にSensor定義が複雑なので使いこなすのに時間が必要でした。
いずれにしても、WorkflowをConfigMapに保存したりYAMLにインラインで定義する必要があり単にスケジュール実行したいという欲求に対してひと手間もふた手間も必要な状態です。
コミュニティでの議論
こちらのIssueでCron形式でのWorkflowの実行について議論されています。前項で示したように、やろうと思えばできなくはないものの複雑な設定が必要であり、やはりワークフローエンジンとしてスケジュール実行は基本でありネイティブでサポートすべきだとの声があがりました。仕様はKubernetesのJobとCronJobの関係と同様に現状のCustom Resource Definition(CDR)であるWorkflowとは別にCronWorkflowを新たに定義することが提案されました。そして現在、simster7さんがこちらのPRで実装してくださっています。この機能は2020年1月のv2.5に含まれることが予定されているので議論開始からおおよそ1年でリリースされることになります。
CronWorkflowの仕様
KubernetesのCronJobのすべてのオプションをサポートし、既存のWorkflowを簡単にCronWorkflowに変換できるようにするとの指針が掲げられています。
具体的には下記のオプションが追加される予定とのことです。
- schedule
通常のcronフォーマット形式の他にKubernetesのCronJobに用いられているライブラリと同じものが使われているので@hourly
といった指定もできます - startingDeadlineSeconds
- concurrencyPolicy
- suspend
- successfulJobsHistoryLimit / failedJobsHistoryLimit
実際に触ってみた
PRに示されている例を参考に実装途中のブランチをローカルでビルドしてGKEにデプロイし実際にCronWorkflowを動かしてみました。
ローカルでのビルドとデプロイはCONTRIBUTING.mdに従えばわりと簡単にできます(最後のhelm install
がなぜかできなかったためインストール用のmanifestのworkflow-controllerのimageを自前ビルドしたものを指定してデプロイしました)。今回はargoコマンドに新たなコマンドが追加されているのでCLIのビルドも必要です。
PR上で示されてるサンプルを実行してみます。
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
name: test-cron-wf
spec:
schedule: "* * * * *"
concurrencyPolicy: "Replace"
startingDeadlineSeconds: 0
workflowSpec:
entrypoint: whalesay
templates:
- name: whalesay
container:
image: alpine:3.6
command: [sh, -c]
args: ["date"]
argo submit
ではなくK8sのCronJobと同様にargo cron create
コマンドを使います。
% ./dist/argo cron create test-cron.yaml
Name: test-cron-wf
Namespace: default
Created: Sun Dec 01 13:30:01 +0900 (now)
Schedule: * * * * *
Suspended: false
StartingDeadlineSeconds: 0}
ConcurrencyPolicy: Replace
一覧では前回実行時間も確認できます。
% ./dist/argo cron list
NAME AGE LAST RUN SCHEDULE SUSPENDED
test-cron-wf 1m 3s * * * * * false
現状のArgo UIではそれぞれが単体で実行されたように表示されます。
現時点でsuccessfulJobsHistoryLimit
とfailedJobsHistoryLimit
は未実装のため試せていませんが、PodGCのPRで将来的に欲しい機能とされてた直近のいくつかのPodを残す機能が実質的に別の形で実装されるということになりそうです。ちなみにCronWorkflowとPodGCは併用ができました。
##今後の期待(個人の意見)
さらに期待するとするならばArgo UIの改善です。CronWorkflow単位での表示とUIからの手動実行が実装されれば他のワークフローエンジンと遜色なく使えるのではないかと思います。今までは実行の度にWorkflow定義をアップロードする形式でしたがCronWorkflowではWorkflow定義をArgoが保持しておく形になるので、これらを実現することが可能になるのではないかと予想しています。
おわりに
現在、実装途中のArgoのCronWorkflowについてIssueやPRをもとに仕様や実際に使った様子を紹介しました。CronWorkflowの登場により実際のプロダクトへの導入や運用が簡単になるのではないかと感じています。
余談
Argoを筆者のプロダクトに導入した際は実際の運用に必要な機能が不足していることを認識しつつ「K8sでワークフローエンジンを使うならArgo一択なのできっと必要な機能は後からついてくるだろう」と考え正直先走った意思決定をしました。なので、このような機能がArgoに実装されていくことは非常にありがたいです。simster7さんをはじめArgoプロジェクトのコントリビュータの方々には頭があがりません。この場を借りて感謝申し上げます。