ArgoのCronWorkflow解説（設定方法・手動実行の方法など）

## はじめに
お疲れさまです！みなさん元気にワークフロー構築してますかー？
2/19についにArgo Workflow v2.5.0がリリースされまして[^1]、CronWorkflowがGA版で使えるようになったので、使い方やオプションについて解説していきたいと思います。

[^1]: これを書いてる2/29にはv2.6.0がリリースされてるので遅きに失した感ありますけど


## 事前準備
- Kubernetesが利用可能であること
  - Docker for desktopやminikubeでKubernetesが利用可能な状態にしておいてください。

## Argoの準備
### Argo CLIのインストール
argoの操作には`argo`コマンドを使うので、あらかじめインストールしておいてください。
**この記事で解説しているCronWorkflowの手動実行にはargo 2.5.2以上のCLIが必要なので、バージョンが古い人はargoコマンドをアップグレードしてください！**

```bash
# Mac
$ brew install argoproj/tap/argo # アップグレードする人は brew upgrade argoしてください

# Linux
$ curl -sSL -o /usr/local/bin/argo https://github.com/argoproj/argo/releases/download/v2.5.2/argo-linux-amd64
$ chmod +x /usr/local/bin/argo
```

### Argoのインストール
今回はシンプルなWorkflowを実行するだけのつもりなので、minioとかworkflow-controller-configmapは準備せずにArgoのみインストールしてしまいます。

```bash
$ kubectl create ns argo
$ kubectl apply -n argo -f https://raw.githubusercontent.com/argoproj/argo/v2.6.0/manifests/install.yaml
```

## CronWorkflowのマニフェスト
今回は本当にシンプルに、cowsayコマンドを定期実行するCronWorkflowを作成してみます。
CronWorkflowはWorkflow CRDとの互換性を保つため、Workflowで利用できる全てのオプションが利用可能な作りになっています。
今までWorkflowで定義していた項目はworkflowSpecの中に定義するフォーマットになっているので、既存のWorkflowを定期実行したいという人は、Workflowのspecの中身をCronWorkflowのworkflowSpecに登録すればそのままCron化が可能です。

この記事ではWorkflowと共通のオプションには細かく説明せず、CronWorkflow特有のオプションについて解説したいと思います。
今回作成したマニフェストは以下の通りです。オプションについて順に見ていきましょう。

```yaml
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
  name: cron-workflow-whalesay
spec:
  schedule: "* * * * *"
  timezone: "Asia/Tokyo"
  # 複数のワークフローが同時にスケジュールされた場合の処理​​を決定するポリシー
  concurrencyPolicy: "Replace"
  # 本来の実行時刻を過ぎても実行したい場合のオプション
  startingDeadlineSeconds: 0
  # 成功したワークフローの数。この設定だと4回以上成功すると古いworkflowの結果から削除されていく
  successfulJobsHistoryLimit: 3
  # 失敗したワークフローの数。この設定だと2回以上失敗すると古いworkflowの結果から削除されていく
  failedJobsHistoryLimit: 1
  workflowSpec:
    entrypoint: whalesay
    templates:
    - name: whalesay
      container:
        image: docker/whalesay
        command: [cowsay]
        args: ["hello cron workflow!!!!"]
```

- workflowSpecはArgoの通常のWorkflowと全く同じマニフェスト
- CronWorkflow独自の設定について説明する
  - schedule
  - timezone
  - concurrencyPolicy
    - 同じ種類のワークフローが同時にスケジュールされた場合の処理をどうするかを設定できる
    - Allow: 全てのタスクを許可。つまり古いjobと新しいjobが並列動作する
    - Replace: 新しいスケジュールを設定する前に古いものをすべて削除。つまり古いjobが残っていたらterminateされる
    - Forbid: 古いjobが残っているうちは新しいjobは動かさない
  - startingDeadlineSeconds
    - concurrencyPolicyがForbidの時などに新しいjobが動けない状態が発生した場合に、本来の実行時刻を過ぎても実行したい場合数値を入力する
    - 0だと本来の実行時刻を逃したjobは実行されない
    - 60だと本来の実行予定時刻から60秒以内にWorkflowが実行可能な状態になれば実行される
  - successfulJobsHistoryLimit
  - failedJobsHistoryLimit

