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

85. コンテナはコンピュータ基礎の見本市である — OSの隔離から分散の制御ループまでの地図

1つのWebアプリが「イメージのビルド」からユーザーに届くまでを1本の縦断図で追い、その各段に本編で学んだCS基礎(隔離・ハッシュ・宣言と実体の分離・制御ループ・最小権限・自己修復・アトミック切り替え)がどう再登場するかを図で確かめていきます。これはコンテナ編の総括であり、このコース全体の答え合わせです。

① ビルドとpush — レイヤーを積み、ハッシュで内容を固定する

Dockerfile手順の宣言(何を積むか)
各レイヤーの中身をハッシュして名前にする
イメージ = レイヤーの積層読み取り専用の層が重なった1枚
起動時に書き込み可能な最上層を1枚かぶせる(copy-on-write)
ECRへpush。タグではなくダイジェストで参照すれば中身が確定する
ECR(レジストリ)イメージの置き場
ダイジェスト sha256:…内容が決まればハッシュが決まる
コンテンツアドレッシング
イミュータブルな成果物同じダイジェスト=どこでも同じ中身
  • ECRはコンテナイメージを保存・管理するレジストリ(公式: Amazon Elastic Container Registry — Store and manage container images)。ECSはECRなどAWSツールとも、Dockerなどサードパーティツールとも統合されている。
  • コンテンツアドレッシング=中身をハッシュした値そのものを名前にする方式。タグ(latest等)は動くポインタだが、sha256ダイジェストは中身が変われば必ず変わるので「その1枚」を一意に固定できる。DynamoDB編で見た『キーをハッシュして置き場所を決める』・S3編のオブジェクトを一意に指す考え方と同じ原理。
  • レイヤーとcopy-on-write=下の層は共有・読み取り専用のまま、変更は最上層に差分として書く。イメージが軽く・再利用が効くのはこのため。これはDocker一般(OSのファイルシステム基礎)の仕組みで、AWS固有の挙動ではない。
  • 根拠: Welcome.html(Amazon Elastic Container Registry: Store and manage container images / integrated with … third-party tools, such as Docker)

イメージは『レイヤーを積み、その中身をハッシュで固定した読み取り専用の成果物』。ビルドの時点でOSのファイルシステム基礎(層とcopy-on-write)とコンテンツアドレッシング(ハッシュ)が同居している。

② 設計図を宣言する — タスク定義

タスク定義アプリの設計図(blueprint)
実体ではなく『こうあるべき』の宣言
宣言から実体を1つ起こす
タスク設計図から起動した実行中の1コピー
設計図 ≠ 実体1枚の設計図から実体は0個にも複数にもなる
  • 公式の定義そのまま:Task definition = 「The blueprint for the application(アプリケーションの設計図)」。Task = 「仕事を実行して停止する、バッチジョブのようなアプリケーション」。サービスのタスクは公式に『タスク定義のインスタンス(instances of a task definition)』と呼ばれる——設計図と実体という語の使い分けが公式ドキュメント自体に埋まっている。
  • 設計図(宣言)と実体(タスク)を分けるのが要点。DynamoDB編・Lambda編でも繰り返し出た『宣言と実体の分離』——望ましい状態を先に紙に書き、システムがそれに合わせて実体を作る。この分離が次段の制御ループを可能にする。
  • タスク定義で `requiresCompatibilities` に `FARGATE` を指定するとFargate向けになる。
  • 根拠: Welcome.html(Features: Task definition = The blueprint for the application / Task = An application such as a batch job that performs work, and then stops)、ecs_services.html(instances of a task definition)、AWS_Fargate.html(requiresCompatibilities=FARGATE)

タスク定義は『こう動かせ』という設計図(宣言)であって、動いている実体ではない。宣言と実体を分けておくことが、次のスケジューラによる自動制御の前提になる。

③ 差分を埋める制御ループ — サービスとdesired count

