高可用性システムにおけるBlue/Greenデプロイメント実装 - 医療システム統合基盤での取り組み

こんにちは。医療プラットフォーム本部の日下(@mkusaka)です。 私の所属する統合基盤チームでは、医療プラットフォームの複数のシステムを支えるサービス群を運用しています。

これまではユーザーへの影響を最小限に抑えるため、リリース作業を深夜や早朝に限定していましたが、その結果として運用チームへの負担増やリリースタイミングの制約といった課題が生じていました。

こうした課題を解決し、日中でも安全かつ段階的にリリースを行うため、統合基盤に Blue/Green デプロイメントを導入しました。今回はその詳細を紹介します。

統合基盤コンポーネントの紹介

統合基盤チームでは、患者と医療機関の双方に使われる医療システムの根幹を支える重要な基盤の開発・運用を行っています。 管理するコンポーネントは、「医療機関向け」と「患者向け」の 2 つに分類できます。

「医療機関向け」機能は、PharmsDentisCLINICS などの各サービス間でコミュニケーションのハブとして機能し、イベントの配信を行います。

一方、「患者向け」機能としては、総合医療アプリ CLINICSから送られたリクエストを適切なサービスに振り分けるゲートウェイの役割を担っています。

このようなアーキテクチャを採用した背景には、医療プラットフォームが複数のプロダクト(Pharms、Dentis、CLINICS など)を統合的に運用する必要があるという背景があります。

医療機関向けには、いずれか一方のシステムの状態に他方が引きずられない構成とすることで、各医療機関の業務システムの可用性を最大限高めるという狙いがあります。

一方、患者向けには、複数の医療機関向けシステムに対して共通のアプリからアクセスできるようにするため、患者情報の一元管理や統一された認証基盤の整備が不可欠です。これにより、患者にとってシームレスな体験を実現し、より効率的で質の高い医療サービスの提供を目指しています。

つまり、統合基盤が管理するこれらのコンポーネントに障害が発生すると、サービス間にまたがる業務だけでなく、患者向けのサービス提供にも影響が及ぶため、高い可用性が求められています。

Blue/Green デプロイメント導入の目的

統合基盤の各サービスは、AWS ECS(Elastic Container Service)上で運用されています。これまでは、運用のシンプルさからローリングデプロイを採用していました。しかしこの手法では、デプロイが開始されると新バージョンが一斉に展開されてしまうため、問題発生時の影響範囲が広く、迅速なロールバックも難しいという課題がありました。

こうした課題への対策として、Blue/Green デプロイメントを導入することを決定しました。 Blue/Green デプロイメントとは、新旧 2 つの環境(Blue と Green)を用意し、新バージョンを片方に展開した後、徐々にトラフィックを移行していく方法です。これにより、致命的な問題やパフォーマンスの劣化を早期に発見し、迅速なロールバックが可能になります。

Blue/Green デプロイメントの要件と独自実装の選択

システムを Blue/Green デプロイする際に、大きく分けて 2 つの考慮事項がありました。 1 つ目は 2 つの明確な検証フェーズを設けることです。

  • 致命的なエラー検出フェーズ:新環境に約 10%のトラフィックを流し、システムの安定性を確認。
  • 負荷時のパフォーマンス検証フェーズ:新環境に約 50%のトラフィックを流し、負荷によるパフォーマンスの劣化を確認。

これら 2 つのフェーズを明確に設け、十分な検証時間を取ることで、より高い自信をもってリリース作業を進めることが可能になると考えました。

2 つ目は非同期処理を担当する Worker サービスを新旧の環境それぞれで用意することです。 Worker サービスでは、ジョブが SQS(Simple Queue Service)キューに投入されてから実際に処理されるまでタイムラグがあります。その間に新しい環境へ切り替えが行われると、旧環境のジョブが新環境の Worker によって処理され、データの不整合が起きる可能性があります。このリスクを防ぐため、Blue と Green の環境それぞれに独立した SQS キューを用意し、それぞれのジョブが確実に自環境の Worker で処理を完了する形式を取ることとしました。

ECS には CodeDeploy を利用した標準的な Blue/Green の段階的デプロイ戦略として、Canary デプロイ(一部のトラフィックで検証後、一気に切り替え)や Linear デプロイ(一定割合ずつ徐々に適用)が提供されています。しかし、私たちが求めるようなトラフィック調整にはこれらの手法が十分に適しておらず、また SQS を分離するための Blue 環境/Green 環境どちらかを判定するような仕組みが整備されていないようだったので、内製化することとしました。

採用した構成

