Argo Rollouts と CircleCI を統合した、Amazon EKS への安全なプログレッシブデリバリー(カナリアリリース)の実現

## Argo Rollouts を使った Kubernetes へのプログレッシブデリバリー(カナリアリリース)

Kubernetes における CI（継続的インテグレーション）/ CD（継続的デリバリー）は一般的になりつつあり、1日に数回などより頻繁なリリースを実現することが可能になりました。一般的には、新たにアプリケーションをローリングアップデート方式でデプロイすることが多いですが、この方法では全てのユーザーに対して一斉に新バージョンが適用されるため、万が一問題が発生した場合の影響範囲が大きくなります。

プログレッシブデリバリーとは、新しい機能を段階的に公開していく手法です。これにより、影響範囲を細かく制御することができ、問題が発生した際に迅速に対応することが可能です。代表的な方法としてカナリアリリースがあります。カナリアリリースでは、新バージョンを一部のユーザーにだけ提供し、問題がなければ段階的に全ユーザーに展開します。これにより、ユーザーへの影響を最小限に抑えながら、確実なリリースが可能です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/39888dcf-36b6-2bc1-b33d-ffa464439f55.png" />
カナリアリリース(Argo Rollouts ドキュメントより)

Argo Rollouts は、Kubernetes でプログレッシブデリバリーを実現するためのオープンソースツールです。Argo Rollouts を使うと、カナリアリリースやブルーグリーンデプロイメントなど、さまざまなデプロイ方法を簡単に設定できます。また、問題が発生した際には自動でロールバックする機能もあります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/c954f6a4-2070-d436-d2f9-64ccf19bd54b.jpeg" />
Argo Rollouts のアーキテクチャ(Argo Rollouts ドキュメントより)

Argo Rollouts を活用することで、安全で効率的なリリースプロセスを構築し、Kubernetes 環境の信頼性を高めることができます。

## Argo Rollouts と CircleCI のリリース機能(CircleCI Releases)の統合

一般的に、Argo Rollouts を活用しながら CI/CD パイプラインを構築していく場合には以下のツールを組み合わせていく必要があります。

* CircleCI などの CI ツール(テスト、Dockerイメージのビルド、Amazon ECRなどのレジストリへのプッシュ)
* ArgoCD などの Kubernetes に特化したCDツール
* Argo Rollouts などの Kubernetes に特化したプログレッシブデリバリーツール

CI と CD ツールを明確に分けることによるメリットもありますが、同時にこれら複数のツールを使い分けることによって一貫性が失われてしまい、可視性・管理が複雑になってしまいがちです。

この課題を解決するために、CircleCI では独自のリリース機能 (CircleCI Releases) を提供し始めました。

Amazon EKSをはじめとしたKubernetesクラスターと CircleCI を接続し、CircleCI ダッシュボードからリリースを管理・操作することができます。

また、Argo Rollouts とネイティブで連携することができ、CircleCI ダッシュボードから Argo Rollouts によるカナリアリリースの状況の可視化・操作を行うことができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/fd240bd8-bdb1-c6c1-1a9e-d79ff2bb2182.png" />
CircleCI Releases のダッシュボード


CircleCI Releases の登場により、CI(ビルド・テスト)からCD(デプロイ・カナリアリリース)までを統合されたワークフローにすることが可能になり、可視性・一貫性・生産性を向上させることができます。

次の章では AWS が提供する Amazon EKS クラスターに対するプログレッシブデリバリーを Argo Rollouts と CircleCI Releases によってどう実現するかについて解説します。

## Amazon EKS クラスター に CircleCI Releases をセットアップする

CircleCI Releases は、Kubernetes クラスターに専用のエージェント(Release Agent)をインストールすることによって、リリースを管理・操作することができるアーキテクチャになっています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/67cf35d5-d225-2832-c363-383a1b466c0f.png" />
CircleCI Releases のアーキテクチャ

実際に Amazon EKS クラスターに CircleCI Releases を使ったリリース環境をセットアップします。

CircleCI Releases ページの「Environments」タブから「Create Environment Integration」を選択し進みます。そして、今回作成するリリース環境（Environment）の Name、 Description を記入し、Type を「Kubernetes Cluster」を選択した上で次に進みます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/c8145ab2-a74e-a653-5770-33b0c4947fe2.png" />
CircleCI Releases の リリース環境(Environment) セットアップ

次に Amazon EKS クラスターに Release Agent をインストールします。
インストールには以下が必要になります。
* Kubernetes クラスター(今回は Amazon EKSクラスター)
* Helm
* Argo Rollouts 

