始めまして、2022年11月にフォースタートアップ株式会社にSREとして入社した表(@Retomo2214)と申します。 現在は社内向けプロダクト「タレントエージェンシー支援システム(SFA/CRM)」のシステム開発、運用を担当しております。
初めてのブログ執筆のため、拙い文章になっていると思いますが、生温かい目で見守っていただければ幸いです。
はじめに
2022年にRails7へのメジャーバージョンアップ対応およびWebpackerからViteへの移行対応を行っておりました。変更ファイル総数が約1500ファイルとなる大規模リリースをBlue/Greenデプロイメントを実施して失敗した話をつらつらと書いていきたいと思います。 本記事はアンチパターンとして皆様がリリースする際の確認材料の一つとなれば幸いです
本記事をお読みいただく上でのインプットとして技術スタックをご紹介します。
いままでのリリース方法
小規模かつ可逆的な変更を頻繁に行うことを重視しておりますので、インプレースデプロイ(In-Place Deployment)という手法を採用しておりました。 インプレースデプロイとは稼働中サーバに対して直接アプリケーションを配置、再起動するという一般的なリリース手段です。しかし今回は、インプレースデプロイではなくBlue/Greenデプロイメントを採用しました。
▼インプレースリリースのイメージ図
リリース方法変更の理由
下記より今回のリリースは”小規模かつ可逆的な変更を頻繁に行う”という考えから逸脱しており、インプレースデプロイを行った場合のユーザ影響が非常に大きいと考えました。
【今回のリリースの特徴と課題】
更新ファイル数が約1500ファイル
- 不具合発生時に依存関係の洗い出しや修正に時間がかかる。
CI/CD実行に約1時間かかっていた
- ロールバックする際にも同様の時間が発生するため、もし障害が発生した場合、ユーザが利用できない時間が長期化する
【インプレースリリースを採用した場合に発生しうる課題】
深夜作業必須
- 稼働中のサーバに対してデプロイを行うため、ダウンタイムが発生し業務影響発生する
リリース⇨失敗⇨修正⇨リリースを繰り返す可能性がある。
- ファイル数が多く依存関係も多々あるため、何度もリリースを失敗する可能性があった。
課題の多いリリースの様に思えましたが、Blue/Greenデプロイメントを採用することでインプレースデプロイの課題点は解決すると考えました。
Blue/Greenデプロイメントとは?
新しいバージョン(Green環境)を本番バージョン(Blue環境)と並行してデプロイし、ELBのルールなどで本番バージョン(Blue環境)と新しいバージョンを(Green環境)へのトラフィックを切り替えリリースを行う手法です。
▼Blue/Greenデプロイメントのイメージ図
メリットとしてはトラフィックで各環境へのアクセスを制御しているため、本番バージョン(Blue環境)をユーザ提供しながら、新バージョン(Green環境)をデプロイとテストを実施することが可能で、ユーザ影響を考えずに、リリースを実施することができます。 逆にデメリットもあり、コスト面とリリース時の複雑性が上がる点です。 良くも悪くもBlueとGreenの2つの環境を用意する必要があるので、リソース利用料が上昇します。 また、リリース自体も環境が増えることでトラフィックの切り替えなどリリース完了までに実施するタスクが多くなります。
私は普段の開発の様に1度の変更が細かいリリースはインプレースリリースを行い、バージョンアップなど変更の粒度が大きいリリースはBlue/Greenデプロイメントが向いていると考えています。
どのように実現したか
まず、今回のリリースは一般的なBlue/Greenデプロイメントとは少し異なります。 一般的なBlue/GreenデプロイメントではGreen環境でテスト完了後にユーザのトラフィックをGreen環境に流しGreen環境を本番環境に昇格して運用します。 ただ今回のリリースではcronなど2重で動くと業務影響がある処理等が含まれていたため、新規でGreen環境用のブランチを切りました。また、Greenブランチをmainブランチに昇格させたのち、Green環境を本番環境に昇格させるのは1回リリースとしては複雑性がかなり高いと考えました。 そこで今回Rails7へのバージョンアップ対応を行ったfeatureブランチをGreenブランチにマージ後、問題なければmainブランチ(Blue環境)にもマージする方法を取りました。
具体的には以下の順序でBlue/Greenデプロイメントのリリースを行いました。
- 本番用ELBにGreen用のリスナールールとターゲットグループを作成
- Green用のECSサービスを作成する。
- mainブランチからGreen用のブランチを切る。
- Green環境にfeatureブランチ(Railsバージョンアップの作業ブランチ)をマージする。
- Green環境でテストを実施。
- mainブランチにfeatureブランチをマージしてBlue環境にリリース
▼全体像のイメージ図
本構成ではDBをBlue環境とGreen環境で共用しているため、開発者によるDB更新処理のテストは実施できません。 代わりに一部のユーザにGreen環境にログインして通常業務を行なってもらい、Green環境での動作確認を実施してもらいました。 本来であればトラフィックを操作して、ユーザを徐々にGreenに流すことで課題は解消されますが、 当サービスではログイン時に認証が行われるため、トラフィック操作時に再度認証する必要があり、 ユーザの通常業務に影響がある可能性があるため一部のユーザにGreen環境にログインして通常業務を行なってもらい、動作確認する方法を採用しました。
リリース当日
Green環境を構築し、数日間ユーザテストとバグ改修を行い、満を持してBlue環境へのリリースを実施しました。 結果は...大量のアラートが発報されました。 すぐにRevertを行いましたが、ダウンタイムが発生してしまい、Blue/Greenデプロイメントは失敗してしまいました。
僕たちがBlue/Greenデプロイメントに失敗した理由
失敗した理由はGreen環境のテスト時に発覚したバグの修正箇所がBlue環境に反映されていないためでした。 Green環境に反映した更新内容がBlueに反映されていなかった理由は、一部の修正がGreen環境から修正用のブランチを切り、マージしていたためです。
▼失敗原因のイメージ図
本来であれば、Green環境で発生したバグはfeatureブランチに反映させ、Green用ブランチにマージすることで、mainブランチ(Blue)にもGreen用ブランチにも同じ修正が入るはずでした。
▼本来想定していたバグフィックス手順イメージ図
結局のところ僕たちがBlue/Greenデプロイメントに失敗した理由は”ヒューマンエラー”です。 気を付けていても人が作業する以上、必ず発生します。 特にリリース時に発生することが多いイメージです。
僕たちがBlue/Greenデプロイメントを成功させるには
今回の失敗を踏まえて対応策は2点あると考えています。 1つ目は「featureブランチからのマージのみGreen環境がデプロイされる様にする」です。 GitHub Actionsをfeatureブランチからのマージのみ発火する様に設定することで、mainブランチとGreen用ブランチのマージ元が同じであることを担保できます。
2つめは「Green用のブランチを切らない」です。 これは一般的なBlue/Greenデプロイに採用されている方法ですが、コミットハッシュを用いてBlueとGreenを管理する方法です。 流れとしては以下の通りです。
- コミットハッシュをタグにしたイメージをビルド
- ECRにプッシュ
- コミットハッシュをタグにしたイメージを利用するBlue用とGreen用のタスク定義を作成
- コミットハッシュを用いてBlueとGreenそれぞれデプロイする。
▼Gitコミットハッシュを用いたBlue/Greenデプロイメントの図
コミットハッシュを用いてBlue/Greenをデプロイを実施することができれば、コードの中でリリースが完結するので、ヒューマンエラーが発生を抑えられます。 また、Blue環境とGreen環境は同一のブランチに存在するので、Green環境でのテスト完了後そのまま本番環境に昇格させることも容易になります。
まとめ
Blue/Greenデプロイメントは環境を2つ作る必要があるため、どうしても複雑性が高くなってしまいます。複雑性が高いシステムを手動で操作するとヒューマンエラーが発生する確率も上がります。 そのため、下記2点を抑えればBlue/Greenデプロイメントにおける失敗は抑えることができます。 シンプルなBlue/Green構成を構築する。 リリースフローは自動化する。
リリーススピードの観点からは引き続きインプレースリリースを採用する予定ですが、 引き続きBlue/Greenデプロイメント等の様々なリリース手法を精査し、各リリースのタイミングで適した手法を選択していこうと思います。
あとがき
Blue/Greenデプロイメントという手法は以前から認知はしていましたが、 採用は初めてで、実際にやってみると今回の失敗も含めいくつか悩むポイントがありました。 「知っている」と「やったことがある」は雲泥の差ということはよく聞きますがまさにその通りだなと改めて感じたリリースでした。 SREとしてダウンタイムを発生させてしまったのは非常に悔しい結果となりましたが、失敗も資産と切り替えて、皆様に共有したく執筆させていただきました。 今後もどんどんブログを書いていく予定なので、見ていただければ幸いです!!
最後に採用情報です。 当社では、まだまだ採用募集中です。ぜひ一緒に課題解決していきましょう! ご興味ありましたらぜひ一度カジュアルにお話できたらと思います。 採用ページはこちら
参考資料
- https://aws.amazon.com/jp/blogs/news/blue-green-deployments-with-the-ecs-external-deployment-controller/
- https://www.redhat.com/ja/topics/devops/what-is-blue-green-deployment
- https://www.publickey1.jp/blog/14/blue-green_deployment.html
- https://dev.classmethod.jp/articles/operation-blue-green-deployment/
- https://speakerdeck.com/track3jyo/blue-green-deploy-devday
- https://www.sunnycloud.jp/column/20210620-01/