こんにちは、アンドパッドSWEの あかりです。
最近子供が産まれて、よく抱っこ写真を撮るのですが、写真を振り返るといつも自分だけ同じ服装をしているのを少し恥ずかしく思ってきた今日この頃です。 ちなみに、息子は毎曜日服装が違うほど服を持っていて、家族一のおしゃれになっていますw
1. 概要
最近、アンドパッドで最も古くから稼働している施工管理サービスについて、その非同期処理基盤をBlue/Greenデプロイ化しました。このデプロイフローの変更は大きく2段階を踏んで実現しています。本記事では、その後半部分の「非同期処理基盤を実際にBlue/Greenデプロイ化した話」について説明します。前半部分に当たる、非同期処理基盤から定期実行ジョブの処理基盤を抽出・分離した話についてはこちらの記事をご参照ください。
2. 前提の説明
施工管理サービスの非同期処理基盤をBlue/Greenデプロイ化しました[前編]にて説明した改修を経て、インフラ構成、および、デプロイフローは下図のようになっています。(図中の赤線はredis-namespaceを利用してnamespaceを分けていることを表現しています。)
前編の記事の再掲になりますが、施工管理サービスでは以下4種類のサーバが存在しており、ユーザーリクエストを同期的に処理するfrontサーバのみがBlue/Greenデプロイされるようになっています。より詳細な前提の説明は、前編の記事をご参照ください。
サーバ | 説明 |
---|---|
frontサーバ | ユーザーからのリクエストを同期的に処理するサーバ |
backサーバ | frontサーバがエンキューした非同期ジョブを実行するサーバ |
schedulerサーバ | 定期実行ジョブをエンキューするサーバ |
workerサーバ | 定期実行ジョブを処理するサーバ |
3. 非同期ジョブの処理を担うbackサーバのBlue/Greenデプロイ化とは
backサーバのBlue/Greenデプロイ化とは、下図のように、Blue/Greenそれぞれの環境のfrontサーバからエンキューされたジョブをそれぞれの環境のbackサーバで処理させることを指しています。これを実現するには、Blue環境とGreen環境とでRedisのデータベース自体を分けるか、あるいは、redis-namespaceというgemを利用して仮想的にRedisのnamespaceを分ける必要があります(これを下図の赤線で表現している)。施工管理サービスでは、すでにredis-namespaceが導入されていたので、今回はredis-namespaceを利用してBlue/Green環境を分離することにしました(以降、Redisのnamespaceと表現します)1。
4. 要件
非同期処理基盤をBlue/Greenデプロイ化するにあたって、Sidekiqが提供する標準のリトライの仕組みをインフラがサポートすることという要件がありました。Sidekiqが提供する標準のリトライの仕組みというのは、「およそ20日間かけて25回の再試行処理を行う」というもので、このリトライ期間中にバグ修正がアプリケーションに適用されることが期待された仕組みとなっています。よって、非同期ジョブを処理するbackサーバがBlue/Greenデプロイ化された後でも、このリトライの仕組みをインフラ側でサポートする必要がありました。
どういうことか、もう少しわかりやすく説明するために、Sidekiqが提供する標準のリトライの仕組みをサポートせずにbackサーバをBlue/Greenデプロイ化した場合のインフラ構成とデプロイフローを例示します。それは、下図に示すように、非同期ジョブを処理するbackサーバがBlue/Greenいずれか一方の環境でしか稼働していない状態です。
backサーバのBlue/Greenデプロイ化を素直に考えると、上図のようなインフラ構成とデプロイフローで構築してしまいそうですよね😅
ですが、この場合、旧環境側に積まれた再試行キューを処理するサーバが存在しない期間ができてしまうので、Sidekiqが標準としているリトライの仕組みがインフラ側でサポートできなくなってしまいます。
5. 要件を満たすインフラ構成とデプロイフロー
4章で説明した要件を満たすためには、下図のように非同期ジョブを処理するbackサーバをBlue/Green両方の環境で常に稼働させる必要があります。よって、下図に示すインフラ構成とデプロイフローを目標とすることにしました。
6. Blue/Greenデプロイ化にあたっての注意点
目標とするデプロイフローを定めたので、あとは変更作業を行うのみです。この章では、実際にbackサーバをBlue/Greenデプロイ化するにあたって注意が必要だったことを説明します。
6-1. デプロイ & リバートスクリプト
ここまでの説明で察している読者の方もいらっしゃるかもしれませんが、施工管理サービスのデプロイフローはCIOpsを採用しています。つまり、CodeBuildからhelmコマンド2やkubectlコマンドを叩いて、デプロイフローおよびリバートフローを制御しています。
注意が必要だったのは、backサーバがBlue/Greenデプロイ化されていない状態からBlue/Greenデプロイ化された状態に持っていくためのデプロイ & リバートスクリプトと、backサーバのBlue/Greenデプロイ化が安定稼働した後でのデプロイ & リバートスクリプトとが異なる点です。一例を挙げると、Helm ReleaseのRevisionが1の時はhelm uninstallコマンドでリバートする必要がありますが、Helm ReleaseのRevisionが2以上になった時にはhelm rollbackコマンドでリバートする必要があります。ですので、backサーバのBlue/Greenデプロイ化をリリースした後、Blue/Greenデプロイが安定稼働するまでの間、リリース回数を数えながら適宜デプロイ & リバートスクリプトを修正していく必要がありました。
6-2. KubernetesのServiceAccountリソース名の変更
backサーバが処理する非同期ジョブの中には、他のAWSアカウントが所有するS3バケットへオブジェクトをアップロードするものがあります。そのため、backサーバのPodにはIRSA (IAM roles for service accounts)と呼ばれる仕組みを利用してPod単位でIAM Roleを割り当てており、この権限によって他アカウントのS3バケットへPutObjectしていました。そして、このIAM RoleはServiceAccountのリソース名がbackであることを条件に信頼関係を構築していました。ですので、backサーバのBlue/Greenデプロイ化にあたって、ServiceAccountのリソース名をback-blueとback-greenへ変更したことに伴い、信頼関係も修正する必要がありました。
6-3. 全体公開時のPod起動数の増加
Blue/Greenデプロイの全体公開時、ALBのリスナールールで全ユーザリクエストをBlue/Greenで切り替える直前には、社内公開のタイミングでデプロイしていた新環境のPodを旧環境と同じ台数にまでスケールアウトしておく必要があります。つまり、backサーバもBlue/Greenデプロイ化したため、全体公開時のPodの起動数がさらに増加することになります(現時点ではPod数を緩やかに増加する制御は行っていない)。よって、この多数のPodの同時起動によって、RDSやRedisへのアクセスに問題が生じないかを確認する必要がありました。
6-4. Sidekiqが利用するRedisのnamespaceの変更
今まではSidekiqが利用しているRedisのnamespaceは一つでした。そのため、backサーバをBlue/Greenデプロイ化したことで、Blue環境とGreen環境とでRedisのnamespaceが異なるようになりました。ですので、Blue/Greenの両方の環境で参照するデータはRedisではなくRDBで保存してもらうよう修正するか、あるいは、もう一方のRedisのnamespaceも参照できるようにロジック変更をしてもらうよう、開発者に依頼する必要がありました。
6-5. Sidekiq Web UIとオートスケール指標
Redisのnamespaceが分かれたので、namespaceごとにSidekiq Web UIをホストするサーバが必要になりました。また、Blue環境とGreen環境とを独立してオートスケールさせる必要があるので、「Blue/Greenそれぞれのオートスケール指標の算出に必要となるメトリクスを出力するエンドポイント」3をホストするサーバも必要になりました。そこで、下図のように、これらの役割を担うサーバ(図中のmonitoring-sidekiqサーバ)をbackサーバと伴走させる形で配置するようにしました。
7. まとめ
この記事では、アンドパッドで最も古くから稼働している施工管理サービスの非同期処理基盤をBlue/Greenデプロイ化した話について説明しました。Sidekiqとredis-namespaceを利用した非同期処理基盤をBlue/Greenデプロイ化するにあたって考慮すべきことをおよそ網羅できたかなと思いますので、今後Blue/Greenデプロイの導入を検討される方々にとって、何らかの手助けになれば幸いです。
最後に
アンドパッドでは、様々な技術要素を活用して開発に取り組んでいます。 一緒に開発、挑戦していただける方を大募集しておりますので興味のある方は下記をご覧ください!
- Sidekiq 7.0以降では、redis-namespaceはサポートされなくなるそうです。↩
- 施工管理サービスのマニフェストはHelmチャートで管理しています。↩
- 施工管理サービスでは、全Sidekiq workerプロセス数に対するジョブを処理しているworkerプロセス数の割合を元にbackサーバをオートスケールさせています。そして、「そのオートスケール指標の算出に必要となるメトリクスを出力するエンドポイント」をsidekiq-prometheus-exporterというgemを利用して用意しています。↩