desired count = 4望ましい状態(あるべき数)
スケジューラが今の実体数(current)と絶えず比較
current = 3実体(いま動いている数)
desired ≠ current の差分を検知
差分ぶんだけ起動/停止して埋める
1タスク起動current 3 → 4
タスクが落ちても、また差分が生まれ
自動で置き換え1つ停止 → スケジューラが新規を起こす
自己修復
current を desired に収束させ続ける一度きりでなく回り続けるループ
  • 公式:「サービスは、指定した数のタスク定義のインスタンスを同時に実行・維持する。タスクが失敗・停止したら、サービススケジューラが別のインスタンスを起動して置き換え、望ましいタスク数を維持する」。
  • 「基盤インフラが故障しても、サービススケジューラがタスクを再スケジュールする」——つまり故障は例外でなく前提として設計されている。
  • これが制御ループ(可観測性編のアラームや、望ましい状態へ収束させる分散の背骨と同じ形):目標(desired)と実測(current)の差を測り、差を埋める操作を打ち、また測る、を繰り返す。宣言的状態+制御ループ=自己修復の正体。
  • 根拠: ecs_services.html(the Amazon ECS service scheduler launches another instance of your task definition to replace it… helps maintain your desired number of tasks / if the underlying infrastructure fails, the service scheduler reschedules a task)

サービスは『何個あるべきか』を宣言するだけ。あとはスケジューラが desired と current の差分を延々と埋め続ける制御ループが、落ちたタスクの置き換え(自己修復)まで自動でやる。命令ではなく状態を宣言するのがコツ。

④ 信頼境界と2枚のロール — Fargateの隔離と最小権限

