🍦

cloudfront continuous deploymentでSPAのデプロイパイプラインを構築する

に公開

こんにちは、TOKIUMのembedded SREの對馬です。

現在構築中のサービスで、はじめてcloudfront continuous deploymentを使いました。
構築してみた結果、便利である反面、IaCとの兼ね合いが難しいなどの考慮すべき点もあり、一長一短、備忘として記事にします。

continuous deploymentの概要

なぜcontinuous deploymentを選んだか

現在構築中のサービスは、以下の図に近い構成をとっています。

ECS アーキテクチャデザインパターン

APIはECS上で動作し、frontendはS3バケットに配置する構成です。

この構成でfrontendに対してカナリアリリースなどを目指す場合、ユーザーからみてS3バケットより手前にあるリソースで、トラフィックを制御する必要があります。

そうなると、AWS WAFか、(図中にないですが)Route 53か、CloudFrontあたりから選ぶことになります。
まずもって、AWS WAFにはリクエスト振り分け機能が存在しないため、候補から外れます。

Route 53も、CloudFrontとの兼ね合いがよろしくないため候補から外れます。
https://zenn.dev/hsaki/articles/aws-canary-like-function-list#ルーティング先がcloudfront-distributionのときの制約

加重ルーティング・IPベース問わず、Route 53のルーティングポリシーを使って複数個のCloudFront Distributionにリクエスト分散させることができません。

そうなると、CloudFront一択となります。

CloudFrontを利用したデプロイ方法にもいくつか種類はあるようですが、今回はcontinuous deploymentを使うことにしました。
(本当は他のデプロイ方法とも比較検討したかったんですが、時間が足りませんでした。)

概要

continuous deploymentは、本番ディストリビューションとは別にステージングディストリビューションを設けることで、本番適用前にテスト・検証ができる機能です。


amazon web serviceブログ

stagingディストリビューションで事前にテストをして、OKだったらステージングの内容を本番に反映する、というフローを作れます。
本番とステージングのルーティング方法としては、以下2つが存在します。

  • ヘッダーベース:特定のヘッダーが付与されているリクエストのみ、ステージングにルーティングする
  • ウェイトベース:すべてのリクエストのうち一定割合はステージングにルーティングする。(0〜15%で指定可能)

仕組みがわかりやすくていいですね。

構築した内容

最終的に構築したインフラは、下記になります。

カナリアリリースを実現したかったため、ルーティングはウェイトベースを選ぶことにしました。
また、デプロイ中の異変に気づけるよう、CloudWatchアラームで、stagingの5XXエラーを監視するようにしています。

デプロイは以下の流れで行われます。

  1. S3に新バージョンのfrontend資材をアップロード
  2. stagingのオリジンパスを、新バージョン向けに更新
  3. stagingの更新が完了したら、deployment policyを有効化し、10%のトラフィックが流れるようにする。
  4. 一定時間この状態で監視を続ける。
    4.a. ステージングで5XXエラーが頻発したら、CloudWatchアラームが発火しデプロイを中止し、deployment policyも無効化する。
  5. 特に問題がなければ、stagingのバージョンをそのまま本番に反映。continuous deploymentを無効化し、デプロイ完了!

continuous deploymentの注意点

terraform applyが一回じゃすまなくなる

わりかしいい感じのcontinuous deploymentですが、CloudFrontのリソース作成とcontinuous deploymentのポリシー紐付けが同時にできない点は注意が必要です。

https://dev.classmethod.jp/articles/how-to-build-cloudfront-cd-with-terraform/

どうやらAWS側の仕様でディストリビューションの作成とデプロイメントポリシーの紐づけを同時にできない様で、このため

  1. 各種リソースの作成
  2. プライマリディストリビューションとデプロイメントポリシーの紐づけ
    を分けて行う必要があります。

この仕様により、一発でインフラを構築できないのがちょっと面倒。
弊社では、クラスメソッドさんの記事と同様に、紐付けを変数化して紐付けなしでapply -> 紐付けしてapplyという形にしています。
構築時の一回だけではあるものの、面倒だなーと思ってしまいます。

結構シェルを書かなきゃいけない

直感的でわかりやすいcontinuous deploymentですが、デプロイを自動化しようとすると、結構な量のシェルを書かないといけなくなります。

弊社のパイプラインでは、以下5つのシェルが必要になりました。

  • ステージング更新シェル
  • 本番反映シェル
  • deployment policy有効化/無効化シェル
  • deployment policy id取得シェル
  • deployment policy 設定更新シェル

deployment policyの制御が結構煩雑で、こういうふうになってしまいました。

まとめ

こんな感じでよさげなcontinuous deploymentですが、本番リリースがまだなので評価しがたい部分もあります。
本番運用で使ってみた感想は、気が向いたら別途記事にしようかと思います。

TOKIUMプロダクトチーム テックブログ

Discussion