障害対応を劇的に短縮。CircleCIのロールバック一元管理でPerkが変えたインシデント対応
Staff Software Engineer at Perk
本寄稿記事では、Perk 社のスタッフ ソフトウェア エンジニアである James Butherway 氏が、CircleCI のビルトインロールバック機能を活用してインシデント復旧を迅速化し、その効果をプラットフォーム チーム ツールキットによって数十ものサービスへとスケールさせた方法についてご紹介します。
お客様のチームでの活用方法を知りたい方は、デモのお問い合わせ、または CircleCI の無料プランをご利用ください。
Perk(旧 TravelPerk)は、出張手配と経費管理を一体化したインテリジェントなプラットフォームです。Foundations 部門に属する当社の DevOps チームは、プラットフォームツールの提供、インフラサポート、運用の卓越性を通じて、部門全体のエンジニアリングチームを支援しています。
私たちは Builders 部門全体の CI/CD 基盤に対して高いオーナーシップを持ち、すべてのチームが日常的に利用する継続的インテグレーションおよびデプロイメントのパイプラインを維持・運用しています。このミッションにおいて、CircleCI とのパートナーシップは重要な役割を果たしており、高度なデプロイワークフローの構築や、本ブログで紹介している集中管理型ロールバック機能のような先進的な仕組みの実装を可能にしています。
Perk の技術スタック
Perk のインフラはマルチクラウド上に構築されており、モダンなクラウドネイティブ・アーキテクチャを採用しています。多くのサービスはコンテナ化されたアプリケーションとして、Amazon Elastic Container Service(ECS)などで稼働しており、プラットフォームのスケーラビリティと信頼性を支えています。
より新しいサービスでは、適材適所でサーバーレス・ファーストのアプローチを採用しています。イベント駆動型ワークロードやマイクロサービスには、AWS Lambda 関数や GCP Cloud Run などを活用しています。さらに、API 管理のための API Gateway や NoSQL データベースとしての DynamoDB をはじめとする各種 AWS/GCP のマネージドサービスを組み合わせることで、インフラ管理ではなく価値提供に集中できる環境を実現しています。
すべての AWS ワークロードは、各リポジトリに分散された CircleCI 設定を用いてビルドおよびデプロイを行っています。どちらのプロジェクト形式においても、インシデント発生時の平均修復時間 (MTTR) を短縮するために、ロールバック機能への対応が必要不可欠でした。
課題:従来のロールバックの仕組み
集中管理型ロールバックを導入する前、Perk のロールバック機能は、2 世代にわたる独自のコマンドライン・インターフェース(CLI)ツールを経て進化してきました。一つは、メンテナンスが停止しているものの古いドキュメントに残っているレガシーな Lambda 用 CLI。もう一つは、エンジニアへの認知度が低く、普及が進んでいない比較的新しい ECS 用 CLI です。
これらのツールが混在していたことで、ロールバック体験は断片化され、インシデント発生時に信頼して使用することが困難な状況にありました。
従来の CLI ツールにおける主な課題は以下の通りです。
- 古くなったドキュメント:包括的なドキュメントが不足しており、すでに廃止されたツールを参照していたため、エンジニアの混乱を招いていました。
- レガシーツールに対する信頼感の低さ:利用頻度が低かったためロールバック実行への心理的ハードルが高く、結果として MTTR が増加。多くのエンジニアはロールバックではなくロールフォワード(修正版の再デプロイ)対応を選択していました。
- 限定的なロールバック機能:旧 CLI では 1 バージョン前への切り戻ししか容易にできず、複数バージョンを遡るような柔軟性に欠けていました。
- 可視性と監査性の欠如:フィードバックが最小限であり、監査ログも不足していたため、インシデント中やその後のロールバックの追跡が困難でした。
- メンテナンスの負担:独自のツールは継続的なメンテナンスを必要とし、スクリプトの形骸化を招きました。その結果、肝心なインシデント発生時にツールが正常に動作しないこともありました。
このような断片化が原因で、エンジニアはインシデント発生時に、通常以下の 2 つの不十分なアプローチをとらざるを得ませんでした。
- パイプライン全体の再実行:テストやビルドの全ステージを含む CI/CD パイプライン全体を最初からトリガーするため、復旧時間が大幅に長引いていました。
- リバートとホットフィックスのマージ(最も一般的):問題のあるデプロイを元に戻すための新しいコード変更を作成し、それをホットフィックスとしてマージする方法です。
私たちの目標は、高プライオリティのインシデントにおいて MTTR を 30 分以下に短縮することでした。この目標を達成するには、ロールバック機能の根本的な再考が必要でした。
私たちは MTTR を、「プラットフォームの不安定化を引き起こしたインシデントの発生から、ユーザーにとって完全に安定した状態に復旧するまでの経過時間」と定義しています。ここで重要なのは、インシデントにはさまざまな深刻度があるという点です。高プライオリティの事象であっても、プラットフォームが完全にダウンすることは稀です。それでもなお、プラットフォーム全体のレジリエンス(回復力)を高めることは Perk にとって極めて重要な目標であり、あらゆる種類のインシデントにおいて復旧時間を短縮することが、本プロジェクトの第一の目的でした。
CircleCI の集中管理型ロールバックの導入による成果
CircleCI のロールバックパイプライン機能とプラットフォーム チーム ツールキットを併せて実装したことで、私たちは大幅な改善を達成しました。
- ロールバック速度の向上:コアアプリにおける P95(第 95 パーセンタイル)の実行時間は、7 分 43 秒から 3 分 48 秒へと短縮されました(48.7 % の削減)。
- MTTR の短縮:新しいロールバック機能を使用したインシデントでは、MTTR は 31 分を記録しました。
- 設定メンテナンスの簡素化:プラットフォーム内の単純なものから複雑なものまで、すべてのロールバック機能は、独自の CLI コマンドに代わって、わずか 4 つの CircleCI コンフィグファイルだけでサポートされるようになりました。
- チーム内での普及:CircleCI API を活用し、80 のアクティブなプロジェクトでロールバック機能を自動的に有効化しました。そのうち 8 つのプロジェクトでは、機能リリースから 2 ヶ月足らずでロールバックの実行に成功しています。
実装の解説:CircleCI を集中管理型のロールバックコントロールプレーンにする
私たちの新しいアプローチでは、CircleCI の 2 つの強力な機能を組み合わせて活用しています。それが、ロールバックパイプライン機能とプラットフォーム チーム ツールキットです。この組み合わせにより、従来の CLI ベースの仕組みが抱えていたすべての制約を解消すると同時に、開発者体験を大きく向上させることができました。
集中管理型の Orb とデプロイメントマーカー
当社のデプロイロジックの多くは、すでにバージョン管理された CircleCI Orb に集約されていました。これを、CircleCI のロールバック機能の前提条件であるデプロイメントマーカーに対応させるための拡張作業は、非常にシンプルかつ小規模な移行プロセスでした。すべてのランナーで利用可能な CircleCI CLI を活用することで、わずか数営業日のうちに、Lambda および ECS サービス全体でデプロイメントマーカーが一貫して追加されるよう対応を完了しました。
CircleCI ロールバックウィザードを使ったテンプレート作成
デプロイメントマーカーの準備が整うと、CircleCI のロールバック UI が利用可能になります。ロールバックが未設定のプロジェクトで「Rollback」ボタンをクリックすると、CircleCI のセットアップ ウィザードが起動し、1 時間足らずでプロセスが完了できます。このウィザードは既存のデプロイ ワークフローを分析し、CircleCI の GitHub 連携を利用して、必要な設定変更を含むフィーチャーブランチを作成し、レビュー用のプルリクエスト(PR)を自動的に作成します。
自動生成された設定は、集中管理型のロールバック用ファイルを作成する上で理想的なテンプレートとなりました。この時点では、実際にサービスをロールバックするコア機能部分は含まれていませんが、一度そのスクリプトを実装してしまえば、この YAML 設定内に組み込むのは非常に簡単でした。
CircleCI のロールバック UI
このロールバックスクリプトをプロジェクトに組み込むことで、最初のサービスにおけるエンドツーエンドのロールバックフローが実現しました。これは従来の CLI ツールからの劇的な進化でした。エンジニアは、コマンドの構文を覚えたりドキュメントをあちこち探し回ったりする代わりに、以下の操作だけで済むようになったのです。
- CircleCI のインターフェース上で「Rollback」ボタンをクリック
- 過去のすべてのデプロイバージョンを視覚的に一覧表示
- ロールバックしたいバージョンを選択
- ワンクリックでロールバックを実行
この直感的なインターフェースにより、CLI ツールの際に直面していた「信頼感の問題」が解消されました。日々のワークフローで CircleCI を利用しているエンジニアにとって、ロールバック機能が既存のツールセットにシームレスに統合されたのは大きなメリットとなりました。
プラットフォーム チーム ツールキットによる導入のスケール化
ロールバック UI によって使いやすさの問題は解決されましたが、依然として課題が残っていました。すべてのチームが手動で設定を更新しなくても、この機能をどうすれば全サービスに迅速に展開できるのかという点です。
その答えが、CircleCI のプラットフォーム チーム ツールキットでした。この機能を使えば、ロールバック設定を集中管理し、組織内の各プロジェクトへ自動で配信できます。さらに CircleCI API と組み合わせることで、次のことが実現しました。
- すべてのサービスで動作する標準化されたロールバック設定の定義
- Lambda および ECS の両方のワークロードにわたる 80 のアクティブなプロジェクトで、ロールバック機能を自動的に有効化
- 各チームが個別にプロジェクトのロールバック設定を手動で行う手間の排除
この集中管理型のアプローチは、ドキュメントやコミュニケーション面での課題も同時に解決しました。エンジニアが自ら CLI ツールを探して設定する手間はなくなり、普段使い慣れた UI から、誰でも自動的にロールバック機能を使えるようになりました。
オーバーライドによる柔軟な設定
「前のバージョンに戻す」というシンプルなユースケースだけでなく、より高度なロールバックワークフローを必要とするチームがあることも、私たちは認識していました。プラットフォーム チーム ツールキットを活用することで、2 段階のロールバック設定を提供できるようになりました。
- 標準ロールバック(集中管理型): サービスにすぐに適用できる、設定不要のシンプルなロールバック。DevOps チームが一元管理し、全プロジェクトに自動的に反映されます。
- 高度なロールバック(プロジェクト固有): Slack 通知やデータベースのマイグレーション、キャッシュのクリアなど、ロールバック前後にカスタムアクションが必要なチームは、コアのロールバック機能を継承しつつ、自プロジェクト内で集中管理型の設定を拡張できます。
この 2 段階アプローチにより、両方のメリットを享受できます。ほとんどのチームには集中管理による一貫性とシンプルさを、高度なユースケースが必要なチームには柔軟性を提供できるのです。コアのロールバックロジックは DevOps が集中管理しつつ、各チームはロールバック機構全体を再実装することなく、ワークフローを自チームのニーズに合わせてカスタマイズできます。
標準ロールバックの設定例
これは、集中管理型の設定リポジトリから抜粋したスクリプトです。このリポジトリは、複数の CircleCI プロジェクト間で共有する予定のコア設定をまとめて管理するために作成しました。
# This workflow performs a rollback of an ECS services task definition to a specified previous version.
version: 2.1
orbs:
common: travelperk/com@4.9.0
jobs:
rollback-component:
executor: common/aws
environment:
COMPONENT_NAME: << pipeline.deploy.component_name >>
NAMESPACE: << pipeline.deploy.namespace >>
ENVIRONMENT_NAME: << pipeline.deploy.environment_name >>
TARGET_VERSION: << pipeline.deploy.target_version >>
steps:
- checkout
- attach_workspace:
at: .
# This step will create a new deploy with PENDING status
# that will show up in the deploys tab in the UI
- run:
name: Plan release of ECS << pipeline.deploy.component_name >> rollback
command: |
circleci run release plan \
--environment-name=${ENVIRONMENT_NAME} \
--namespace=${NAMESPACE} \
--component-name=${COMPONENT_NAME} \
--target-version=${TARGET_VERSION} \
--rollback
- common/aws_login:
default_aws_profile: << pipeline.deploy.environment_name >>
- run:
name: Perform ECS rollback for << pipeline.deploy.component_name >> to version << pipeline.deploy.target_version >> in << pipeline.deploy.environment_name >>
command: |
update_service_task_definition_by_version.py \
--environment=${ENVIRONMENT_NAME} \
--cci-component-name=${COMPONENT_NAME} \
--version=${TARGET_VERSION}
# These last two steps update the PENDING deployment marker
# to SUCCESS or FAILED, based on the outcome of the job.
- run:
name: Update planned release to SUCCESS
command: |
circleci run release update \
--status=SUCCESS
when: on_success
- run:
name: Update planned release to FAILED
command: |
circleci run release update \
--status=FAILED
when: on_fail
# This job handles the cancellation of the rollback deploy marker
# if the rollback job is canceled
cancel-rollback:
docker:
- image: cimg/base:current
steps:
- run:
name: Update planned release to CANCELED
command: |
circleci run release update \
--status=CANCELED
workflows:
rollback:
jobs:
- rollback-component:
context: [aws, github, codeartifact]
- cancel-rollback:
requires:
- rollback-component
- canceled
filters:
branches:
only: main
改善点のまとめ
- 共通インターフェースから「 2 クリック」でロールバックできるシンプルな操作性により、対応速度と自信が向上
- 直前のデプロイバージョンだけでなく、複数のバージョンへのロールバックが可能に
- GitHub のコミット情報を含む、ロールバック対象バージョンのメタデータを明確に表示
- ロールバック操作の説明を記録することで、説明責任とセキュリティのための監査証跡を実現
- 独自 CLI を廃止し、DevOps のコードメンテナンス負荷を削減。 コンフィグファイルへの移行により管理を簡素化
以下のフィードバックは、実際のインシデント対応時に、エンジニアが新しいロールバックワークフローをどのように体験したかを示しています。
「新しいロールバック機能は、いざというときに本当に助かりました!特にインシデント発生時のような状況では、スクリプトの仕組みをまず理解しようとする余裕はありません。CircleCI のシンプルな UI で、ロールバック先のコミットハッシュを入力するだけで対応できたのは、非常に便利でした。」— Perk社 シニアソフトウェアエンジニア
まとめ:現在地と今後の展望
この成果を踏まえ、次のステップとして以下を計画しています。
- フロントエンドプロジェクトへのロールバック対応:現在、ロールバック機能はバックエンドプロジェクトのみに対応していますが、フロントエンドプロジェクトも CircleCI を使用しています。同じパターンをマイクロフロントエンドのロールバックに応用できないか、現在フロントエンドエンジニアと検討を進めています。
- 下位環境へのデプロイにおける設定の共有:ロールバックとデプロイは非常に似たアクションであり、どちらも集中管理型設定との親和性が高いと言えます。下位環境へのデプロイをより簡単にしたいというニーズの高まりを受け、ビルド・テストジョブとは切り離した形で、本番環境前のバージョンをデプロイする新しいパイプラインにも同様のアプローチを適用できればと考えています。
- コアパイプラインの設定オーバーライド:現在、新規プロジェクトを作成する際は、チームが使用する想定のワークフローとジョブを含む設定テンプレートを複製しています。プラットフォーム チーム ツールキットの集中管理とオーバーライド機能を活用することで、設定の重複を減らしつつ、プロジェクトパイプラインの構造をより適切に管理できるようになる可能性があります。複雑なカスタマイズが必要なプロジェクトにも柔軟に対応しながら、イノベーションの余地を残せる点も期待しています。