1タスク = 独立した分離境界カーネル・CPU・メモリ・ENIを他タスクと共有しない
Lambda編で見たFirecracker(microVM)と同じ分離の発想がここに再登場
起動には2種類の権限が要る。役割を分けて渡す
実行ロール(胴元)ECRからイメージをpull・ログ送信など『起動の裏方』
タスクロール(アプリ)アプリのコードがS3やDynamoを呼ぶ権限
権限が2枚に分かれている起こす人の権限と、動くアプリの権限は別物
  • 公式:「各Fargateタスクは自分自身の分離境界(isolation boundary)を持ち、基盤のカーネル・CPUリソース・メモリリソース・ENIを他タスクと共有しない」。だからFargateでは『コンテナワークロードをセキュリティのために自分で隔離する』作業が不要になる。※ECSの公式ドキュメント上の表現は「isolation boundary」で、この実体がFirecracker型のmicroVMだという対応づけはAWSのFirecracker公表(Lambda編で扱った)に基づく。
  • 重要な但し書き:「コンテナはセキュリティ境界ではない(Containers are not a security boundary)」。厳格な隔離が要る場合は公式もFargateを推奨する。対してEC2・ECS Managed Instances・ECS Anywhereでは公式に「タスク間の隔離はなく(no task isolation)、コンテナは同一インスタンス上の他タスクの認証情報にアクセスし得る」と明記されている。
  • 2枚のロール:タスクロールは「コンテナ内で動くアプリケーションのコードが他のAWSサービス(例:S3)を使うためのもの」。実行ロールは「ECSコンテナ/Fargateエージェントがユーザーに代わってAWS APIを呼ぶための権限」で、公式のユースケースはECRプライベートリポジトリからのイメージpullや、awslogsドライバでのCloudWatch Logsへのログ送信。しかも実行ロールの権限は「タスク内のコンテナからは直接アクセスできない」——裏方と表方が権限レベルで遮断されている。認証暗号編で見た1つのロールが、コンテナでは責務ごとに2枚へ分かれる——最小権限の具体化。
  • 根拠: AWS_Fargate.html(Each Fargate task has its own isolation boundary and does not share the underlying kernel, CPU resources, memory resources, or elastic network interface with another task)、task-iam-roles.html(allows your application code (running in the container) to use other AWS services / Containers are not a security boundary / For EC2 … there is no task isolation and containers can potentially access credentials for other tasks)、task_execution_IAM_role.html(grants the Amazon ECS container and Fargate agents permission to make AWS API calls on your behalf / pulls a container image from an Amazon ECR private repository / sends container logs to CloudWatch Logs / they aren't directly accessible by the containers in the task)

Fargateは1タスク=1つの信頼境界で分離を担保し、権限は『起こす人(実行ロール)』と『動くアプリ(タスクロール)』の2枚に割って最小権限にする。Lambda編のmicroVMの発想と認証暗号編のロールが、ここで一度に姿を現す。

⑤ 動的登録と自己修復 — ターゲットグループとヘルスチェック

タスク(ENI=自分のIP)awsvpcモードなのでIP単位で登録(type=ip)
ロードバランサが定期的に健康診断
ヘルスチェック健全なターゲットにだけ振り分ける
API Gateway編のリバースプロキシがここでロードバランサとして再登場
不健全と判定されたら
振り分け対象から外れるトラフィックが来なくなる
スケジューラが置き換え新タスク起動→HEALTHY確認→不健全な方を停止
③のループと同じ自己修復
壊れた実体は自動で外れ、新品が入る健全な状態へ勝手に戻る
  • 公式:「サービススケジューラは、コンテナのヘルスチェックまたはロードバランサのターゲットグループのヘルスチェックが失敗して不健全と判定されたタスクを置き換える」。手順は『まず置き換えを起動→置き換えが HEALTHY なら不健全な方を停止』。maximumPercentの上限で先に起動できない場合は、不健全タスクを1つずつ停止して空きを作ってから置き換えを起動する。
  • Fargate(awsvpc)ではタスクがENIを持つため、ターゲットグループの type は `instance` ではなく `ip` を選ぶ(タスクはEC2インスタンスでなくENIに紐づくから)。
  • 健全か否かで振り分けを切り替えるのは、可観測性編で見た有限状態機械(healthy↔unhealthy)そのもの。healthCheckGracePeriodSeconds(未指定なら既定0秒)は『タスク起動直後の一定時間はELB・VPC Lattice・コンテナヘルスチェックの不健全を無視する』猶予——立ち上がりに時間がかかるアプリを、起動しきる前に不健全と誤判定して止めないための、状態機械の初期状態の扱い。
  • リバースプロキシ(API Gateway編)とロードバランサは『前段で受けて後ろの実体へ配る』同じ骨格。ロードバランサはそれに『健全な実体だけに配る』自己修復を足したもの。
  • 根拠: ecs_services.html(replaces tasks determined to be unhealthy after a container health check or a load balancer target group health check fails / the service scheduler will first start a replacement task / If the maximumPercent parameter limits the scheduler… stop an unhealthy task one at a time… then start a replacement)、AWS_Fargate.html(you must choose ip as the target type, not instance… associated with an elastic network interface, not an Amazon EC2 instance)、service_definition_parameters.html(healthCheckGracePeriodSeconds: ignores unhealthy Elastic Load Balancing, VPC Lattice, and container health checks after a task has first started / default value of 0)

起動したタスクはIPで自動登録され、ヘルスチェックが健全な実体にだけトラフィックを流す。壊れれば外して置き換える——③の制御ループが、ロードバランサ(=自己修復するリバースプロキシ)と組んで自動で健全さを保つ。

⑥ 安全に入れ替える — アトミックな切り替えとデプロイ

新リビジョン設計図②を差し替える
方式A:ローリング更新(min/maxの制約で入れ替え)
min 100% / max 200%常に4本以上を保ち、先に新4本→旧4本停止
既定値(REPLICAサービス)
方式B:Blue/Green(ポインタの切り替え)
旧(Blue)と新(Green)を並置検証してから
トラフィックを一斉に付け替え指す先を切り替えるだけ
アトミック切り替え
ユーザーから見て途切れない更新常に『どちらか健全な方』が応答している
  • 既定のデプロイコントローラは `ECS`。何も指定しなければ `ECS` が使われ、公式にrolling update / blue-green / linear / canary の複数戦略をサポートすると明記されている(linear=等分で段階的に、canary=まず少量→残り全部)。
  • ローリング更新の量はmin/maxで決まる。REPLICAサービスの既定は `minimumHealthyPercent`=100%、`maximumPercent`=200%。公式の例:desiredCount=4・maximumPercent=200%なら『旧4本を止める前に新4本を起動する』。100%を切らせなければ稼働は途切れない。
  • Blue/Greenは2通りある。`ECS`コントローラ内蔵の戦略は公式に「新しい環境を作り、トラフィックを一斉に切り替える(create a new environment and shift traffic all at once)」。別コントローラの`CODE_DEPLOY`はCodeDeploy駆動のblue/greenで「本番トラフィックを流す前に新デプロイを検証できる」。どちらも要点は同じ——イミュータブルな成果物(①)だから、旧を書き換えず新を丸ごと立てて“指す先”だけ切り替えられる。これがアトミック切り替えで、半端な状態を外から観測させない。
  • 『新しいバージョンを、旧を壊さず横に立てて、ポインタで一気に切り替える』はDynamoDB編の追記ログ+切り替えや、S3のイミュータブルなオブジェクトと同じ発想。可変を避けるほど切り替えは安全になる。
  • 根拠: service_definition_parameters.html(If no deployment controller is specified, the ECS controller is used / The Amazon ECS deployment controller supports multiple deployment strategies: rolling update, blue/green, linear, and canary / Blue/green deployments create a new environment and shift traffic all at once / minimumHealthyPercent default 100% for replica / maximumPercent default 200% for REPLICA / desiredCount of four tasks and a maximumPercent value of 200%, the scheduler starts four new tasks before stopping the four older tasks / CODE_DEPLOY: allows you to verify a new deployment of a service before sending production traffic to it)

更新は『壊しながら直す』のではなく『新品を横に立てて指す先を切り替える』。ローリングはmin/maxの制約で常に健全な本数を保ち、Blue/Greenはポインタのアトミック切り替えで一気に移す。イミュータブルな成果物だからこそ安全に入れ替えられる。

⑦ 地図の答え合わせ — 新サービスは、もう知っている基礎の組み合わせ

レイヤーFS+copy-on-writeOSのファイルシステム → ①イメージ
コンテンツアドレッシングハッシュ → ①ECRのダイジェスト
宣言と実体の分離→ ②タスク定義とタスク
制御ループ+自己修復→ ③スケジューラ ⑤ヘルスチェック
microVMの信頼境界Lambda編のFirecracker → ④Fargate
最小権限(ロール)認証暗号編の1枚 → ④2枚に分割
リバースプロキシ→LBAPI Gateway編 → ⑤ロードバランサ
状態機械/イミュータブル可観測性編のFSM ⑤ / 追記ログ ⑥
同じ背骨は次(EKS)でも変わらない
宣言的状態 + 制御ループKubernetes(EKS)へ進んでも背骨は同じ
望ましい状態を宣言し、差分を埋め続ける
  • この1本で通った縦断:①ビルド(レイヤー+copy-on-write)→ECR push(ダイジェスト)→②タスク定義(設計図)→③スケジューラが差分を埋める(制御ループ)→④Fargate=1タスク1分離境界(信頼境界)+2枚のロール(最小権限)→⑤ターゲットグループ登録・ヘルスチェック(自己修復)→⑥min/max入れ替え or Blue/Greenのポインタ切り替え(アトミック更新)。
  • コンテナが『卒業制作』なのは、OS基礎(プロセス隔離・ファイルシステム)と分散基礎(制御ループ・自己修復・デプロイ)が1つのサービスの中で層をなして同居しているから。新しいサービスの中身は、もう知っている基礎の組み合わせだった。
  • 次への一言:EKS(Kubernetes)に進んでも『宣言的状態+制御ループ』という背骨は同じ。desired と current の差分を埋め続ける、という一点さえ掴めば、名前が変わっても迷わない。
  • 根拠: 本編各編との接続(Lambda編Firecracker=AWS_Fargate.htmlの分離境界 / 認証暗号編ロール=task-iam-roles.html・task_execution_IAM_role.htmlの2枚 / API Gateway編リバースプロキシ=ecs_services.htmlのload balancing / ③⑥=ecs_services.html・service_definition_parameters.html)

コンテナは『マネージドサービスの中身はコンピュータの基礎でできている』が最も濃く出る領域。OSの隔離から分散の制御ループまでが1本のアプリの旅程に層をなして並ぶ。この背骨(宣言的状態+制御ループ)はEKSでも変わらない——だから次も、もう知っている基礎の組み合わせとして読める。

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