AWSでB/GデプロイやCanaryデプロイができそうな機能をまとめて比較してみた
この記事について
- 本番環境と同じ条件でステージング環境をデプロイし、開発者だけでそこにアクセスして挙動を確認してから本番昇格させたい!
- 一部の機能を一部のユーザーだけに開放して、A/Bテストのような機能検証がしたい!
といった場合には、全く同じ構成の環境を複製するのではなく、同じリソース配下に複数環境をホストしたいという要望が出てくるかと思います。
そしてそのような状況となったときに、実現する手法というのはAWSにおいて複数考えられます。
この記事では、AWSに存在する各種リソースの「Blue / Green」「Canaryデプロイ」「ステージング環境ホスト」に類比する機能をまとめて紹介し、それぞれの機能の特徴・良し悪し・向き不向きを考察していきます。
使用する環境・バージョン
- 2024/6/2時点で提供されている機能に基づき考察
読者に要求する前提知識
- AWS Certified Solutions Architect - Associate レベルの知識は説明なしに使います
AWSネットワークにおける主要経由ポイント
クライアントからAWS内にホストされたサーバー・サービスにアクセスするルートを考えてみると、概ね次の経由ポイントが洗い出せます。
- Route53での名前解決
- CloudFrontのCDNエッジサーバー
- API Gateway
- ALB
これらのサービスでは、ステージング環境や本番環境といった異なる環境を異なる条件で公開する手段や、それらをB/Gの形でデプロイする手法がそれぞれ用意されています。
ここからは各サービスの複数環境ホスト・切り替えデプロイ機能の比較をしていきたいと思います。
Route53
Route53はネームサーバーを提供するサービスで、とあるドメインにアクセスがあったときにトラフィックをどこに流すのかを設定することができます。
ただ単純の1:1対応ではなく、ルーティングポリシーというものを使うことで柔軟な割り振りを実現することができます。
Route53のルーティングポリシー
複数環境ホスト・切り替え機能という文脈で使えそうなルーティングポリシーは2つあります。
- IPベースのルーティングポリシー
- 加重ルーティングポリシー
IPベースのルーティングポリシーでは「アクセス元のIP CIDRによってルーティング先を変える」という挙動をさせられるため、例えば、同じmysite.example.com
というドメインにアクセスしたときに
- アクセス元IPが社内VPNのものならステージング環境に繋げる
- それ以外のIPからアクセスされているのであれば本番環境に繋げる
ということが理論上は可能です。(どのような場合に不可能なのかは後述)
加重ルーティングポリシーでは、「アクセスのうちn%はBlue環境へ、残りはGreen環境へ」という割合ベースでのルーティング分散をさせることができます。
Route53利用の際の制約事項
sticky sessionの機能はない
「とあるクライアントからとある条件でアクセスしてきた場合には、常に同じ環境にルーティングさせる」という機能全般のことをsticky sessionといいます。
Route53の場合、加重ルーティングポリシーを利用したときの割り振り先は一定の割合の元での完全ランダムで決定されてしまいます。
そのため、例えば「リクエストヘッダーを見て、〇〇の場合は絶対にBlue環境にルーティングしてほしい」ということはできません。
もちろんDNSにはキャッシュがありますから、その影響でとあるクライアントからのリクエストがB/Gを行ったり来たりということは起こりづらいです。ただ、Route53の機能としてルーティング先を固定する機能はありません。
即時のルーティング切り替えができない
Route53のレコードにはTTLを設定することができ、ここで設定した秒数分だけリゾルバーでDNSレコードの値をキャッシュされます。
そのため、例えRout53上でmysite.example.com
のルーティング先がGreen環境100%に設定されたとしても、リゾルバ側でBlue環境へのレコードキャッシュが残っていた場合Blue環境にリクエストが若干数飛んでくることになります。
また、IPベースルーティングの方でも同様の現象が考えられます。
社内VPN接続時のDNSキャッシュ設定がPCのなかに残っているのであれば、VPNを切っていたとしても本番環境ではなくステージング環境にリクエストが飛んでしまうということが理論上考えられます。
アクセス制限を行いたい場合
Route53はあくまで名前解決を行うサービスであり、ルーティング先へのアクセスを制限させるような機能は存在しません。
そのため、例えIPベースのルーティングを用いて「社内からのアクセスはサーバーAに、社外からのアクセスはサーバーBに」という設定を施していたとしても、サーバーAのIPアドレスが割れているのであれば社外からそのIPを直に叩くことでアクセスが可能であり、これを防ぐ機構はRoute53には存在しません。
アクセス制御を行うのはあくまで後段のルーティング先であるという考え方です。
ルーティング先がCloudFront Distributionのときの制約
加重ルーティング・IPベース問わず、Route53のルーティングポリシーを使って複数個のCloudFront Distributionにリクエスト分散させることができません。
具体的には、mysite.example.com
へアクセスしたときに
- 条件AのときはCloudFront Distribution Aに
- 条件Bのときは別のCloudFront Distribution Bに
という設定をさせるのは不可能です。
というのも、CloudFrontで独自ドメインmysite.example.com
を使うためには、「mysite.example.com
→ xxxx.cloudfront.net
(Distributionに割り当てられたドメイン)」というエイリアスレコードをRoute53で設定するだけではなく、CloudFront Distribution側でもAlternative Donamin Nameというものを設定する必要があります。
画像出典: Developer.IO - CloudFrontで独自ドメイン利用の際にディストリビューション側にもCNAME設定が必要な点をその動作とともに検証してみた
そして重要なのは、異なるDistributionで同じAlternative Domain Nameを設定することはできないということです。もしそのような設定を試みた場合はCNAMEAlreadyExists
というエラーが発生することになります。
つまり、Route53を利用して異なるCloudFront Distributionにルーティング分散させる・ルーティング先を切り替える[1]ということは現状難しいのです。
Route53 - まとめ
以上のことから、Route53でのルーティング分散・環境切り分けには以下のような向き不向きがあることがわかります。
- Route53が向いているケース
- とあるクライアントがBlue/Greenどちらに・どんなタイミングでアクセスしたとしてもシステム上問題にならない場合
- Route53が不向きなケース
- sticky session / アクセス制限を行いたい場合
- あるクライアントからアクセスする環境を状況によって頻繁に切り替えたい場合
- ルーティング先がCloudFrontである場合
開発者でコントロール可能なAWS環境外にもキャッシュの機能が存在するDNSの性質上、条件によってクライアントが向く環境を正確に制御・強制したいんだという要件にはRoute53は向きません。
CloudFront
CloudFrontはAWSにおけるCDNサービスです。
リクエストをユーザーから一番近いエッジサーバーに誘導することで、エッジでキャッシュされたコンテンツを返す・オリジンへのトラフィックをAWS内部ネットワークを通すようにさせるなどして低レイテンシでのコンテンツ提供を実現します。
CloudFrontでの複数環境ホスト・切り替え機能
CloudFrontには継続的デプロイという機能があり、これを用いることによってビューワーリクエストを変えることなく条件によってリクエストを2つのDistributionに振り分けることができるようになります。
プライマリDistribution / ステージングDistribution間でのリクエスト振り分けロジックは以下の2つが用意されています。
- ウェイトベース: 一定の割合でステージングDistributionに割り振る
- ヘッダーベース: リクエストに特定のヘッダー[2]がついている場合にはステージングDistributionに割り振る
また、継続的デプロイを用いてホストしているステージング側の環境の検証が済んだときにはB/Gデプロイに近い形での本番環境昇格を行うことができます。
このときはプライマリDistributionのエンドポイントは変わらず、ステージングDistributionの設定内容でプライマリの設定内容が上書きされるような挙動となります。
CloudFront継続的デプロイで実現可能な要件
サーバーサイド主体での(緩やかな)sticky session
ウェイトベースのリクエスト振り分けを行う場合でも、sticky session設定をオンにすることで同じセッションでのリクエストは同じDistributionに割り振ることができます。
そのためクライアントロジックに変更が加えられない場合でも、サーバーサイドの設定だけでアクセス先をプライマリ/ステージングどちらかに誘導・固定することができます。
ただし一定期間の間そのクライアントからのリクエスト間隔が空いた場合には新規セッションとして扱われるため、前とは別のDistributionにリクエストが割り振られるということは厳密にはあり得るという点は注意です。
クライアントサイド主体でのアクセス先環境指定(緊急時除く)
クライアントサイドで明確にリクエストパラメータを制御することができるのであれば、ヘッダーベースの割り振りを用いることで意図的にプライマリ環境にアクセス・ステージング環境にアクセスとアクセス先を切り替えることができます。
CloudFront継続的デプロイ利用の際の制約事項
クライアントに一方の環境へのアクセスを厳格に強制することは不可能
ウェイトベースの割り振りを行っている場合はある一定時間リクエストがなかった場合は新規セッションとして扱われるため、とある特定のクライアントからのリクエストを常にプライマリ / ステージングに振り分けることは不可能という話は前述した通りです。
また、CloudFrontのサービス自体が高負荷になった場合、常にプライマリDistributionにリクエストルーティングされるような縮退稼働がなされる場合があるということがドキュメントに記載されています。
ビューワーは、DNS 名、IP アドレス、または CNAME を使用してステージングディストリビューションにリクエストを直接送信することはできません。
出典: https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/continuous-deployment.html#continuous-deployment-quotas-considerations
また、継続的デプロイを利用している場合、ステージング環境に直接リクエストを送ることは不可能である仕様となっています。
ビューワーは、DNS 名、IP アドレス、または CNAME を使用してステージングディストリビューションにリクエストを直接送信することはできません。
出典: https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/continuous-deployment.html#understanding-continuous-deployment
そのため、縮退運転時には例えヘッダーベースのリクエスト割り振りを設定していたとしてもステージングへのルーティングを強制することはできません。
ステージングのみの稼働
前述の縮退稼働の件からも、CloudFrontの継続的デプロイはあくまで「プライマリを使ってサービスを健全に稼働させることは大前提であり、とある特定の条件の時のみステージングにお試しでルーティングさせることができますよ」というスタンスであると推察されます。
そのため、プライマリDistributionが本番環境/ステージングDistributionがステージング環境という位置付けを社内でしていたとして、「サービスイン前なため本番環境はまだ動かしたくない、すなわちステージングDistributionだけ用意したい」ということはできません。
プライマリ/ステージングで異なるアクセス制限を行う
プライマリ / ステージングには異なるDistribution IDが割り振られるため、それぞれに異なるWAF ACLを適用できると思う方も多いかもしれません。
しかし、どうやら継続的デプロイを利用している場合にはプライマリ / ステージングともに同じWAFが紐づくようになっているようです。
そのため、プライマリDistributionとステージングDistributionで異なるWAFを紐づけることによってアクセス条件を変えさせるような設定を施すことはできません。
(余談) マルチオリジンの機能を用いてプライマリ / ステージングの厳密なルーティングができるかどうか
継続的デプロイとはまた別の話になりますが、CloudFrontにはマルチオリジンという機能があります。
これを用いれば
- パス
/stg
にアクセスした場合はオリジン1に - パス
/prd
にアクセスした場合はオリジン2に
というリクエスト割り振りが可能であり、クライアントが向き先環境を指定するためにパスを変えることができるのであれば「このクライアントには〇〇の環境の方に絶対にルーティングさせる」ということは可能です。
ただ、CloudFrontがオリジンにリクエストルーティングするときには、このstg
・prd
といったパスまで含めてフォワーディングされるため、オリジン側ではそれを前提としたパス設計が必要となります。が、そこまで考慮した設計をオリジンアプリでするのはなかなか難しいのではないでしょうか……。[3]
また、マルチオリジンの場合は1つのCloudFront Distribution内で設定がまとめられてしまうので、当然全ての環境に対応したアクセス制限の定義を1つのWAFの中でやらなくてはいけません。
もしも、WAFの構文の都合で自分たちの要件が1つのWAFで実現することが不可能だという事態に陥ったとしても、この構成ですと分離・スケールさせるのは大変だと思うので、マルチオリジンで異なる環境を表現するのはあまりいい手段ではないと思います。
CloudFront - まとめ
以上のことからわかる、CloudFrontの性質は次の通りです。
- DNSキャッシュの影響を排除したスピーディーな設定変更が得意
- 継続的デプロイを使用する場合でも一旦は全てのリクエストはプライマリDistributionに飛ぶため
- リクエストを受け取った際にどのオリジン・キャッシュの内容を使うかの設定をエッジサーバー内で変えているだけという理解をすると良い
- あくまでプライマリありきのサービスであり、B/Gのように平等な2環境を動かすという思想ではない
- ステージングがないと成り立たないような仕組み・企画は組まない方が無難
- WAFの設定も同じものが適用されてしまう
- B/Gどちらの環境にルーティングさせるのかを強制することにはあまり向いてない
- 継続的デプロイはプライマリありきの仕組みであり、「意図せぬリクエストが来ることもある、もしきたらアクセス制限の方で弾く」というマインドを取った方がいい
- マルチオリジンを使えばパス指定によってアクセスするオリジンを明確に分けることはできるが、そもそもこの構成はスケールしにくいので危険
API Gateway
API GatewayはREST / Websocket APIを作成・公開するためのマネージドサービスです。
API Gatewayでの複数環境ホスト・切り替え機能
REST APIの場合にはCanaryリリースを行うことができます。
API GatewayのCanaryリリース機能は、とあるAPIステージ(メインステージ)に紐づくCanaryステージを作成し、
- 両者の間で一定割合(0~100%)でリクエストを割り振る
- Canaryステージをメインステージに昇格させる形でのB/Gデプロイ
といった操作を行うことができます。
また、メインとCanaryの間ではキャッシュは共有されません。
異なるバージョンに関連付けられている場合、本稼働と Canary リクエストへのレスポンスは別々にキャッシュされ(以下略)
出典: https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/canary-release.html
API Gateway Canaryステージ利用の際の制約事項
リクエスト先の明示的な選択
リクエストがメインステージに振り分けられるのかCanaryステージに振り分けられるのかは、ある一定の割合のもとで完全ランダムに決定されます。そのため、明示的にメインステージに/Canaryステージにリクエストを送るための設定機構はクライアント側・サーバー側含めて存在しません。
Canaryステージのみの稼働
CloudFrontの継続的デプロイのときと同様に、Canaryステージはあくまでそれに対応するメインステージが存在することを前提とした概念です。
そのため、メインに該当するステージが存在しなかった場合にはエラーが返ってくるようになっています。
次に、prod ステージの Canary デプロイを作成します。
指定されたステージ (prod) が存在しない場合、前述のコマンドはエラーを返します。
出典: https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/create-canary-deployment.html
異なるアクセス制限を行う
メインステージとCanaryステージには同じWAFが紐づけられます。また、リクエストがメインステージに割り振られるかCanaryステージに割り振られるか、WAFを通す段階で判断する術はありません。
そのため、「メインステージは全員に公開、Canaryステージは社内のみ公開」といった異なるアクセス制限をWAFでかけることはできません。
アクセス制限に限って厳密に言えば、メインステージとCanaryステージでLambdaオーソライザーを変えて異なる認証認可を行わせること自体は可能です。
ただ、メインステージとCanaryステージへのリクエスト割り振りが完全にランダムになってしまう都合、両者で異なるアクセス制限を用いると「アクセス許可されるかどうかもランダムに決まる」という挙動にクライアント側から見えてしまうので、あまり使い勝手が良いものではないでしょう。
そもそも、API GatewayのCanaryリリースの思想は「全てのAPIトラフィックをランダムに割り振る」というものだとドキュメントに明記されています。
Canary リリースのデプロイでは、すべての API トラフィックはランダムに区切られて事前に設定された比率で本稼働リリースと Canary リリースに送られます。
(中略)
Canary トラフィックを低く保ち、選択をランダムにすることにより、どのような時でもほとんどのユーザーは新しいバージョンの潜在的なバグに悪影響を受けず、また、常に悪影響を受け続けるユーザーもいません。
出典: https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/canary-release.html
そのため、ランダムに振り分けられた先のバックエンドロジックを変える以外でメインとCanaryで異なる設定を行うというのは、Canaryリリース機能の思想とは異なるところがあるためなるべく避けたほうが無難です。
API Gatewayまとめ
以上のことから、API Gateway Canaryの向き不向きをまとめます。
- (API Gatewayまで辿り着きさえすれば)キャッシュの性質を受けない
- メインステージとCanaryステージは別々のキャッシュを用いるため
- ただし、CloudFrontなど前段にAPI応答をキャッシュするレイヤを挟んでいる場合には、API Gatewayまでリクエストがたどりつかないためそこでのキャッシュの影響を受ける
- 完全にランダムにリクエストを割り振るCanaryリリースには向いている
- sticky sessionはできないので注意
- Canaryステージは一部ユーザーのための限定公開環境ではなく、全ユーザーにランダムに開かれているという点がポイント。ダークカナリアリリースではない。
- そのような意味では、Canaryはメインありきのステージであり、独立したステージングという感じではない。
- リクエスト処理を担うバックエンドサービス以外の差分を、メインステージとCanaryステージにつけるのは得策ではない
Application Load Balancer
Application Load Balancer(ALB)はAWSマネージドなロードバランサーツールです。
ALBでの複数環境ホスト・切り替え機能
ALBで複数環境をホストし、それらへのリクエスト振り分けを行うための機能は大きく分けて2つに分けられます。
- 高度なリクエストルーティング
- 加重ターゲットグループ
- 複数リスナーのホスト
高度なリクエストルーティング
高度なリクエストルーティングは、1つのリスナーが受けたリクエスト条件に応じてルーティング先のターゲットグループを決める機能です。
条件として以下のものを設定することができます(出典)。
- HTTPヘッダー: 「
User-Agent
がSafari
の場合はターゲットグループAに」といったルーティング - HTTPメソッド: 「
POST
リクエストならターゲットグループBに」といったルーティング - ホスト名: 「
ccc.example.com
へのリクエストならターゲットグループCに」といったルーティング - パス名: 「
/image
へのリクエストならターゲットグループDに」といったルーティング - クエリパラメータ:
example.com?version=v1
のように、version=v1
のクエリパラメータがついているならターゲットグループEに」といったルーティング - 送信元IP: 「〇〇のCIDRからのリクエストならターゲットグループFに」といったルーティング
加重ターゲットグループ
加重ターゲットグループは指定した割合によって2つのターゲットグループ間でリクエストを分散させる機能です。
これを利用することで例えば「ターゲットグループAとターゲットグループBに、1:2の割合でリクエストする」といった設定が可能になります。
複数リスナーのホスト
また、高度なリクエストルーティングを用いて「1つのリスナーを使ってリクエストを受けて、条件によって振り分ける環境を変える」という方式を組むのではなく、単純に「1つのALBの中に複数のリスナーを用意して、リスナーAで受けたリクエストは環境Aに、リスナーBで受けたリクエストは環境Bに」という構成も組むことができます。
ALBで実現可能な要件
サーバーサイド主体での(緩やかな)sticky session
加重ターゲットグループを利用した場合、配下にある2種類のターゲットグループのうちどちらにルーティングされるかはランダムです。
しかし「ターゲットグループの維持(TargetGroupStickinessConfig)」という設定を有効化することによって、指定した有効期限内まではルーティング先のターゲットグループをクライアントごとにどちらか一方に固定させることができます。
セキュリティグループを利用したアクセス制限
ここまで紹介してきたリソースの中で、ALBは唯一セキュリティグループでのアクセス制限が可能です。
そのため、ポートAでリクエストを受けるリスナー・ポートBでリクエストを受けるリスナーを同時に1つのALBに配置した上で
- ポートAへのリクエストはIP制限なしで通す
- ポートBへのリクエストは社内VPNのIPからしか通さない
といった制御を行うことも条件によっては可能です。
どのような時にできないかは後述します。
ALBを用いる場合の制約事項
ルーティング条件にNOT・正規表現が使えない
「高度な」リクエストルーティングとはいえ、指定できる条件には限りがあります。
例えばNOTの条件は記述することはできないので「User-Agent
ヘッダーが〇〇の値以外なら〜〜」という条件指定は不可能です。
また、ワイルドカードとして*
を条件式の中に使うことはできますが、それ以上複雑な正規表現を条件の中に混ぜることはできません。
送信元IPはクライアントのIPを表しているとは限らない
リクエストルーティング条件の中に送信元IPがありますが、前段にCDNのようなプロキシを挟んでいる場合はそのプロキシのIPがここでの判定条件として用いられます。
本当のクライアントIPを特定するためにはX-Forwarded-For
ヘッダーを使うことが多いですが、ALBのルーティング条件では「X-Forwarded-For
ヘッダーに格納されているIPアドレスが特定のCIDRの中にあるかどうか」という複雑な判定はできません。
また、セキュリティグループでのアクセス制御を行う際にもこのことを考慮する必要があります。
前段にCloudFrontのようなCDNを挟んでいる場合にはアクセス元IPはそのCDNサービスのものとなるため、「特定のポートは社内VPNからのアクセスだけを通す」という設定をALBでしても効力を発揮しません。
ALBまとめ
ALBの機能・特徴についてまとめてみます。
- クライアントサイド・サーバーサイドともにリクエストルーティングに関する機能が比較的豊富
- 高度なリクエストルーティングを使うことで様々な条件でリクエスト先を割り振ることが可能で、クライアントサイドでアクセス先環境をコントロールできる
- 条件に正規表現やNOTが使えないなど限度はあるが、他サービスと比べると手数は多い
- サーバーサイドの目線でも、sticky sessionでクライアントアクセス先環境を固定させることが可能
- ただし、比較的後段に位置するサービスであることから、送信元IPがそのままクライアントIPとは限らないケースが多い
サービス選定観点
要件ベースでの比較
ここまでAWSの各サービスの機能について触れてきましたが、異なる環境を同時にホストさせたいという状況では以下の観点が重要になるでしょう。
- 環境Aと環境Bでエンドポイントの違いがあるかどうか
- 全く同じエンドポイントで、ランダムにアクセス環境が決定される
- エンドポイントは同じだが、ヘッダーなどリクエスト内容によってアクセス環境が決定される
- エンドポイントのホスト名は同じだが、パスが異なる
- エンドポイントのホスト名から異なる
- 環境Aと環境Bどちらにアクセスするかをクライアントは意図的に選択できるか
- クライアントにどちらの環境へアクセスさせるかをサーバーサイドで指定・固定させることができるか
- sticky sessionなどの機能を想定
- 環境へのアクセス制限設定を個別に行うことができるか
そして、ご紹介してきたソリューションがこれらの観点を満たすかどうかをまとめてみます。
サービス | エンドポイント | クライアントが選択可能か | サーバーサイドで固定可能か | アクセス制限設定 |
---|---|---|---|---|
Route53 加重ルーティングポリシー | 全く同じエンドポイントでランダム選択 | 選択不可 | 固定不可 | 制限機能なし |
Route53 IPベースのルーティングポリシー | 全く同じエンドポイントでIPによって遷移先が決定 | VPNのon/offでできる場合があるが万能ではない | 固定不可 | 制限機能なし |
CloudFront 継続的デプロイ ウェイトベース | 全く同じでランダム選択 | 選択不可 | 一定時間限りのsticky sessionあり | 同じWAF設定が適用 |
CloudFront 継続的デプロイ ヘッダーベース | 全く同じでヘッダーによって遷移先決定 | ヘッダーによって選択可能(例外あり) | -(クライアント側で選択) | 同じWAF設定が適用 |
API Gateway Canaryリリース | 全く同じエンドポイントでランダム選択 | 選択不可 | 固定不可 | 同じWAF設定が適用・オーソライザーを分けることはできるが得策ではない |
ALBを共有 | 全く同じエンドポイントでリクエスト条件によって遷移先決定 / ホスト名同じでパスが異なる | パスやリクエストパラメータで選択可能 | 一定時間限りのsticky sessionあり | 同じWAF設定が適用・セキュリティグループを作り込めるが、CDNが前段にある場合には送信元IPの特定が難しい |
こうして横断的な視点で見るとわかることが2つあります。
まず1つ目は、どのサービスを使ったとしても同時にホストしている環境でアクセス制限設定を柔軟に変えるということは難しいということです。
Route53に関してはそもそもアクセス制限という概念がありませんし、CloudFrontやAPI Gatewayではメインとステージングで同じWAFを使うことを強いられます。
ALBでは異なるリスナーを使って異なるポートで複数環境をホストするようにすれば、セキュリティグループでアクセス制御を試みることは可能ですが、それは前段にCDNのようなプロキシサービスがないことが前提となっていますので万能とはいえません。
本番デプロイ前の最終チェックを行うステージング環境という意味合いでの複数環境ホストであり、そのステージング側へのアクセスを限られた人だけに絞りたいのであれば、この記事で紹介したような機能を使うのではなく、アクセス制御機能だけ変えて他は全く同じという複製環境を用意するしかないのだと思います。
2つ目は、サーバーサイドでとあるクライアントのリクエストを一方の環境に固定する方法は少ないということです。
APIv GatewayやRoute53のように完全ランダムとなってしまうものもありますし、ALBやCloudFrontのようにsticky sessionがあっても、セッション固定できる期間が決まっていたりもします。
アクセス環境をきっちり固定したいのであれば、特定のリクエストヘッダをつけるなどしてクライアント側で制御する方式を取る方が確実です。
各サービスの特性
また、各サービスの特性についても考察してみます。
- Route53
- A/Bテストなど、ホストしている2つの環境のうちのどちらにリクエストが飛んでも大きな問題にならないような環境に向いている
- CanaryリリースやB/Gデプロイにも流用可能、ただしDNSキャッシュの存在があるため急激な環境切り替えにはおそらく不向き
- CloudFront(継続的デプロイ)
- 現本番環境と全く同じ設定でデプロイするCanaryリリース向き
- ウェイトベースの場合は通常のCanaryリリース
- ヘッダーベースの場合はダークCanaryリリース
- Canaryという性質上「プライマリDistributionとなる本番環境ありき」の思想
- 現本番環境と全く同じ設定でデプロイするCanaryリリース向き
- API Gateway (Canaryリリース)
- (名前の通り)現本番環境と全く同じ設定でデプロイするCanaryリリース向き
- Canaryという思想上「メインステージとなる本番環境ありき」の思想
- ALB
- A/Bテスト・B/Gデプロイ・Canaryデプロイなど大体のことは何でもできる
- ただし比較的後段に配置されているサービスであるため、CDNのようなプロキシを挟んでいる場合はこの断面でアクセス制御を行うことは難しい
まとめ
以上、B/GやCanaryっぽい機能をまとめて考察してみた記事でした。
ただ単純に全く別の複製環境を作れば良いじゃん!とはならずにこのようなCanary的な機能を求めるとしても、目的によってどのリソース断面で複数環境ホストの仕組みを作り出すのか・そもそも本当にCanary的な仕組みが必要なのか/ただの複製環境でいいのではないかというところも変わってくるかと思います。
本記事の内容をもとに、皆さんの要件整理・言語化の助けになれれば幸いです。
-
B/Gのようなルーティング先切り替えについては条件付きで可能です → https://dev.classmethod.jp/articles/atomic-swap-cloudfront-cname/ ↩︎
-
リクエスト割り振りに利用するヘッダー名は
aws-cf-cd-
から始まっていないといけないという制約があります。 ↩︎ -
stg/prdだと容易そうに見えますが、v1/v2...のように総数が読めないようなパスを考えると、どんな文字列にも対応できるような拡張性を担保するのはしんどそうに思えます。 ↩︎
-
参考ブログ → https://dev.classmethod.jp/articles/tsnote-how-to-configure-source-ip-for-listener-rules-in-multistage-alb/ ↩︎
Discussion