こんにちは!
エンジニアの岩間です。
今回は、Amazon ECS on EC2をブルーグリーンデプロイする際にLaravelのセッション切れを起こさないための対策をご紹介します。
前提条件
- AWS ECS on EC2(※1)上にLaravel10アプリケーションを構築
- LaravelアプリはAppコンテナとWebコンテナの2コンテナで構成
- CodePipeline + CodeDeployでブルーグリーンデプロイ(※2)パイプラインを構築済み
- CodeDeployのデプロイタイプはCodeDeployDefault.ECSAllAtOnce
- 本番リスナーは443、テストリスナーは8443(※3)
- Laravelのセッション保存先はデータベース(RDS)
→.envファイルでSESSION_DRIVER=databaseに変更、RDSでsessionsテーブルを作成済み
以下の画像は構成図です。
(※1 )AWS ECSのインフラはFargate(サーバレス)とEC2インスタンスが選択できます。今回はEC2インスタンスタイプを選択しました。
(※2)ブルーグリーンデプロイメントは、アプリケーションやサービスの新しいバージョンをリリースする際に使用されるデプロイメント戦略の一種です。
従来の「ブルー」の環境と新しい「グリーン」の環境の2つの異なる環境を用意し、トラフィックをブルー環境からグリーン環境に漸進的に切り替えることで、ダウンタイム0でシームレスなトランジションを実現できます。
また、ブルー環境を破棄する前にしばらく並行して実行させておくことでロールバックを容易にし、問題が発生した場合に素早く以前の状態に戻すことができるというメリットがあります。
詳しくはこちら
(※3)ブルーグリーンデプロイメントでは、新しいバージョンのアプリケーションに対するトラフィックを制御するために、テストリスナーとプロダクションリスナーを使用します。
- テストリスナー: 新しいバージョンのアプリケーションに対するトラフィックを一部のユーザーやテスト環境に向けるためのリスナーです。テストリスナーを使用することで、新しい機能や変更の影響を限定的なユーザーに制限し、本番環境への影響を最小限に抑えることができます。
- プロダクションリスナー: 新しいバージョンのアプリケーションに対するトラフィックを本番環境に向けるためのリスナーです。テストリスナーでのテストが完了し、新しいバージョンが本番環境で正常に動作することが確認された後、プロダクションリスナーを介してトラフィックを新しいバージョンに切り替えます。
解決したいこと
ECS on EC2でブルーグリーンデプロイを行う際に、Laravelアプリがセッション中の状態で画面遷移すると「CSRF token mismatch.」のエラーが発生する事象があります。
原因
ブルーグリーンデプロイの際、デプロイタイプをCodeDeployDefault.ECSAllAtOnce(※4)に設定しているため、ALB443リスナーの向き先が一度で同時にブルー環境からグリーン環境に変更されます。
この一括切り替えにより、ブルー環境でセッション中のLaravelアプリがグリーン環境に移行した際に、新しいセッションが再生成されることに起因しています。(グリーン環境で生成された新しいセッションIDは、データベースのSessionsテーブルに存在しない状態)
CSRFトークン(※5)はセッションに紐づいており、セッションIDがブルー環境からグリーン環境に引き継がれないことで、「CSRF token mismatch.」エラーが発生していました。
問題解決のためには、ブルーグリーンデプロイの際にセッション情報を維持させる必要があります。
ブルー環境からグリーン環境にセッションIDが引き継がれることで、CSRFトークンの不一致が防止され、画面遷移時のエラーが解消されます。
(※4) ECSブルーグリーンデプロイを行う場合、CodeDeployのデプロイ設定より、更新された Amazon ECS タスクセットにトラフィックを移行する方法を指定ができます。
以下のようにcanary、リニア、または一度にすべてのデプロイ設定を使用してトラフィックをシフトできます。
項目 | 内容 |
CodeDeployDefault.ECSLiner10PercentEvery1Minutes | すべてのトラフィックが移行されるまで、毎分トラフィックの 10 パーセントを移行します。 |
CodeDeployDefault.ECSLiner10PercentEvery3Minutes | すべてのトラフィックが移行されるまで、3 分ごとにトラフィックの 10 パーセントを移行します。 |
CodeDeployDefault.ECSCanary10Percent5Minutes | 最初の増分でトラフィックの 10 パーセントを移行します。残りの 90 パーセントは 5 分後にデプロイされます。 |
CodeDeployDefault.ECSCanary10Percent15Minutes | 最初の増分でトラフィックの 10 パーセントを移行します。残りの 90 パーセントは 15 分後にデプロイされます。 |
CodeDeployDefault.ECSAllAtOnce | すべてのトラフィックを同時に更新済み Amazon ECS コンテナに移行します。 |
上記の他にも、CodeDeploy→デプロイグループの編集→デプロイ設定の作成で独自のカスタムルールを作成することもできます。
(※5) CSRFトークンは、フォームリクエストやAjaxリクエストなど、アプリケーションが送信するすべてのリクエストに含まれる必要があります。
これにより、リクエストが正当なものであるかどうかを検証し、CSRF攻撃からアプリケーションを保護する仕組みです。
解決方法
上記の事象は、ALBのスティッキーセッションを利用することで解決ができます。
スティッキーセッションとは、ALBで暗号化されたCookieを生成し、 ユーザーのセッションを特定のターゲットにバインドできるようにすることができる機能です。
これにより、セッション中のユーザーからのすべてのリクエストが同じターゲットに送信されるようになります。
詳しくはこちら
設定方法
ブルーグリーンデプロイの際にセッション情報を維持させるためには、以下でご紹介するターゲットグループのスティッキーセッション設定とグループレベルの維持設定をする必要があります。
ターゲットグループのスティッキーセッション設定
まずは個別のターゲットグループに対してスティッキーセッションの設定を行っていきます。
1.構築済みのECSのサービスの画面でデプロイのタブに移動します。
2.ブルー/グリーンデプロイ用ロードバランサーの項目内の「ターゲットグループ1」をクリックします。
3.詳細画面に移動するので、ターゲットグループにチェックを入れ、アクション→ターゲットグループ属性を編集をクリックします。
4.編集画面のターゲット選択設定の項目で、「維持設定をオンにする」にチェックをいれ、維持設定のタイプに「ロードバランサーがCookieを生成しました」を選択します。
維持設定の期間は、セッションを維持したい任意の時間を入力し、設定を保存します。
※ここで維持設定のタイプに「アプリケーションのクッキー」を指定してブルーグリーンデプロイすると、以下のエラーがでてしまいます。
The ELB could not be updated due to the following error: When configuring a rule with multiple target groups, none of them can have stickiness of type 'app_cookie' enabled
複数のターゲットグループを持つルールを構成する際、どれもアプリケーションのクッキータイプを選択することはできないようです。
5.ターゲットグループ2に対しても手順3~4と同様の設定をします。
ここまターゲットグループの個別設定でした。
グループレベルの維持設定
ここからはグループレベルの維持設定です。
上記のターゲットグループの個別設定で維持設定を有効にした場合、リスナーの個別ルールでもグループレベルの維持設定を有効にする必要があります。
※この設定を行わないと、デプロイ時に以下のエラーがでてしまいます。
The ELB could not be updated due to the following error: You must enable group stickiness on a rule if you enabled target stickiness on one of its target groups.
ターゲットグループの維持設定
クライアントに同じバージョンのアプリケーションを指定した期間経験させたい、または現在アプリケーションを使用しているクライアントが、セッション中新しくデプロイされた (グリーン
) バージョンに切り替わらないようにしたいという状況があります。これらのユースケースのために、AWS はターゲットグループの維持設定も導入しました。ターゲットグループの維持設定が有効化されていると、クライアントからのリクエストは、指定された期間中すべて同じターゲットグループに送信されます。その期間が過ぎると、リクエストは重みに従ってターゲットグループに分散されます。ALB は、ターゲットグループの維持設定を維持するためにクッキーを発行します。ターゲットグループの維持設定は、すでに存在するターゲットの維持設定 (スティッキーセッションとも呼ばれます) とは異なることに注意してください。スティッキーセッションは、クライアントからのリクエストが常にターゲットグループ内の特定のターゲットに維持されることを確実にします。ターゲットグループの維持設定は、リクエストが特定のターゲットグループに送信されることを確実にするだけです。スティッキーセッションは、ターゲットグループレベルの維持設定と併用できます。
ターゲットグループの維持設定について、詳しくはこちら
1.再び構築済みのECSのサービスの画面のデプロイのタブに移動し、ブルー/グリーンデプロイ用ロードバランサーの項目内の「プロダクションリスナープロトコル」をクリックします。
2.リスナーの画面に移動するので、対象のリスナールールにチェックを入れ、アクション→ルールの編集をクリックします。
3.ルール条件の定義の画面が表示されますが、特に設定変更せずに次へをクリックします。
4.ルールアクションの定義の画面が表示されるので、「グループレベルの維持をオンにする」にチェックを入れます。
維持設定の期間はセッションを維持したい任意の期間を入力し、次へをクリックします。
5.変更を確認する画面が表示されるので、変更内容の保存をクリックします。
6.変更内容の保存後、以下の画像のように「グループレベルの維持設定:指定した維持期間」が表示されていればOKです。
7.手順1~6をテストリスナー(8443)の対象のルールに対しても同様の設定を行います。
これで設定完了です!
動作確認
設定が完了したら、動作確認をしてみましょう。
ブルーグリーンデプロイでブルー環境からグリーン環境に切り替わった後もセッション情報が維持され、エラーが表示されなくなるかと思います。
Chromeのデベロッパーツール等でCookieの項目を見てみると、ALBスティッキーセッションによって生成されたAWSALB
という名前のCookieが確認できます。
ALBのCookieに関しての仕様はこちら
まとめ
以上、Amazon ECS on EC2のブルーグリーンデプロイ時にLaravelのセッション切れを起こさないための対策でした。
ここまで読んでいただきありがとうございました。
- 電子工作で自作した植物の自動水やり機から土壌データをAWS IoT Coreに連携してみた - 2024-09-13
- 【ESP8266 NodeMCU】電子工作で植物の自動水やり機を作ってみた - 2024-08-14
- Amazon Bedrock APIでTypeScriptのテストコードを出力してみた - 2024-05-07
- AWS CDK × CodeBuild × CypressでE2Eテストを自動化&実行動画をS3に保存してみる - 2024-04-16
- AWS ECSでブルーグリーンデプロイメント!~デプロイメントタイプ別の動作比較~ - 2024-04-03