### schedule
これはわかりやすいですね。cronと同じインターフェースで、workflowSpecで定義したjobをいつ実行するかを指定するオプションです。

### timezone
これもわかりやすいですね。どのタイムゾーンの時刻に合わせてcronを実行するかを設定します。
みなさん大体 `"Asia/Tokyo"`を指定することになるんじゃないでしょうか。

### concurrencyPolicy
これはちょっとわかりづらいかもしれないですね。
同じ種類のワークフローが同時にスケジュールされた場合の処理をどうするかを設定できるオプションです。
例えば、毎分実行している本来1分で終わるはずのworkflowがなんらかの理由で１分半かかってしまった、というシチュエーションで
- 1分後に起動される予定のworkflowを実行して良いのか？
- 実行する場合、先に起動していたworkflowはどのように取り扱うのか？を設定します。

設定できるオプションは下記の通りです。

- Allow: 全てのタスクを許可。つまり古いjobと新しいjobが並列して実行される
- Replace: 新しいスケジュールを設定する前に古いものをすべて削除。古いjobが残っていた場合はterminateされる
- Forbid: 古いjobが残っているうちは新しいjobは動かさない

### startingDeadlineSeconds
これもちょっとわかりづらいオプションですね。
例えばconcurrencyPolicyをForbidにしてworkflowが多重起動しない設定になっていた場合に、本来起動すべき時刻に実行できなかったworkflowをどのように扱うのか？を設定するためのオプションです。
デフォルトでは0となっており、本来実行する予定だった時刻に実行できなかったworkflowは実行されない設定になっています。ここの数値を６０などにした場合、本来起動する予定だった時刻から60秒以内に実行可能な状態になると、後続のworkflowが直ちに実行されます。


### successfulJobsHistoryLimit
成功したJobの履歴を何回分保存しておくかの設定です。
例えば３と設定しておくと、成功したJobの実行結果が直近3回分だけ保存されて、古いものは適宜削除されるようになります。


### failedJobsHistoryLimit
失敗したJobの履歴を何回分保存しておくかの設定です。
例えば３と設定しておくと、失敗したJobの実行結果が直近3回分だけ保存されて、古いものは適宜削除されるようになります。


## CronWorkflowの登録/更新/削除方法
`argo cron` コマンドと `kubectl` コマンドを使う方法の両方があります。
`argo cron` コマンドはCronWorkflowを削除・更新できないので `kubectl` コマンドを使っておくほうが無難だと思います（誰かargo cronコマンドを使うメリットを知っていたら教えてください）。

また、細かい話ですがCronWorkflowによって実行されるJob用のPodはCronWorkflow CRDを作成したnamespaceで起動します。デフォルトで登録するとCronWorkflowはdefaultネームスペースに登録され、Cronで実行されるWorkflowもdefaultネームスペースで実行されるようになるため、適宜作成するネームスペースは変更するようにしましょう。

### 登録
`argo cron` コマンドと `kubectl apply` コマンドを使う方法の両方があります。

```bash
$ argo cron create `マニフェストファイル` -n `ネームスペース`
$ kubectl apply -f `マニフェストファイル` -n `ネームスペース`
```

### 更新
`kubectl apply` コマンドを使います。

```bash
$ kubectl apply -f `マニフェストファイル` -n `ネームスペース`
```

### 削除
`kubectl delete` コマンドを使います。

```bash
$ kubectl delete -f `マニフェストファイル` -n `ネームスペース`
```


## CronWorkflowを手動実行する
開発・デバッグ時に地味に必須と言えるコマンドです。
基本的には `argo submit` コマンドなんですが、実行するjobの指定方法が普通のWorkflowとちょっと違います。
手動で実行したいCronWorkflow CRDがapplyされている状態で --fromオプションを使って起動します。

```bash
$ argo submit --from cronwf/`CronWorkflowの名前`
```

以上です。それではみなさん良いワークフロー構築ライフを！