argo-workflowを半年運用してみた

## **はじめに**

こんにちは、サイバーエージェントのAI事業本部SREチームの田口です。 今回は、argo-workflowsについて、半年間運用してみたのでその感想など話していきます。

<!-- truncate -->

## **argo-workflowとは**

argo-workflowは、kubernetes上で並列ジョブを実行するためのオープンソースのコンテナネイティブエンジンです。Kubernetes CRD (カスタム リソース定義) として実装されています。 詳しくは、公式のページに詳しく情報が載っているのでこちらをご覧になってください。

**[argo 公式サイト](https://argoproj.github.io/argo-workflows/)**

## **構成はどのようになっているか**

社内のkubernetes基盤であるAKE上に2つのクラスタを作成しています。 1つは、CI/CD ならびワークフロー処理をするクラスタ、もう1つはアプリケーションクラスターになります。 開発者はgitの状態と同期を行い、OPSクラスターから、自動もしくは、コマンド、GUI上で、デプロイや定期実行のワークフローを動かしています。


![argo-workflow1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87607/9ebe150e-5a17-c898-9184-a1a1ea5e0205.png)

## **どのようなことに利用しているのか**

担当プロダクトでは、現状以下のような機能を動かしています。

- logの収集や転送のワークフロー
- dbのtableの変更や作成のワークフロー
- mlの特徴量作成やmodelのデプロイのワークフロー

これらは、argo-workflowsの機能の1つである「Cron Workflows」を使うことによって定期実行しています。

以下の例では、実際に並列で動かしているworkflowsのUIです。ワークフローの実行結果を表示しています。 UIは変更できますが、この場合上から下にワークフローがステップ実行されている様子を表しています。 横に並んでいる箇所は1つのステップ内で、並列処理をしている状態を表してます。 「...」で省略されている箇所はありますが、こちらも開くと10個ほどの並列ステップが実行されていることがわかります。※1参照


![argo-workflow2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87607/3fbf2ddc-e722-6ea3-b7fe-afcfedd647e0.png)

※1 一部展開した例)


![argo-workflow3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87607/9650f635-4ae6-3dfb-799f-4707eb79e1ca.png)


## **何が便利か**

実際に使ってみて便利だった点を数点ご紹介します。 まずはこちらのワークフローをご確認ください。こちら公式に載っているものを少し加工したものになります。

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: exit-handlers-
spec:
  entrypoint: intentional-fail
  onExit: exit-handler                  # invoke exit-handler template at end of the workflow
  templates:
  # primary workflow template
  - name: intentional-fail
    container:
      image: alpine:latest
      command: [sh, -c]
      args: ["echo intentional failure; exit 1"]

  # Exit handler templates
  # After the completion of the entrypoint template, the status of the
  # workflow is made available in the global variable {{workflow.status}}.
  # {{workflow.status}} will be one of: Succeeded, Failed, Error
  - name: exit-handler
    steps:
    - - name: notify
        template: send-email
      - name: celebrate
        template: celebrate
        when: "{{workflow.status}} == Succeeded"
      - name: cry
        template: cry
        when: "{{workflow.status}} != Succeeded"
  - name: send-email
    container:
      image: alpine:latest
      command: [sh, -c]
      args: ["echo send e-mail: {{workflow.name}} {{workflow.status}} {{workflow.duration}}"]
  - name: celebrate
    container:
      image: alpine:latest
      command: [sh, -c]
      args: ["echo hooray!"]
  - name: cry
    container:
      image: alpine:latest
      command: [sh, -c]
      args: ["echo boohoo!"]

```

### **エラーハンドリングが容易にできる**

「spec.onExit」を定義することで（この場合、exit-handler)ワークフローの最後で必ず呼び出すことができます。上記の例ではワークフローのステータスを確認することにより、エラーハンドリングできます。この機能はkubernetes標準のjobやCronJobではやりにくい点だと思うので、この辺りはかなり便利かなと思います。

### **shellやdockerとの相性が良い**

基本dockerのimageベースで各ステップを記載します。 こちらpythonの例ですが、pythonのプレーンなdocker imageを指定し、処理自体は、workflow上に簡単に書くことによって、簡単な処理などはわざわざ、dockerをビルドして、作る必要もなく非常に簡単に実装でき、開発の効率をあげることができます

```yaml
  - name: gen-random-int-python
    script:
      image: python:alpine3.6
      command: [python]
      source: |
        import random
        i = random.randint(1, 100)
        print(i)

```

### **外部からの呼び出しが簡単**

workflowを外部から実行したい場合はよくあるケースだと思います。 そういった場合でも以下のように、argo-workflowのクライアントのインストールなどをしなくても呼び出し方ができ、簡単に外から呼び出すことができます。

```sh
curl $ARGO_SERVER/api/v1/events/argo/my-discriminator \\
    -H "Authorization: $ARGO_TOKEN" \\
    -H "X-Argo-E2E: true" \\
    -d '{"message": "hello events"}'

```

## **最後に**

使い始めて半年ぐらいですが、簡単に並列処理やジョブが作成でき便利に感じています。 まだまだ便利な使い方や、機能がたくさんので、今後とも最新情報を追っていく予定です。
また、私たちのチームブログも別途公開していますので、よかったらこちらもご覧ください

https://sre.cyberagent.ai/