AWS CloudFormationでBlueGreenデプロイを実現してみた(第2回)

2019.11.25 Cloud

こんにちは、BTCクラウドCoEの西村です。

今回のBTC Tech Blogは引き続き「AWS CloudFormationでBlueGreenデプロイを実現してみた」(第2回目)です。

 

前回のおさらい

第1回目では、クラウドに代表されるデプロイ/リリース方法と、それぞれのメリット・デメリットを説明しました。
また、支援プロジェクトで、CFnテンプレートでインフラを定義しつつ、BlueGreenデプロイを完全自動化するシステムを構築したという頭出しだけさせていただきました。

 

アーキテクチャの説明とBlueGreenデプロイの採用について

ここからは、実際に支援したプロジェクトで構築したシステムを元に、インフラのコード化と、BlueGreenデプロイの自動化について説明します。

アーキテクチャ

・グローバルコーポレートサイトで、海外からのアクセスがあります。
・Route53で名前解決、CloudFrontで静的コンテンツのキャッシュとパスベースのトラフィック振り分け、HTTPSへのリダイレクト処理を実施しています。S3に静的コンテンツが格納された場合、Lambdaを発火させてCloudFrontのキャッシュをクリアしています。
・フロントサイドはOWASP TOP10に基づいたルールをWAFで管理し、ELBに付与しています。管理サイドはWAFは付与せず、想定したルートからのアクセスのみWordPressに振り分けるようルールを設定しています。想定外のルートからのアクセスはLambdaを使用してSNSでメール通知させています。
・システム全体が冗長構成となっており、RDSでもMultiAZを設定しています。

アーキテクチャ概要

 
全体概要は上記の通りですが、細かいところでは以下の構成を採用しています。
・Bastionサーバは用意せず、AWS Systems Manager(以下、SSMと略します。)のセッションマネージャ経由でOSにアクセスしています。
・AWS BackupやSSM Automation、AWS Lambdaなどを利用してバックアップを取得しています。
・監査や監視の設定はもちろん、ほぼ全てのセキュリティ系サービスを取り入れています。
・S3に格納したログはライフサイクル設定により、一定期間経過後にGlacierへの移行、削除が実施されます。

CFnテンプレートの構成設計

これらの設定に加えて、AWS CodePipelineや予算の設定もCFnテンプレートで定義し、スタックとして展開しています。
CFnを利用する場合、論理的な役割ごとにテンプレートを分割することが基本となります。
今回の支援プロジェクトでは、4つの親テンプレートをメインとする形で、以下のようにテンプレート分割を行いました。

ネストスタックの詳細はネストされたスタックの操作を参照ください。

CloudFormationテンプレート分割

 
まず、4つの親テンプレートのうち、以下の3つについては一度スタックを展開したら二度と削除されない想定のものです。
・aws-wordpress-master-01-vpc.yaml
・aws-wordpress-master-03-dns.yaml
・aws-wordpress-master-04-adminpath.yaml

BlueGreenデプロイによって回転させるスタックは、以下のテンプレートによって展開されるスタックとなります。
・aws-wordpress-master-02-bluegreen.yaml

BlueGreenデプロイの自動化はAWS CodePipelineによって実施されますが、この時、「aws-wordpress-master-02-bluegreen.yaml」で展開されるスタックとそれ以外のスタックで依存関係(クロススタック参照など)があると更新や削除ができなくなってしまいます。
詳細は別の機会にお話ししますが、「aws-wordpress-master-03-dns.yaml」から展開されるAmazon CloudFrontが、「aws-wordpress-master-02-bluegreen.yaml」から展開されるELBを指定している場合、参照されている状態ではBlueGreenを回せませんよ~というエラーが表示されます。

依存関係は発生してしまうのに、依存関係があるとCFnでのBlueGreenデプロイができない。。。という状況を解決してくれるのがSSM Parameter Storeです。
SSM Parameter Storeは設定データ管理と機密管理のための安全な階層型ストレージです。KeyValue型で依存関係の発生するパラメータを格納することで、スタックを回していくことが可能になりました。

BlueGreenデプロイフロー

さて、本題のBlueGreenデプロイの流れの説明に入ります。
今回構築したシステムはグローバルなサイトであり、夜間対応という概念がありませんでした。また、デプロイ作業(WordPressのアップデートやOSパッチ適用、テーマの更新、プラグインのインストールとアップデートなど)後は、参照だけでなく登録や削除といった動作確認も完了した上で公開したいというご要望があり、BlueGreenデプロイを採用しています。

この際、登録や削除といった動作確認のためにはEFSやRDSもGreen環境として構築する必要がありましたので、スタック全体を入れ替える形でのBlueGreenデプロイが必要でした。

