GitHub ActionsからEKS上で動作するArgo Workflowsを実行する

# Argo Workflowsについて

Argo Workflowsは、Kubernetes上で動作するオープンソースのワークフロー管理ツールです。
https://argoproj.github.io/workflows/

複数のタスクを定義して実行するワークフローを管理・自動化可能であり、複雑なCI/CDパイプラインを簡単に構築することができます。

[REST API](https://argo-workflows.readthedocs.io/en/latest/rest-api/)の機能も持っており、ワークフローの実行や管理を外部からHTTP経由で実行することも可能です。

ただし、そのためには[サーバーの認証方法](https://argo-workflows.readthedocs.io/en/latest/argo-server-auth-mode/)でTokenによる認証を有効化し、専用のTokenを生成して管理するなどの対応が必要となります。

既存のCI/CDなどでGitHub ActionsからAWS環境へのアクセスが既に確立されている場合は、awscliやkubectlなどのコマンドを使用した方が新しい侵入経路を作らないため安全です。

この記事では、GitHub Actionsからコマンド経由で、EKS上で動作するArgo Workflowを実行する方法について説明します。

# 前提条件

以下は事前に用意してあるものとします。
- Argo Workflowsが動作するEKS Cluster
- GitHub ActionsからEKS Clusterにアクセスするための認証設定
  - GitHub Actions と AWS環境間のアクセスには [GitHub ActionsとAWSの連携におけるOIDC認証の活用](https://qiita.com/satooshi/items/0c2f5a0e2b64a1d9a4b3) などを参考
  - aws-authや access entryによるIAMロールとKubernetesの権限周りのマッピングも必要

また、実行した環境は以下のとおりです。
- EKS Cluster: v1.29.10-eks-7f9249a
- Argo Workflows: v3.5.1

# 単純にGitHub ActionsからArgo Workflowsのワークフローを実行するケース

以下のようなGitHub Actionsのワークフローを定義することで、argocliをインストールでき、 [argo submit](https://argo-workflows.readthedocs.io/en/latest/cli/argo_submit/) コマンドを実行できるようになります。

```yaml: GitHub Actionsのワークフロー
name: Sample Workflow
on:
  workflow_dispatch:

# OIDC認証を利用するためid-token: writeを設定する
permissions:
  actions: write
  contents: read
  id-token: write
  pull-requests: write

env:
  ROLE_ARN: arn:aws:iam::123456789012:role/role-name
  CLUSTER_NAME: cluster-name
  REGION: ap-northeast-1
  KUBERNETES_VERSION: v1.29.0
  ARGOCLI_VERSION: v3.5.1

jobs:
  sample-workflow:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ env.ROLE_ARN }}
          aws-region: ${{ env.REGION }}
      - name: Install kubectl command
        uses: azure/setup-kubectl@v4
        with:
          version: ${{ env.KUBERNETES_VERSION }}

      - name: Install Argo CLI
        run: |
          curl -sLO https://github.com/argoproj/argo-workflows/releases/download/${{ env.ARGOCLI_VERSION }}/argo-linux-amd64.gz
          gunzip argo-linux-amd64.gz
          chmod +x argo-linux-amd64
          sudo mv argo-linux-amd64 /usr/local/bin/argo

      - name: Submit Argo Workflow
        id: submit-workflow
        run: |
          aws eks --region ${{ env.REGION }} update-kubeconfig --name ${{ env.CLUSTER_NAME }}
        # 同じリポジトリで管理しているargo_sample.yamlを渡して実行する
        # --wait オプションを渡すことで実行完了まで待機する
          argo submit argo_sample.yaml --wait -o json -n <NAMESPACE>
```
`argo submit` コマンドに、argo workflows上で動作させるワークフローの定義ファイルを渡すことで実行が行われます。

```yaml:argo submitの引数に渡す argo_sample.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: example-workflow
spec:
  entrypoint: whalesay
  serviceAccountName: executor
  templates:
  - name: whalesay
    container:
      image: docker/whalesay:latest
      command: [echo]
      args: ["hello world"]
```

# WorkflowTemplateを設定して呼び出すケース

上記の方法で、指定したWorkflowを実行できます。

ただし、GitHub Actionsと同じリポジトリでWorkflowのファイルを管理する必要があるため、ArgoWorkflowsのリソースを管理しているリポジトリと、GitHub Actionsを実行したいリポジトリが異なる場合などに、リソースの定義が散らばってしまいます。

ArgoWorkflowsのリソースをまとめておきたい場合には`argo subimit` コマンドの `--from` オプションが活用できます。
`--from` オプションを使用することでArgoWorkflowに登録済みのリソースを呼び出すことができます。
例えば次のようなWorkflowTemplateを登録しておいて、こちらを基にしてWorkflowを起動するなどが可能です。

```yaml:ArgoWorkflowsに登録しておくWorkflowTemplate
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: workflowtemplate-sample
spec:
  serviceAccountName: <SERVICE_ACCOUNT_NAME>
  entrypoint: whalesay
  ttlStrategy:
    secondsAfterCompletion: 3600 # 1 hour
  templates:
  - name: whalesay
    container:
      image: docker/whalesay:latest
      command:
      - sh
      - -c
      - |
        echo "hello world"
```
```yaml:GitHub Actionsでargo submitを実行するstep
      - name: Submit Argo Workflow
        id: submit-workflow
        run: |
          aws eks --region ${{ env.REGION }} update-kubeconfig --name ${{ env.CLUSTER_NAME }}
        # workflowtemplate を呼び出す
          argo submit --from workflowtemplate/workflowtemplate-sample --wait -o json -n <NAMESPACE>
```

# ArgoWorkflows側での実行結果を呼び出し側で取得するケース

上記のように `argo submit`の実行によってworkflowを起動することができますが、その結果をGitHub Actions側の後続処理に渡したい場合などがあります。そのようなケースではパラメータが活用できます。

以下はGitHub Actions側から入力用のパラメータを渡し、ArgoWorkflows側での実行結果を出力用のパラメータとして出力する場合の例となります。

```yaml: inputs/outputsのパラメータが設定されたWorkflowTemplate
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: workflowtemplate-sample
spec:
  serviceAccountName: <SERVICE_ACCOUNT_NAME>
  entrypoint: whalesay
  arguments:
    parameters:
    - name: message
      value: "" # set the value by argo submit --parameter
  ttlStrategy:
    secondsAfterCompletion: 3600 # 1 hour
  templates:
  - name: whalesay
    inputs:
      parameters:
        - name: message
    outputs:
      parameters:
        - name: output-message
          valueFrom:
            path: /tmp/hello_world.txt
    container:
      image: docker/whalesay:latest
      command:
      - sh
      - -c
      - |
        echo -n {{inputs.parameters.message}} > /tmp/hello_world.txt
```

GitHub Actions側では実行結果がそのまま返ってくるものではないので、起動されたワークフロー名を基にして結果を取得しにいく必要があります。

```bash:GitHub Actionsでargo submitを実行するstep
# --parameter でworkflowに入力値として渡すパラメータを設定し、実行時に出力される情報をworkflow.jsonに保存する
argo submit --from workflowtemplate/workflowtemplate-sample --wait -o json -n <Namespace> --parameter message="Hello, world!" > workflow.json

# workflow.jsonから実行されたworkflowの名前を取得
WORKFLOW_NAME=$(< workflow.json jq -r '.metadata.name')
echo "workflow name : $WORKFLOW_NAME"

# 実行完了後の情報をargo_get_result.jsonに保存
argo get -n <NAMESPACE> "$WORKFLOW_NAME" -o json > argo_get_result.json

# argo_get_result.json から実行後のステータスやoutputsパラメータに設定した情報を取得する
ARGO_WORKFLOW_RESULT=$(< argo_get_result.json  jq -r '.status.phase')
echo "workflow result : $ARGO_WORKFLOW_RESULT"
RESULT_MESSAGE=$(< argo_get_result.json jq -r '.status.nodes' |jq -r ".\"$WORKFLOW_NAME\"" | jq -r '.outputs.parameters[] | select(.name == "output-message").value')
echo "result : $RESULT_MESSAGE"
```

このような方法でArgo Workflows側での結果をGitHub Actions側に持ってくることができます。
- それぞれでの結果画面
  - Argo WorkflowsのINPUTS/OUTPUTS
    - <img width="400" alt="qiita-square" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299916/a2d03bc3-4c55-23e5-0c06-5764ea1e0b61.png">
  - GitHub Actionsの実行結果
    - ![Monosnap argo test · st-tech:zozo-DB-schema-history@79c520e 2024-12-14 01-49-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299916/71d67ec8-80c0-a8d3-7c5e-200dd91d15a7.png)


# おわりに

以上、GitHub ActionsからEKS上で動作するArgo Workflowsを実行する際の対応例を複数パターンで紹介しました。
同じような対応が必要になった際には、参考にしてみてください。