こんにちは。Akito Kogaです。
AWSにおけるECSとCodeDeployを使用してブルーグリーンデプロイの環境を整えていたのですが、ブルーグリーンデプロイ環境では通常、ステージング環境がデプロイ時に用意できます。 Cloudfrontを利用した環境において、本番環境とステージング環境で相互にルーティングするために、Cloudfront Continuous Distributionを利用すると便利でした。 今回はそちらを実装する機会があったので、その備忘録も兼ねて共有です。
Table of Contents
Open Table of Contents
ブルーグリーンデプロイとは
ブルーグリーンデプロイは、本番環境とステージング環境を用意して、デプロイ時にステージング環境に新しいソフトウェアを立ち上げて、本番環境とステージング環境の切り替えを行うことで安全にアプリケーションを展開するデプロイ方法です。
コンテナオーケストレーションツールであるECSやKubernetesなどを使用している場合に選択肢としてよく利用される方法で、私自身も仕事で開発しているアプリケーションをリリースする戦略として採用しました。
AllAtOnceでダウンタイムなしでデプロイできたり、カナリアリリースのように一部のユーザーに新機能を提供して、徐々に全ユーザーに提供することができるなど、ロードバランサーのターゲットをどのように切り替えるか柔軟に選択できることが利点です。
また、何か問題が発生した場合には、簡単にロールバックすることができることも利点の一つです。
実際にはブルーグリーンデプロイも銀の弾丸ではなく、デプロイの手間が増えることや、デプロイ時にステージング環境を用意するためのコストがかかることなど、デメリットもあります。
ですので、ローリングアップデートを筆頭に、デプロイ方法は様々な選択肢がありますので、アプリケーションの要件に合わせて選択することが重要です。
ブルーグリーンデプロイにおけるステージング環境
ブルーグリーンデプロイでは、デプロイ時に新しいステージング環境(グリーン環境)を立ち上げて、ロードバランサーのターゲットをブルー環境からグリーン環境に切り替えることによって、瞬時にソフトウェアを更新することができるデプロイ方法です。
通常、ブルー環境には80番ポート、グリーン環境には10080番ポートをそれぞれ割り当てて、開発者は指定するポートを切り替えることによって、ステージング環境にアクセスすることができます。
デプロイ前は80番も10080番もブルー環境をターゲットにしているのですが、デプロイ時に10080番をグリーン環境のターゲットとして切り替えます。 開発者は10080番にアクセスして、ステージング環境での新しいソフトウェアの動作確認を行うことができます。
一方で、80番ポートのターゲットはブルー環境の状態のままなので、デプロイの段階ではユーザーからのトラフィックは本番環境にしか向けられていません。 開発者だけが10080番にアクセスして動作確認を行うことができる状況です。 ステージング環境での動作確認が終了したら、グリーン環境にユーザーからのトラフィックを流していきます。
ユーザーのトラフィックを切り替える際は、ロードバランサーのターゲット切り替えをどのような割合で行うかを指定することができます。 例えば、100%のトラフィックをグリーン環境に切り替える場合は、AllAtOnceと呼ばれるデプロイ方法になります。 一方で、100%未満の任意の割合でトラフィックを切り替える場合は、カナリアリリースと呼ばれるデプロイ方法になります。
これが、ブルーグリーンデプロイでのステージング環境の一般的な利用の説明です。
Cloudfrontでのツラミ
しかし、ALBの前段にCDNとしてCloudfrontを立てた場合に、容易にステージング環境にアクセスできる方法がありませんでした。
Cloudfrontは複数のオリジンサーバーを登録することができます。ですので、80番ポートのリスナーと、10080番ポートのリスナーを別々のオリジンサーバーとして登録して、適切にルーティングさせることができれば良いと思うかもしれません。
しかし、Cloudfrontのルーティングはパスルーティングです。ポート番号を変えることでルーティング先を切り替えることができません。
無理やりパスを変更する手もなくはないのですが、本番環境とステージング環境でパスが違うというのは色々な意味で制約が発生しますし、ソフトウェアの動作を確認したいのに本番相当の動作ができなければ本末転倒です。
なので、今まではCloudfrontをALBの前段に用いてECSのブルーグリーンデプロイを利用する場合は、ステージング環境のホストをDNSレコードに新たに登録するといった、少し煩雑な実装が求められていました。
Cloudfront Continuous Distribution
上記のような理由で、Cloudfrontを通したECSのブルーグリーンデプロイは割とツラミが多く、私もどうやって実現させようかと考えていました。
そのような中で、Cloudfront Continuous DistributionはECSのブルーグリーンデプロイにおけるステージング環境と連携する手段としてとても最適でした。
Cloudfront Continuous Distributionでは、Cloudfrontのディストリビューションを本番環境とステージング環境で2つ用意します。ステージング環境のディストリビューションは本番環境のものと紐付けされています。
本番環境のディストリビューションには、80番ポートのALBのリスナーをオリジンとして登録します。 一方で、ステージング環境のディストリビューションには、10080番ポートのALBのリスナーをオリジンとして登録します。 この2つのディストリビューションを、Cloudfrontが指定する方法で切り替えることができます。
Cloudfrontが提供する切り替え方法は、Wait Base と Header Base の2つがあります。 Wait Baseはイメージとしてはカナリアリリースに近い方法で、ユーザーが指定した任意の割合でランダムにディストリビューションを切り替えます。 ただ、Wait Baseは今回の目的では使用しません。Header Baseによる切り替えを利用します。
Header Baseでの切り替えとして、aws-cf-cd-
から始まる追加のリクエストヘッダーを用意して、ヘッダーの有無でCloudfrontのディストリビューションを切り替えることができます。
実際にやってみて困ったこと
aws-cf-cd-
から始まる追加のリクエストヘッダーはChromeなどのブラウザの拡張機能を用いて付与するのが一番簡単です。しかし、Chromeの拡張機能を色々と調べてみたのですが、正直言ってセキュリティ的に怪しい拡張機能しかありませんでした。
これは困ったと色々と探していたのですが、Requestlyという拡張機能を発見しました。こちらは信頼性の高い拡張機能として使用することができそうです。
また、私が実装した環境ではフロントエンドにNext.js、バックエンドにWeb APIを使用するような構成でアプリケーションを構成していました。 バックエンドAPIにブルーグリーンデプロイを適用していたので、フロントエンドが追加のリクエストヘッダーを中継する必要がありました。 ブルーグリーンデプロイを適用するのがAPIで、フロントと完全に切り離して運用している場合、リクエストヘッダーを中継してあげる必要があるので注意が必要です。 特に、フロントがSSRを行っている場合は、サーバーサイドフェッチでリクエストヘッダーの中継処理を行う必要があります。
最後に、ALBのセキュリティグループとしてCloudfrontのマネージドプレフィックスリストを適用する必要があるのですが、80番と10080番で2つのSGのインバウンドルールを適用する必要があります。 しかし、AWSのSGのルールの上限数は60です。マネージドプレフィックスリストのエントリ数が55なので、80番に一つインバウンドルールを適用すると、残りの使えるルール数は5つしかありません。
ですので、10080番にもSGのルールを適用するためには、AWSにSGのルール数の上限を110以上に引き上げるように申請しなくてはなりません。MAXで200です。
特にTerraformなどのIaCで構成管理をしている場合に、SGのルール上限数でapplyできない場合はこちらに引っかかっている可能性が高いので、確認してみてください。
まとめ
Cloudfront Continuous Distributionを使用して、ECSのブルーグリーンデプロイにおけるステージング環境に追加ヘッダーを用いてルーティングを切り替える方法について説明しました。
私自身使用する際にうまくいくのか疑問だったのですが、驚くほどスムーズに動作確認することができて驚きました。以前は使用できなかった機能ですので、AWSが枝葉の細かいニーズに着々と対応しているのは感謝です。
ただし、Cloudfront Continuous Distributionを使うにあたり、構成が複雑になるので注意が必要です。実装する際はCloudfrontを利用するのが本当に適切なのかも踏まえて、実装するアプリケーションの要件に合わせて選択しましょう。