自前の Blue/Green デプロイを実現するため、以下の構成を採用しました。

  1. ALB(Application Load Balancer)の weighted target groups を利用して、トラフィックを柔軟に調整しています。
  2. ECS 環境は Blue/Green のそれぞれが並行稼働し、SQS は各環境ごとに独立したキューを設けます。

新バージョンは Green 環境として起動し、初期状態では Blue 環境(現行バージョン)がすべてのトラフィックを処理します。その後、Green 環境へのトラフィックを 10%、50%と段階的に増やしながら、各段階でメトリクスの監視を行います。 10%の段階で致命的なエラーがないことを確認し、50%の段階で負荷時のパフォーマンスに問題ないと判断されたら、最終的にすべてのトラフィックを Green 環境へ切り替えます(100%)。

また、各種ステップは承認操作やロールバックも含めて CI 上で完結するように整備を行うことで、デプロイの複雑性も抑えています。

実装サンプル

Terraform と AWS CLI を組み合わせて実装しています。

ALB の weighted routing 設定(Terraform)

resource "aws_lb_listener_rule" "weighted_routing" {
  listener_arn = aws_lb_listener.https.arn

  action {
    type = "forward"
    forward {
      target_group {
        arn    = aws_lb_target_group.app_blue.arn
        weight = 100  # 初期状態では Blue が 100%
      }
      target_group {
        arn    = aws_lb_target_group.app_green.arn
        weight = 0    # Green は 0%
      }
    }
  }

  # AWS CLI で weight を動的に調整するため、Terraform での変更を無視
  lifecycle {
    ignore_changes = [action]
  }
}

トラフィック配分の変更(AWS CLI)

デプロイ時のトラフィック配分は、AWS CLI を使用して動的に変更します。実際の運用では、Green の weight を指定すると Blue が自動的に 100 - Green になるように調整しています:

# Green の weight を指定して Blue/Green の配分を設定
# 例:GREEN_WEIGHT=10 の場合、Blue=90、Green=10 に自動計算
set-weight:
	@aws elbv2 modify-rule \
	  --rule-arn $(LISTENER_RULE_ARN) \
	  --actions '[{
	    "Type": "forward",
	    "ForwardConfig": {
	      "TargetGroups": [
	        {
	          "TargetGroupArn": "$(BLUE_TG_ARN)",
	          "Weight": '$$((100 - $(GREEN_WEIGHT)))'
	        },
	        {
	          "TargetGroupArn": "$(GREEN_TG_ARN)",
	          "Weight": '$(GREEN_WEIGHT)'
	        }
	      ]
	    }
	  }]'

デプロイフロー

実際のデプロイでは、以下のような手順で段階的にトラフィックを移行します:

# 1. Green 環境へのデプロイ
make app-green.deploy TAG=$(NEW_VERSION)

# 2. トラフィックを段階的に移行
make set-weight GREEN_WEIGHT=10   # 10% を Green へ
make set-weight GREEN_WEIGHT=50   # 50% を Green へ
make set-weight GREEN_WEIGHT=100  # 100% を Green へ(切り替え完了)

# 3. 問題が発生した場合のロールバック
make set-weight GREEN_WEIGHT=0    # すべてのトラフィックを Blue へ戻す

この実装により、段階的なリリースと問題発生時の迅速なロールバックが可能になっています。

導入後の効果

Blue/Green デプロイメント導入後、深夜のリリース作業がなくなり、運用チームの負担が大幅に軽減されました。また日中であってもリスクを最小限に抑えたリリースが実現でき、問題が発生した場合にも迅速にロールバックできるようになったため、システムの安定性を犠牲にすることなくリリースを行えるようになりました。

まとめ

今回は、医療システム統合基盤における Blue/Green デプロイメントの導入事例を紹介しました。

医療システムには高い可用性が求められる中、従来のローリングデプロイでは段階的なリリースや迅速なロールバックが困難で、深夜作業が必須となっていました。

Blue/Green デプロイメントの導入により、以下を実現しました:

  • ALB の weighted target groups を活用した段階的トラフィック移行(10%→50%→100%)により品質を確認しながらのリリース進行
  • Worker サービス用の SQS キューを環境ごとに分離し、データ不整合を防止
  • 深夜作業を廃止し、日中でも安全にリリース作業を実施可能に

今後も医療システムに求められる高可用性を維持しながら、開発効率の向上を目指し、継続的な改善を進めていきます。

We’re hiring

統合基盤チームでは、医療システムの根幹を支える重要な基盤の開発・運用を行っています。

今回紹介したような Blue/Green デプロイメントの実装をはじめ、高可用性が求められるシステムにおいて、技術的な課題に向き合いながら医療現場と患者体験の向上に貢献できる環境があります。

医療の未来をエンジニアリングで支えることに興味がある方のご応募をお待ちしています。