Dev Study
AWSサービスの内部原理 コース

83. サービスはロードバランサに自分で名乗り出る — ターゲットグループへの動的登録と自己修復の連携

タスクは数分で入れ替わり続けるのに、なぜ利用者はずっと同じURLで届くのか——「名前は安定、実体は流動」を支える動的登録と、二系統の健康判定がどう連携して自己修復になるかを、図で追っていきます。

① 名前は安定、実体は流動

利用者いつも同じ URL / DNS 名を見る
現在の登録先へ振り分け
ロードバランサ入口。名前は変わらない
登録されている実体へ
ターゲットグループ「今どのタスクが生きているか」の登録簿
レジストリ(registry)
タスクA短命・IPは毎回変わる
タスクB増えたり消えたりする
タスクC実体は流動
  • 利用者から見える名前は不変。ターゲットグループの中身(登録されたタスク)だけが時々刻々と入れ替わる。
  • ロードバランサは3種類: ALB=L7(HTTP/HTTPS)、NLB=L4(TCP/UDP)、GWLB=L4で仮想アプライアンス(ファイアウォール・侵入検知/防止・ディープパケット検査)向け。公式はECSサービスにはALBを推奨している。

入口の名前と実体を分離し、間にレジストリを挟むことで、実体がいくら流動しても利用者は同じURLで届き続ける。これはAPI Gateway編で見た「リバースプロキシ=入口と実体の分離」の続編であり、DynamoDB編の「パーティションキーという安定した名前で流動する物理配置を隠す」構図と同じ原理だ。

② スケジューラが登録を代行

サービス定義loadBalancers でターゲットグループを紐づけ
targetGroupArn + containerName + containerPort
タスクのライフサイクルに連動して
スケジューラ制御ループ(前々レッスン)
登録簿へ随時反映
配置→自動登録タスクを配置したらターゲットとして登録
停止→自動解除タスクが止まったら登録解除
登録簿は常に最新ターゲットグループが「今生きているのはこれ」を保ち続ける
  • 紐づけ情報は targetGroupArn(どの登録簿か)+ containerName + containerPort(タスクのどのコンテナのどのポートを登録するか)。
  • ALB/NLBでは1つのサービスに最大5つのターゲットグループを付けられる。
  • 登録・登録解除の実務はECSがサービスリンクロールの権限で行う——公式は「タスクの作成時・停止時にターゲットを登録・登録解除する権限(register and deregister targets with your load balancer when tasks are created and stopped)」と明記している。

登録簿を書き換えるのは配置を握るスケジューラ自身。だから「実体が入れ替わっても登録簿は常に正しい」が自動的に成り立つ——サービスが自分でロードバランサに名乗り出る、の正体はこれだ。

③ マシンでなくタスクを登録

EC2起動タイプ複数タスクがマシンの1つのIPを共有
Fargate / awsvpcタスクごとに専用ENI=自分のIPを持つ
タスクが独立したネットワーク的住所を持つ
instance「マシン+ポート」で登録
ip「タスクのIP」で登録
  • 公式: 「target group を作るときは instance ではなく ip を選ぶ必要がある。awsvpc モードのタスクは EC2 インスタンスではなく elastic network interface に紐づくため」(AWS_Fargate.html)。
  • Fargate では awsvpc ネットワークモードが必須。

タスクが自分のIPを持つからこそ、登録の単位が「マシン」から「タスク」へ下りる。動的登録が細かく効くのは、この住所の独立があってこそだ。

④ 内から測るヘルスチェック

healthCheckタスク定義にコマンドを記述
例: curl -f http://localhost/ || exit 1
終了コードで判定
loopback接続localhost / 127.0.0.1 経由で自分のアプリへ
コンテナの外へは出ない
HEALTHY終了コード 0
UNHEALTHY終了コード 非0
  • 状態は3つ: HEALTHY / UNHEALTHY / UNKNOWN。UNKNOWN=評価中、ヘルスチェック未定義、または状態不明。
  • 調整パラメータは interval(間隔) / timeout(待ち時間) / retries(不健康と見なす前の再試行回数) / startPeriod(起動猶予)。
  • startPeriod の猶予中に一度成功すると、以後の失敗は retries にカウントされる。
  • ヘルスチェックコマンドはコンテナイメージに含めておく必要がある。

コンテナの外へ出ず、自分のループバック経由で自分を測る——だから「アプリのプロセスが応答できているか」をいちばん近い距離で判定できる。

⑤ 悪い状態が優先で合成

判定対象essential(必須)かつヘルスチェックありのコンテナのみ
悪い方優先で合成
コンテナ1HEALTHY
コンテナ2UNHEALTHY
コンテナ3HEALTHY
安全側に倒す
合成規則UNHEALTHY > UNKNOWN > HEALTHY
1つでも不健康なら他が元気でも不健康
タスク全体UNHEALTHY
  • 公式の合成表より。例: (UNHEALTHY, HEALTHY)→UNHEALTHY、(HEALTHY, UNKNOWN)→UNKNOWN、(HEALTHY, HEALTHY)→HEALTHY。
  • エージェントが一時的に切断されても、これは勝手にUNHEALTHYにしない——「最後に聞いた(last heard from)状態」を保持し、切断前がHEALTHYなら再接続まではHEALTHYのまま。
  • エージェント再起動や一時的な不通の間もコンテナを走らせ続けるための設計判断(公式: "This is by design")。

3状態を悪い方優先で合成する規則は、可観測性編のアラームFSM(OK / ALARM / INSUFFICIENT_DATA)と同型だ。そして「切断=不明」を「不健康」と即断せず最後の状態を保持するのは、観測の欠落を故障と混同しないための、同じく可観測性の思想である。

⑥ 検知と修復の分業

内から測るコンテナヘルスチェック(loopback)
外から測るターゲットグループのヘルスチェック(LBがHTTP等で叩く)
Yes → 失敗を無視 / No → 置き換えへ
起動猶予内?healthCheckGracePeriodSeconds の期間内かを確認
新タスク起動 → 動的登録(②)へ戻る
失敗を無視起動の遅いアプリを誤って殺さないための猶予
タスク置き換えスケジューラ(制御ループ)が停止・再起動
ループが閉じる自己修復(self-healing)の完成
  • healthCheckGracePeriodSeconds は「タスクが最初に起動した後、スケジューラが unhealthy な ELB / VPC Lattice / コンテナヘルスチェックを無視する秒数」。指定しなければデフォルト0秒。
  • 最大は 2,147,483,647 秒(約69年、と公式自身が注記)——これは32ビット符号付き整数の最大値、という小ネタ。
  • 置き換えの公式明文: 「サービスのタスクがロードバランサのヘルスチェック基準を満たさなければ、そのタスクは停止され再起動される。このプロセスはサービスが desired count に達するまで続く」。

観測(可観測性編)と制御ループ(本編)が組み合わさって初めて「壊れたら自分で置き換える」自己修復になる。検知と修復を別々の係に分けたこの分業こそ、分散システムにおける自己修復(self-healing)というCS基礎の実装であり、置き換えられた新タスクが再び②の動的登録に戻ることで、ループが閉じる。

公式ドキュメントで詳しく ↗