新卒1年目がECSにCanary Releaseを導入し信頼性を高めた話〜PipeCD〜 

## はじめに

こんにちは、サイバーエージェントのAI事業本部でバックエンドエンジニアをしている23卒の高橋です。

CD環境をGitHubActionsからPipeCDに完全移行したので、その知見や感想について共有したいと思います。


## 背景

現在のデプロイフローはGitHubActionsを採用しており、以下のような非常にシンプルな手順になっております。

1.　workflow　dispatchで手動実行
2.　GitHubActionsがImageをビルドし、ECRにPushします

![work-shun (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/64bb3b12-0d2b-f23f-bf0b-dd6aff71d739.jpeg)

3. Imageタグを指定して、以下のworkflowを手動実行
4. SSMの値を書き換え,terrafrom apply

![work-shun (3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/8f641cca-debe-c466-009d-f850ad67d4e4.jpeg)


これらの手順を追うことでビルドからデプロイまでの作業が完了します。


## 課題点

このデプロイ方法には以下のような課題点がありました
- **ビックバンリリースのリスク**
- **ロールバック問題**
- **誤操作のリスク**
- **多様なデプロイ戦略が不可**

　デプロイを一度開始してしまうと100％環境に反映されてしまいます。
 そのため重要度の高いエラーや障害が起こってしまった際に全てのユーザーに影響が出てしまい、切り戻すにも上記で定義したデプロイフローを行わないといけないため、かなりの時間と工数がかかります。

また人間が手動でデプロイを開始したり、デプロイ対象や環境を指定します。
そのためstgに出そうとしていたものがprdに出してしまったり、違うデプロイ対象を指定してしまうといったヒューマンエラーが起こるリスクもあります。

そのためビックバンリリースだけではなく、リスク低減かつ安全なデプロイ方法である、Blue-Green DeploymentやCanary Release、プログレッシブデリバリーを行いたいと考えました。

## CDツールの選定

KubernetesではArgo Rollouts, Spinnaker, FluxCDなどデプロイ戦略ツールが豊富かつ多くの企業やプロジェクトで実践されております。
![スクリーンショット 2023-12-15 午後3.29.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/71fa5ded-3231-2675-1301-ca8e8104342b.png)

ECSではデプロイツールの選択肢がかなり限定的になります。AWS CodeDeployやApp Meshなどでカナリアリリースを実現することはできるのですが、マルチクラウドに対応しておらず、デプロイ戦略全体として管理することはできません..

-> **GitOpsやCanary Releaseに対応しているPipeCDを採用することにしました**


## PipeCDとは

PipeCDとは一言で表すと　**「継続的デリバリーを実現するGitOpsツール」** です。

特徴としては以下があります。
- **マルチクラウド & マルチプラットフォーム対応**
- **GitOpsによる継続的デリバリー**
- **Canary, Blue-Greenなどの戦略をサポート**




[PipeCD Documentation](https://pipecd.dev/docs-v0.45.x/overview/)

## PipeCDの構成

PipeCDのコンポーネントには大きく二つあります。

**Control Plane:**
デプロイメントデータを管理し、PipeCDのWeb機能を提供する中央集権的なコンポーネントです。
これには認証、デプロイメントのリストや詳細の表示、アプリケーションのリストなどの機能が含まれます。
また、Pipedとの接続のためのgRPC APIも提供します。

**Piped:**　
デプロイメントタスクを処理するためにクラスターやローカルネットワークに配置するシングルバイナリコンポーネントです。
このコンポーネントはステートレスに設計されているため、シングルVMやローカルマシン上でも実行可能です。
![architecture-overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/dc14ce49-6236-67d0-502a-738ad25c7513.png)

https://pipecd.dev/docs-v0.45.x/concepts/

## Pipedの構築

私たちのプロダクトではPipedをECS環境に構築して、運用しております。
具体的には以下のような構成になっております。

![Piped改善案2.drawio (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/77f1bce3-0b6f-b663-ccd5-54637a3cb3cc.png)

AWS環境でPipeCDを最適に運用するために、シンプルかつセキュアなリソース構成を採用しました。ここでは、その構成要素とその理由を紹介します。

**VPC & Subnet:**
パブリックサブネットを用いたシンプルな構成を採用し、管理を容易にしています。

**SSMパラメータストア:**
`piped.config.yaml`の安全な管理を実現するため、AWSのSSMパラメータストアにBase64でエンコードされた設定ファイルを格納しています。

**セキュリティグループ:**
アウトバウンド通信は全て許可されており、必要な通信のみを簡潔に制御しています。

**シングルAZ構成:**
Pipedの競合を防ぐため、シングルアベイラビリティゾーン(AZ)を採用。

**Pipedインスタンスの集約:**
ECS、Terraform、Lambdaなど、異なるプラットフォーム向けのPipedインスタンスを一箇所に集約することで、運用の複雑さを軽減しています。

**Control Plane通信:**
PipedはControl PlaneとgRPCプロトコルで通信を行い、ALB(Application Load Balancer)は使用せず、egress通信のみを許可しています。


## PipeCDを使ったCanary Release

Canary Releaseとは新しいバージョンを一部のユーザーだけに徐々にリリースして、問題がないかを確認しながら展開するデプロイ方法の一つです。

PipeCDではデプロイ手順の設定を`app.pipecd.yaml`のpipelineに記述します。
下記はCanary Releaseの一例になります。
```yaml
  pipeline:
    stages:
      # Rollout CANARY variant's workload.
      # scale represents the percentage of workload will be rolled out,
      # in this case 30% of the current PRIMARY variant's workload is set.
      # Note: Rolled out variant serves no traffic at this time.
      - name: ECS_CANARY_ROLLOUT
        with:
          scale: 30
      # Change the traffic routing state where
      # the CANARY workloads will receive the specified percentage of traffic
      # (20% in this case). This is known as multi-phase canary strategy.
      - name: ECS_TRAFFIC_ROUTING
        with:
          canary: 20
      # Hold the deployment process for 150 seconds.
      - name: WAIT
        with:
          duration: 150s
      # Update the workload of PRIMARY variant to the new version.
      - name: ECS_PRIMARY_ROLLOUT
      # Change the traffic routing state where
      # the PRIMARY workloads will receive 100% of the traffic.
      - name: ECS_TRAFFIC_ROUTING
        with:
          primary: 100
      # Destroy all workloads of CANARY variant.
      - name: ECS_CANARY_CLEAN
```


https://github.com/pipe-cd/examples/blob/master/ecs/canary/app.pipecd.yaml


## ECSのCanary Release or Blue-Green Deployment

PipeCDを使ったBlue-Green Deploymentの挙動について説明します。
(Canary Releaseもパラメーターが違うだけで同じ流れになります)

**ECS_CANARY_ROLLOUT:**
このステージでは、新しいバージョンのワークロードのカナリアバージョン（実験バージョン）を、現行のプライマリバージョンのワークロードの100%の規模で展開します。

![PipeCD pipeline.drawio (16).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/3fecb5f8-ea2f-6de2-e7e5-562b19e3c668.png)

**ECS_TRAFFIC_ROUTING (カナリア):**
トラフィックのルーティングを変更して、カナリアバージョンのワークロードがトラフィックの100%を受け取るようにします。

![PipeCD pipeline.drawio (17).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/d53c3b8a-9023-84f7-d1aa-8ff84ead58e5.png)

**ECS_PRIMARY_ROLLOUT:**
カナリアバージョンで問題がないと確認されたら、プライマリバージョン（現行の主バージョン）のワークロードを新しいバージョンに更新します。

![PipeCD pipeline.drawio (18).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/d5e47b40-b4ff-12d2-f153-01d3cad49408.png)

**ECS_TRAFFIC_ROUTING (プライマリ):**
トラフィックのルーティングを再度変更して、プライマリバージョンのワークロードがトラフィックの100%を受け取るようにします。
これで全てのトラフィックが新しいバージョンに向けられることになります。

![PipeCD pipeline.drawio (19).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2033092/bcacd53a-67b6-697e-e6f3-d14bb1221497.png)

**ECS_CANARY_CLEAN:**
最後に、カナリアバージョンのワークロードを破棄します。
これにより、デプロイメントプロセスが完了し、新しいバージョンが完全に展開されます。


## 最後に

PipeCDのカナリアリリースを導入し安全なデプロイを実現することができました。問題が生じた際には、自動的に前の安定バージョンにロールバックすることができます。

また、GitOpsを実践することで、インフラとアプリケーションの状態をコードで定義し、クリアなバージョンニングと追跡性が向上しました。

簡潔ながら、この紹介が何かの参考になれば幸いです。