この記事は Create a pipeline with canary deployments for Amazon ECS using AWS App Mesh を翻訳したものです。
この記事では Amazon Elastic Container Service (Amazon ECS) で実行されるアプリケーションのカナリアデプロイ戦略を、AWS App Meshと組み合わせて実装する方法を説明します。ALB の加重ターゲットグループを使用した AWS CodeDeploy でのカナリアデプロイを行う場合はこちらの記事を参照してください。
Amazon ECS や Amazon EKS などのコンテナオーケストレータを利用することで、世界中のお客様は複雑なアプリケーションを大規模に実行できます。ただし、これらのツールの機能を活用する場合、お客様は高度に分散されたサービス群を実行するために、分散アーキテクチャにおけるマイクロサービス間の接続性、運用、およびセキュリティの管理について考える必要があります。
AWS App Mesh は、アプリケーションレベルのネットワーキングを提供するサービスメッシュで、様々なタイプのコンピューティングインフラストラクチャ上でのサービス同士の通信を容易にします。また、エンドツーエンドの可視性を提供し、アプリケーションの高可用性を確保するのに役立ちます。App Mesh はアプリケーション内のすべてのサービス間の一貫した可視性と、ネットワークトラフィック制御を提供します。
カナリアデプロイ/リリースでは、特定のアプリケーションの新しいバージョンをデプロイした後、ビジネスニーズに応じてユーザー定義のパーセント単位でトラフィックを切り替えられます。また、新しいバージョンの状態を監視できるため、問題が発生した場合でも自動的にトラフィックを古いバージョンに切り替えることができます。新しいバージョンのアプリケーションに混入したバグが、エンドカスタマーに与える影響を減らすことができます。このアプローチは、新しい機能の実装に役立つだけではなく、複雑な分散型マイクロサービスのテストのニーズにも対応しており、トラフィクの一部をコントロールしながら新しいバージョンに送ることができます。
以下のアーキテクチャ図は、パイプラインの作成に使用される AWS サービスの概要を示しています。
このアーキテクチャをデモするために Yelb というアプリケーションを使用します。Yelb のアプリケーション上で、ユーザーがレストランなどの一連の選択肢に投票すると、投票に基づいて円グラフが動的に更新されます。さらに、Yelb はページビューの数を追跡し、yelb-appserver
インスタンスのホスト名を出力します。このホスト名は、投票やページ更新の API リクエストを受けるタスクの (Amazon ECS で awsvpc ネットワークモードを利用した際の) IP アドレスになります。Yelb には以下のコンポーネントが含まれます。
Yelb のアーキテクチャは次のようになります。
Yelb の設定では、すべてのコンテナにエフェメラルディスクが使用されます。この方法でデータベースを実行するのは、あくまでデモのためであることにご注意ください。
この記事では AWS のオレゴンリージョン (us-west-2) を使用します。
以降の手順では必要なツールが備わった環境が必要です。このチュートリアルを実行するために AWS Cloud9 インスタンスを使用します。AWS アカウント上に Cloud9 インスタンスを作成する場合、Amazon ECS Workshop の “Create a Workspace” の章の初めから “Validate the IAM role“ までの手順を参照してください。
パイプラインを作成する前に、インストールや設定が必要なものがいくつかあります。まず GitHub リポジトリのクローンを作成することから始めます。
# ヘルパースクリプトと、ブログ投稿のリソースgit clone https://github.com/aws/aws-app-mesh-examples.gitcd aws-app-mesh-examples/blogs/ecs-canary-deployments-pipeline/# サンプルアプリケーションgit clone https://github.com/tiagoReichert/yelb.git && mv yelb microservices
手順を簡略化するためにMakefile
を追加しています。この Makefile は、ダウンロードしたリソースのsetup
フォルダの下に配置されたヘルパースクリプト実行します。 これらのヘルパースクリプトは AWS Cloud9 インスタンスで作成およびテストされており、次の手順でリソースの作成を容易にするために使用されます。ヘルパースクリプトの機能を理解するために、スクリプトの中身を確認してみてください。
それでは、いくつかの環境変数をエクスポートすることから始めましょう (これらの変数は自由にカスタマイズしてください) 。
make set-env
また、AWS クラウド上で、定義された仮想ネットワークで AWS リソースを起動する論理的に分離されたセクションをプロビジョニングするためには、Amazon Virtual Private Cloud (VPC) が必要です。VPC では自身で定義した仮想ネットワーク内で AWS リソースを起動することができます。独自の IP アドレス範囲の選択、サブネットの作成、ルートテーブルとネットワークゲートウェイの設定など、仮想ネットワーク環境を完全に制御できます。
make create-vpc
Amazon Elastic Container Service (Amazon ECS) は、クラスター上のコンテナの実行、停止、管理を容易にするスケーラブルで高速なコンテナ管理サービスです。ここでは、ECS サービスを起動するための前提条件を備えた空の Amazon ECS クラスターと AWS App Mesh でのサービスメッシュを作成し、マイクロサービスでカナリアデプロイを実行するために使用します。
make create-ecs-mesh
CloudWatch Container Insights の Prometheus メトリクスのモニタリング は、コンテナ化されたシステムとワークロードからの Prometheus メトリクスの検出を自動化します。Prometheus は、オープンソースのシステム監視およびアラートのためのツールキットです。詳細は Prometheus のドキュメントにある “What is Prometheus?” を参照してください。動的なサービスディスカバリメカニズムの概念を活用し、正規表現ベースのサービスディスカバリに基づいて、ECS タスク定義の ARN をベースに ECS タスク定義を検出します。
make create-monitoring-resources
これですべての要件がインストール、設定されたので、マイクロサービスごとに AWS CodePipeline を利用したパイプラインの作成を進めることができます。
共有の AWS CloudFormation スタックには、パイプラインのデプロイステージを担当する複数の AWS Lambda 関数と 1 つの AWS Step Functions ステートマシンが含まれています。すべての設定パラメータを入力として受け入れるため、すべてのデプロイで同じリソースを使用できます。
AWS Step Functions のステートマシンは、マイクロサービス単位のリポジトリで利用可能な CloudFormation テンプレートのヘルパーを使用して、カナリアデプロイを実行する複数の Lambda 関数をオーケストレーションします。これは、ユーザーが定義した待機時間を考慮して、アプリケーションの複数バージョン間でトラフィックの切り替えを行います。
ステートマシンのワークフローの概要:
FAILED
になるとどうなりますか?では、共有のCloudFormationスタックを作成してみましょう。
make create-shared-cloudformation-stack
最後のコマンドがCREATE_COMPLETE
を返した場合のみ、次のステップに進みます。
パイプラインの AWS CloudFormation スタックは、マイクロサービス単位でデプロイするように設計されています。1つのAWS CodeCommit リポジトリと、そのリポジトリの master ブランチへの新規コミットをトリガーとするパイプラインを作成します。
デモ用に Yelb マイクロサービスで 4 つのスタックを作成します。USE_SAMPLE_MICROSERVICES
という環境変数を「False
」に変更すると、パイプラインに必要なすべてのリソースと空の AWS Code Commit リポジトリが作成され、独自のソースコードで使用できるようになります。
Yelb アーキテクチャには4つのマイクロサービスが含まれているため、必要なすべての AWS CloudFormation スタックを作成するスクリプトを作成しました。
make create-sample-microservice-pipeline-stack
最後のコマンドで「All CloudFormation stacks created successfully!
」と返ってきた場合のみ、次のステップに進みます。
これでアーキテクチャがすべて作成されたので、このアーキテクチャがどのように機能するのか見ていきましょう。
まず、マイクロサービス固有のコードリポジトリがある AWS CodeCommit リポジトリを見てみましょう。 そこには 3 つのファイルがあるspecfiles
というフォルダがあります。これら 3 つのファイルに Dive Deep していきましょう。
canary-helper.yaml
は AWS CloudFormation テンプレートで、デプロイ時に Amazon ECS のサービス、AWS Cloud Map のサービスディスカバリーレコード、AWS App Mesh の仮想ノードの作成に使用されます。デプロイ時に設定できるいくつかの変数が入っていることがわかります。deploy.json
には、マイクロサービスをデプロイするためのコンフィグパラメータが含まれています。以下は、マイクロサービスのリポジトリのディレクトリ構造のレイアウト例です。AWS CodeCommit リポジトリ内の他のすべてのものは、それぞれの Yelb アプリケーションのソースコードです。
作成されたリソースを確認する最も簡単な方法は、AWS CodePipeline を開くことです。AWS コンソール上に先ほど作成した 4 つのパイプラインが表示されています。
その中の一つを開くと、「Source
」「Build
」「Deploy
」のステップが表示されます。これらのステップはすべてカスタマイズ可能です。例えば、デプロイの前にセキュリティチェックや手動承認などを追加することができます。
1.Source
ステップは、AWS CodeCommit リポジトリの master ブランチに変更があるかどうかを監視します。Source ステップ内の AWS CodeCommit のリンクをクリックすると、リポジトリにアクセスできます。
2.Build
ステップでは、AWS CodeBuild 内で Docker イメージをビルドし、Amazon ECR に保存します。Build ステップから「Details」リンクをクリックすると、ビルドログを見ることができます。
3.Deploy
ステップは、共有された AWS CloudFormation スタックによって作成された AWS Step Functions のステートマシンをトリガーします。「Details」リンクをクリックすると、そのステータスが表示されます。
Deploy
ステップから「Details」タブをクリックすると、実行時のインプットとアウトプット、各ステップごとの AWS Lambda 関数や実行ログを確認することができます。
トラフィックの 100% が新バージョンに切り替わり、すべてのヘルスチェックに合格したデプロイメントの成功例は、以下の画像のようになります。
CloudWatch メトリクス の ECS/ContainerInsights/Prometheus ネームスペースを見ると、新バージョン (yelb-appserver-
)の5xx
レスポンスコードが表示されていないはずです。
では、Yelb アプリケーションが動作しているのを確認し、パイプラインの動作を確認するためにいくつかの変更を加えてみましょう。
source ~/.bash_profile && echo http://$APP_URI
上記のコマンドで返された URL をお好みのブラウザで開きます。以下のようなページが表示されるはずです (DNS 名が伝播するのに数分かかる場合があります)。
いくつかの投票ボタンをクリックすると値がどのように更新されるかを確認できます。投票中に何かお気づきになりましたか?
実は、yelb-appserver のマイクロサービスに意図的に問題点を追加し、投票が 1 件あるたびに 2 件ずつインクリメントするようにしました。さて、その問題点を修正するとどのように適用されるか見てみましょう。
AWS CodeCommit のコンソールを開き、yelb-appserver のリポジトリに移動しましょう。modules/restaurantsdbupdate.rb
というファイルを開き、Edit ボタンをクリックして問題点を修正します。以下の行を変更します。
con.prepare('statement1', 'UPDATE restaurants SET count = count +2 WHERE name = $1')
からcon.prepare('statement1', 'UPDATE restaurants SET count = count +1 WHERE name = $1')
へ変更し、コミットします
AWS CodePipeline のコンソールを開くと、数秒後に yelb-appserver-pipeline にIn progress
と表示されます。それを開いてデプロイの進捗を確認します。Deploy stage
になるまで待ち、Yelb アプリケーションのブラウザタブを数回更新します。以下の画像のように App Server のホスト名が元の名前から切り替わっているのを確認できますが、これはカナリアのデプロイが行われているためです。
AWS App Mesh のコンソールで yelb-appserver マイクロサービスの仮想ルーターの詳細を開くと、現時点でのウェイトがどのようになっているかを確認することができます。また AWS CodeCommit の yelb-appserver リポジトリにある specfiles/deploy.json ファイルを開くとpercent_step
とwait_time
パラメータが表示され、すべてのトラフィックを切り替えるのにかかる時間を知ることができます。この例ではpercent_step: 10
とwait_time: 60
という値が使われており、すべてのトラフィックを切り替えるのに合計で 10 分かかります。
デプロイが完了した後、再び Yelb アプリケーションで投票してみると 投票が 1 件ずつ増えていることがわかります。
AWS CodeCommit リポジトリ の yelb-appserver から yelb-appserver.rb ファイルを開きます。本番設定のアプリケーションのポート (33行目) を 4567 から 4568 (または 4567 以外のポート番号) に変更し、変更をコミットします。
すると yelb-appserver-pipeline がトリガーされ、動作しない yelb-appserver マイクロサービスの新バージョンがデプロイされます。AWS CodePipeline で yelb-appserver-pipeline を開き、Deploy ステージが「In Progress」になるまで待ちます。その後、Deploy ステージの下にある Details をクリックします。このページではデプロイ中のビジュアルワークフローが表示されます。
Yelb アプリケーションを開いているブラウザを何度か更新してみてください。リロードしても投票データが返ってこず、投票できない状態であるのがわかります。これは動作していない新バージョンにリダイレクトされているためです。
数分待つと、新しいバージョンがヘルスチェックを通過しなかったため、ロールバックが発生したことがビジュアルワークフローで確認できます。ここで重要なのは、今回のワークフローにおけるヘルスチェックの責務は AWS Lambda 関数であり、必要に応じてカスタマイズすることができるということです。
CloudWatch メトリクスの ECS/ContainerInsights/Prometheus 名前空間を見ると、古いバージョンはまだレスポンスコード2xx
を返しているのに対し、新しいバージョンは5xx
を返しています。しばらくすると、新しいバージョンのメトリクスは削除されたため (自動ロールバックされて)、存在しなくなることがわかります。
Yelbアプリケーションを開いているブラウザを何度か更新すると、以前のバージョンで正常に動作するようになります。
以下のコマンドで、前のステップで作成したリソースを削除することができます。
make delete-blog-contents
この記事では AWS App Mesh を活用し、AWS Code Pipeline や AWS Step Functions などの他の AWS サービスと連携してカナリア式のデプロイ戦略を実施する方法を紹介しました。
さらに、AWS App Mesh をより深く知りたい場合は、以下の便利なリンクをご参照ください。
App Mesh のロードマップで今後の機能を確認したり、App Mesh のプレビューチャンネルで新機能を試したりすることができます。また、App Mesh の Slack コミュニティに参加して、チームや仲間と経験を共有したり議論したりすることもできます。
翻訳はソリューションアーキテクト加治が担当しました。原文はこちらです。
カテゴリー
関連記事
ホット記事