Argo Rollouts のインストール方法については[公式ドキュメント(英語)](https://argoproj.github.io/argo-rollouts/installation/)を参考にしてください。

次に、CircleCI Helm レポジトリを追加し、ローカル Helm レポジトリキャッシュを更新して、最新バージョンであることを確認します。

```
helm repo add release-agent 
https://circleci-public.github.io/cci-k8s-release-agent

helm repo update
```

以下の Helm コマンドで Release Agent をインストールします。

```
helm upgrade --install circleci-release-agent-system
release-agent/circleci-release-agent \ --set 
tokenSecret.token=[YOUR_CCI_INTEGRATION_TOKEN]
--create-namespace \ --namespace
circleci-release-agent-system \ --set 
managedNamespaces="{namespace1,namespace2}"
```

チュートリアルの中でこのコマンド内にある `YOUR_CCI_INTEGRATION_TOKEN`
は自動生成されますが、手動で生成する際には、各 Environments のページから「Create Integration Token」を選択して作成します。

また、default 以外で CircleCI Releases で監視したい namespace があれば、`managedNamespaces`　に追加します。

インストールが成功すると、Release Agent のステータスが「ONLINE」になります

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/1cd05075-3625-59e6-050c-dc27d62939ac.png" />
Release Agent のステータス

最新の情報は以下のドキュメントを参考にしてください。
[Set up a release environment - CircleCI](https://circleci.com/docs/release/set-up-a-release-environment/)
[CircleCI Kubernetes Release Agent Helm Chart | cci-k8s-release-agent](https://circleci-public.github.io/cci-k8s-release-agent/)

## Amazon EKS にデプロイする CircleCI パイプラインを作成する

Amazon EKS クラスター に CircleCI Releases を使ったリリース環境がセットアップできたので、次にAmazon EKS にデプロイする CircleCI パイプラインを作成していきます。

パイプラインのアーキテクチャとしては以下のようになります。

① CircleCI が VCS(ソースコード管理)の変更を検知し、Docker イメージをビルド・Amazon ECR にプッシュ
② CircleCI から Amazon EKS クラスターの Rollout を更新

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/41fafffa-af2d-be08-7065-1eed17fcfc7f.png" />
Amazon EKS にデプロイする CircleCI パイプラインのアーキテクチャ

①と②のデプロイのステップが成功すると、③で実際に CircleCI のリリース画面からリリースを管理・操作することが可能になります。

### Docker イメージをビルド・Amazon ECR にプッシュ

はじめに、CircleCI で対象のアプリケーションのDockerイメージをビルドし、Amazon ECR にプッシュするジョブ `build_and_push_ecr` を作成します。

CircleCI が提供する AWS インテグレーション(CircleCI Orb)を使うと、以下の設定ファイルのようにシンプルにすることが可能です。

[CircleCI Developer Hub - circleci/aws-ecr](https://circleci.com/developer/ja/orbs/orb/circleci/aws-ecr)
[CircleCI Developer Hub - circleci/aws-cli](https://circleci.com/developer/ja/orbs/orb/circleci/aws-cli)

```yaml
build_and_push_ecr:
  machine:
    docker_layer_caching: true
  steps:
    - checkout
    - aws-ecr/build_and_push_image:
        auth:
          - aws-cli/setup:
              role_arn: ${AWS_ROLE_ARN}
        repo: tadashi-demo-release-eks-app
        tag: '${CIRCLE_SHA1}'
```
AWS への認証にはOpenID Connect を利用しており、CircleCI にAWSの永続的なキーを保持する必要がなく、よりセキュアな認証を実現することができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/fefe3a01-40be-bafd-0dbd-c6639bd80f6c.jpeg" />
OpenID Connect を使った AWS への認証アーキテクチャ

設定方法については下記のドキュメントを参考にしてください。
[ジョブでの OpenID Connect トークンの使用 - CircleCI](https://circleci.com/docs/ja/openid-connect-tokens/#aws)

CircleCI の設定ファイル (`.circleci/config.yml`)においては、`aws-cli/setup` パラメーターにある `role_arn` を対象の IAM Role に指定することによって、自動的に OpenID Connect を使った認証に切り替わります。

### CircleCI から Amazon EKS クラスターの Rollout を更新

次に、 CircleCI から Amazon EKS クラスターの Rollout を更新(Amazon ECR の最新の Docker イメージタグに変更)します 

今回は以下の Argo Rollouts のKubernetes マニフェスト(Rollout) を使用していきます。

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  annotations:
    circleci.com/job-number: "${CIRCLE_BUILD_NUM}"
    circleci.com/pipeline-id: "${CIRCLE_PIPELINE_ID}"
    circleci.com/project-id: "${CIRCLE_PROJECT_ID}"
    circleci.com/workflow-id: "${CIRCLE_WORKFLOW_ID}"
  labels:
    app: demo-app
    circleci.com/component-name: demo-eks
    circleci.com/version: "${CIRCLE_SHA1_SHORT}"
  name: demo-eks
spec:
  replicas: 4
  strategy:
    canary:
      steps:
      - setWeight: 50
      - pause: {}
  selector:
    matchLabels:
      app: demo-eks
  template:
    metadata:
      labels:
        app: demo-eks
        circleci.com/component-name: demo-eks
        circleci.com/version: "${CIRCLE_SHA1_SHORT}"
    spec:
      containers:
        - image: 660990364978.dkr.ecr.ap-northeast-1.amazonaws.com/tadashi-demo-release-eks-app:$CIRCLE_SHA1
          name: demo-eks
          ports:
            - containerPort: 3000
```
この Rollouts では、以下のカナリアリリース戦略をとっています。
* 50%までリリースする
* 一時停止(pause)する

この場合、100%までリリースを進行したい場合には手動コマンド、あるいはこの後紹介する CircleCI Releases ダッシュボードを使った操作が必要になります。

この他に、Datadog などのオブザーバビリティツールと連携することによって、それらのデータを元にリリースを自動判断することができます。

[https://docs.datadoghq.com/ja/integrations/argo_rollouts/](https://docs.datadoghq.com/ja/integrations/argo_rollouts/)

先ほどの Rollout ファイルですが、CircleCI 独自の annotation や label を追記しています。

これらは、どの CircleCI の Job からトリガーされたものか(Release Trigger) CircleCI Release ダッシュボードで確認できるのに役立ちます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/0128e2b8-d336-85b3-4878-86af0d184bb0.png" />
CircleCI Releases で確認できる Release Trigge

annotation や label の値を環境変数にしていますが、この後 CircleCI ジョブ内でこの Rollouts の変更を実行するため、その際に CircleCI ジョブ内にある環境変数から参照・置換します。

Amazon EKS クラスターに対してRollouts の更新を行う CircleCI ジョブ(deploy_eks)の設定ファイルは以下です。

```yaml
deploy_eks:
  docker:
    - image: cimg/aws:2024.03.1
  steps:
    - checkout
    - aws-cli/setup:
        role_arn: ${AWS_ROLE_ARN}
    - aws-eks/update-kubeconfig-with-authenticator:
        install-aws-cli: false
        aws-region: ap-northeast-1
        cluster-name: cci-demo-release
    - run:
        name: Apply Kubernetes Manifest to EKS
        command: |
          export CIRCLE_SHA1_SHORT=${CIRCLE_SHA1:0:8}
          envsubst < manifest/rollout.yaml | kubectl apply -f -
```
deploy_eks ジョブでは以下のステップを実行しています。
* aws-cli Orb を使って、OpenID Connect 認証を行う
* aws-eks Orb を使って、対象の Amazon EKS クラスターの kubeconfig の認証の更新を行う
* kubectl コマンドを使い、Kubernetes マニフェスト(Rollout)にCircleCIの環境変数を渡しつつ、新しい Dokcer イメージタグに変更する

## CircleCI Releases ダッシュボード からリリースを管理・操作する

実際に CircleCI Releases ダッシュボードにおいてリリースを管理・操作する方法を紹介します。

### リリースを進行する(Promote)

現在進行しているカナリアリリースを進行したい場合には、対象のリリースページにある「Promote」を選択します。
全て進行させたい場合には「Promote All」を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/15f0a9ea-25f4-2949-8ccf-079dd44ec5fc.png" />
リリースを進行する(Promote)

以下の Argo Rollouts コマンドと同等の操作をしています。

```
kubectl argo rollouts promote <rollout-name>
```

### リリースをキャンセルする(Cancel)

現在進行しているカナリアリリースをキャンセルする際には、対象のリリースページにある「Cancel Release」を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/a2b94a90-771e-1e97-5054-3a7ad490dfc2.png" />
リリースをキャンセルする(Cancel)

以下の Argo Rollouts コマンドと同等の操作をしています。

```
kubectl argo rollouts abort <rollout-name>
```

### リリースバージョンをロールバックする(Restore)

現在のリリースバージョンから以前のリリースバージョンにロールバックしたい場合には、対象のリリースバージョンの「RESTORE」を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/8758f4c8-18ee-6b61-2e3d-969598911e91.png" />
リリースバージョンをロールバックする(Restore)

以下の Argo Rollouts コマンドと同等の操作をしています。

```
kubectl argo rollouts undo <rollout-name> 
--to-revision=<revision_number>
```

その他の操作については下記のドキュメント(英語)を参照してください。
[Manage releases - CircleCI](https://circleci.com/docs/release/manage-releases/)

## まとめ

この記事では、Argo Rollouts と CircleCI のリリース機能(CircleCI Releases)を統合することによって、Amazon EKS への安全なプログレッシブデリバリー(カナリアリリース)を実現する方法について紹介しました。

Argo Rollouts が提供しているプログレッシブデリバリー(カナリアリリース)のメリットを活用しながら、CircleCI Releases を使うことによって可視性・一貫性・生産性を向上させることができます。

CircleCI Releases は Free プランからご利用いただけます、是非お試しいただきそのメリットを体験していただければと思います。

[料金プラン情報 - CircleCI](https://circleci.com/ja/pricing/)