ということで、実際のデプロイフローは以下の通りです。
※細かい調整内容は省略しており、大枠でのご紹介になります。
デプロイフロー前半

デプロイフロー後半

 
順に説明します。
①CodeCommitへのPush
コードリポジトリとしてCodeCommitを使用しています。
Greenスタック展開用パラメータファイルおよびCodeDeploy設定ファイルをCodeCommitへPush(CodePipeline発火)します。
ここで、新旧スタック名などの、設定が必要な最低限のパラメータを渡します。

②Green環境の構築
LambdaでAMI、RDSスナップショットを自動取得し、Greenスタック展開用パラメータファイルを読み込み、CFnを利用して「aws-wordpress-master-02-bluegreen.yaml」から新規でスタックを展開します。
ここで、テンプレートに定義してあるELB、EC2、RDS、EFSのコピーを作成するのですが、EFSはこの時点では真っ新な状態です。

2019/10/25現在では、EFSのデータを引き継いだ状態でコピーを作ることができません。
ということで、悩んだ末の対応策は以下の通りです。
ⅰ. CFnテンプレートで専用のEC2を1台作成
ⅱ. UserDataの定義で新旧EFSを別のディレクトリでマウント
ⅲ. UserDataの定義で旧EFSから新EFSへファイルコピー

上記の対応で、不格好ではあるもののEFSを複製したのと同じ状態になります。

③Green環境のサーバ内調整
Green環境構築後に必要になるのはOS上での設定変更です。
今回の場合はDB接続情報を新RDSに向ける必要がありますが、Lambdaでは内部ファイルを変更できません。
ここで利用したのがSSM RunCommandです。
あらかじめCFnテンプレートで定義済みのドキュメントに引数を渡す形で設定ファイルを更新します。

④CodeDeployを利用したWordPress環境設定ファイルのデプロイ
WordPressではthemesフォルダの更新に失敗すると、画面崩れが発生する可能性があります。
このようなファイル群はBlueGreenデプロイを利用して、安全な状態で更新しましょう。
また、ここではpluginsフォルダもデプロイ対象としました。EFSのパフォーマンスの問題で、プラグインによっては管理画面からの更新でタイムアウトが発生するためです。
2019/11/25現在では、プラグインの問題を解決できる程度までEFSの性能を向上する方法はないようです。

⑤EFSデータコピー用EC2の削除
Green環境へのEFSデータコピー用EC2は今後必要なくなりますので、デプロイフローの中で削除しておきます。
ここで、対象のスタックごと削除してしまうと、環境を削除する際にエラーが発生しますので注意してください。スタックは残したままリソースのみを削除します。

ここまでのフェーズで、Green環境の構築が完了しています。ここから先は環境を入れ替えるフェーズに入ります。

⑥CloudFrontの向き先を新ELBに変更
CloudFrontを挟んでいますので、Route53ではなくCloudFrontの向き先を更新します。
入れ替えまでにGreen環境での動作確認はしっかりと行ってください。

⑦Blueスタックの削除
環境を入れ替え、エンドユーザがGreen環境にアクセスするようになったらBlue環境は不要です。
念のために数日の間Blue環境を残しておき、不具合の報告がなければ削除するという運用もアリかと思います。
CodePipelineで手動承認フェーズを挟んでいますので、仕様上1週間は⑥までの状態で待機可能です。

 

反省点

お気づきの方もいらっしゃるかと思いますが、ご紹介したBlueGreenデプロイではGreen環境構築後のBlue環境での更新分が反映されません。
今回はコーポレートサイトの構築でしたので問題はなかったのですが、デプロイ作業中は運用担当者は作業を止める必要があります。
改善案としては、
・同一RDS内で別DBを構築して、新規DBをGreen環境で利用する。
・スナップショットでの環境コピーではなく、リードレプリカをGreen環境側に構築する。
などが考えられます。

また、EFSのデータコピーやパフォーマンス問題での対応など、ベターな方法がありそうな気はしています。
良いアイデアのある方は教えていただきたいです。

 

まとめ

デプロイ中のデータ同期方法を突き詰めていけば、どのようなシステムに対しても上記のBlueGreenデプロイを実施できそうです。
CFnテンプレートで定義しておけば再利用も容易ですね。

また、上記フローを見て、「これってImmutableデプロイに近いのでは?」と感じられた方がいらっしゃるかもしれません。
その通りなのですが、私にはサーバの「本番環境のサーバに手を加えない」という思想はなく、切り戻しも可能な状態でしばらく残しておくことも加味して、勝手ながらBlueGreenデプロイと呼ばせていただいております。
BlueGreenとImmutableのハイブリッドと考えてもらえればカッコいいですね!

本投稿はこの辺りで締めたいと思います。
次回はInfastructure as CodeやCI/CDといったテーマで執筆する予定です。