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

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

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

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


![Canary Release.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/e99e0f66-5a21-9bff-67eb-bb94cd46485f.png)
カナリアリリース(Argo Rollouts ドキュメントより)

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

![argo-rollout-architecture.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/5962cc82-90a3-dac0-19c7-1457150d3f50.jpeg)
Argo Rollouts のアーキテクチャ(Argo Rollouts ドキュメントより)

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

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

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

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

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

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

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

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

![dashboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/07a253fc-9cc5-fc2d-b6e6-b3dcabb96863.png)
CircleCI Releases のダッシュボード

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

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

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

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

![releases-architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/4be6228b-ed2b-daf8-ee60-696b100bba21.png)
CircleCI Releases のアーキテクチャ

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

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

![setup-release-environment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/a85c8b0e-6613-2557-bf49-e74fe1f6c499.png)
CircleCI Releases の リリース環境(Environment) セットアップ

次に GKE クラスターに Release Agent をインストールします。
インストールには以下が必要になります。

* Kubernetes クラスター(今回は GKEクラスター)
* 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」になります。

![release-agent-status.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/52809c38-6657-a1ab-79c4-fb389f094924.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/)

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

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

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

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

![gke-architecture (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/7df26d47-1859-dfa2-78f6-6b53e0de8b70.jpeg)
GKE にデプロイする CircleCI パイプラインのアーキテクチャ

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

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

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

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

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

```yaml
build_and_push_artifact_registry:
  machine:
    docker_layer_caching: true
  environment:
    GCLOUD_REGISTRY: asia-northeast-docker.pkg.dev
    IMAGE_NAME: circleci-tadashi/circleci-demo-release-gke/app
  steps:
    - checkout
    - gcp-cli/setup
        use_oidc: true
    - run: gcloud auth configure-docker $GCLOUD_REGISTRY
    - docker/build:
        registry: $GCLOUD_REGISTRY
        image: $IMAGE_NAME
        use-buildkit: true
    - docker/push:
        registry: $GCLOUD_REGISTRY
        image: $IMAGE_NAME
```

Google Cloud への認証にはOpenID Connect を利用しており、CircleCI に Google Cloud の永続的なキーを保持する必要がなく、よりセキュアな認証を実現することができます。

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

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

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

次に、 CircleCI から GKE クラスターの Rollout を更新(Artifact Registry の最新の 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-gke
    circleci.com/component-name: demo-gke
    circleci.com/version: "${CIRCLE_SHA1_SHORT}"
  name: demo-gke
spec:
  replicas: 4
  strategy:
    canary:
      steps:
      - setWeight: 50
      - pause: {}
  selector:
    matchLabels:
      app: demo-gke
  template:
    metadata:
      labels:
        app: demo-gke
        circleci.com/component-name: demo-gke
        circleci.com/version: "${CIRCLE_SHA1_SHORT}"
    spec:
      containers:
        - image: asia-northeast1-docker.pkg.dev/circleci-tadashi/circleci-demo-release-gke/app:$CIRCLE_SHA1
          name: demo-gke
          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 ダッシュボードで確認できるのに役立ちます。

![release-trigger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/366a2026-c7d9-99a0-3ba7-58929ac5a672.png)
CircleCI Releases で確認できる Release Trigger

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

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

```yaml
deploy_gke:
  docker:
    - image: cimg/gcp:2024.03.1
  steps:
    - checkout
    - gcp-cli/setup:
        components: gke-gcloud-auth-plugin kubectl
        use_oidc: true
    - gcp-gke/update-kubeconfig-with-credentials:
        cluster: circleci-demo-release-cluster
    - run:
        name: Apply Kubernetes Manifest to GKE
        command: |
          export CIRCLE_SHA1_SHORT=${CIRCLE_SHA1:0:8}
          envsubst < manifest/rollout.yaml | kubectl apply -f -
```
deploy_gke ジョブでは以下のステップを実行しています。
* gcp-cli Orb を使って、GCloud CLI 追加コンポーネントのインストール、OpenID Connect 認証を行う
* gcp-gke Orb を使って、対象の GKE クラスターの kubeconfig の認証の更新を行う
* kubectl コマンドを使い、Kubernetes マニフェスト(Rollout)にCircleCIの環境変数を渡しつつ、新しい Dokcer イメージタグに変更する

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

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

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

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

![promote-options.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/512e9f03-fd03-d924-5eb8-6043a87549eb.png)
リリースを進行する(Promote)

以下の Argo Rollouts コマンドと同等の操作をしています。
```
kubectl argo rollouts promote <rollout-name>
```
### リリースをキャンセルする(Cancel)
現在進行しているカナリアリリースをキャンセルする際には、対象のリリースページにある「Cancel Release」を選択します。

![cancel-release.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/3f72e399-b2c5-0503-3c16-f389f0e944b0.png)
リリースをキャンセルする(Cancel)

以下の Argo Rollouts コマンドと同等の操作をしています。
```
kubectl argo rollouts abort <rollout-name>
```

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

![restore-version.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819936/4ffef8fe-e375-95fb-2d6b-0dbab3616335.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)を統合することによって、Google Kubernetes Engine(GKE) への安全なプログレッシブデリバリー(カナリアリリース)を実現する方法について紹介しました。

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

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

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