[セッション] AWS Fargate Under the Hood CON423 #reinvent
FargateのアーキテクチャをRunTask APIを中心に深掘りしていくセッションです.
すでに動画も出ていますので, 合わせてご確認ください.
Goal of AWS Fargate
- Fargateのゴールはシンプルである
- コンテナ化されたアプリケーションをAWSの仮想マシン上でプロビジョニングやスケール, 管理をすることなく実行すること
- "Container Native Experience" をAWSで完全に実現すること
- Faragteでの "Container Native Experience" とは何かの振り返り
-
タスク定義を定義する
タスク定義自体が1単位であり, 1つの仮想マシンにデプロイされる
複数タスクの定義も可能 -
クラスタを作成する
クラスタはEC2インスタンスを束ねるというよりは, アプリケーションをグループ化させる用途に使用するものである -
タスク定義とクラスタを使用して, RunTask APIをコールする
Fargateを使用しているのでEC2インスタンスは作成されずにコンテナ化されたアプリケーションが実行される
Fargate Design Tenets
Secyruty
- コンテナ基盤となるインフラのセキュリティが最も重要な部分である
- Fargateのアーキテクチャで良いデザインができたとしても, セキュリティに少しでも妥協があった場合はそのデザインは採用されない
- タスクよりしたにあるハードウェアやソフトウェアに対してパッチを当てることで最新の状態を保ち, ネットワークやクレデンシャルに対する不正アクセスが発生しないようにしている
Availabillity & Scalability
- Fargateはタスクが常に起動し続けるようにしている
- アプリケーションの需要に基づいた新規タスクの作成や削除といった, スケーリングに関しても信頼性を保てる様に努めている
Operational Efficiency
- Fargateのように1週の間に何千万も起動するサービスの裏に, タスク起動のために膨大な量のサーバが起動されている
- 使用されていないリソースを特定して削除することでリソース使用率の改善をすることが重要になる
- リソース使用率の改善はAWS利用料金の削減にもつながることであり, 実際にFargateは過去に料金を下げている
- Savings Planも同様にコスト節約に役立つ
Fargate Architecture
- Fargateのアーキテクチャは大まかにコントロールプレーンとデータプレーンに分かれている
- コントロールプレーンはFargateのビジネスロジックを担当するサービス
- データプレーンはコンテナを実行する膨大なサービス群のこと
- RunTask APIはFargateにおける全ての魔法のようなものが詰まっている部分
Fargate Data Plane
- ここから話すデータプレーンはFIrecrackerを導入する前の話である
- Fargateの実態はEC2インスタンスであり, データプレーンのサーバ群として利用されている
- Fargate用のVPCにあるためユーザアカウントからはみることができいない
- Amazon Linux2をOSとするEC2インスタンスを使用している
- EC2の責任範囲より上で, コンテナランタイムまでがFargateの責任範囲でありパッチを当てたりしてメンテナンスを行っている
- コンテナランタイムより上はユーザの責任範囲となる
- RunTaskを実行する都度EC2インスタンスを起動すると時間がかかるため, 起動しているインスタンスを常に確保している
- RunTaskが実行された際にEC2インスタンスを選択してそこでタスクを起動する
- EC2インスタンスで動いているのでネットワークはVPCとENIが使用されている
- メインのENI (Fargate ENI) はFargate用のVPC上でEC2インスタンスにアタッチされていいる
- Fargate Agentとコントロールプレーン, EC2インスタンスとのやりとりはFargate ENIで行われる
- ユーザアカウントでネットワーク機能を利用すると, ENIがユーザアカウントのVPCに作成され, EC2インスタンスにアタッチされる
- ユーザのアプリケーションで発生するネットワークトラフィック, Dockerイメージのプルやログの送信はなどは全てユーザアカウントのENIを経由する
Fargate Control Plane
- 複数の異なるサービスからなる, マイクロサービスアーキテクチャで構築されている
Frontend Service
- パブリックエンドポイントとしてユーザからのリクエストを受け付ける
- IAMでの認証など, APIとして一般的なサービス保護を行う
Custom Manager Sub System
- クラスタとタスクを追跡する
- データプレーンと通信をする
Capacity Manager Sub System
- 使用できるインスタンスとできないインスタンスを追跡する
- RunTask APIを実行した時に, どのインスタンスを使用するかをタスクの要求に基づいて選択する
RunTask: One Level Deeper
- クライアントのRunTaskリクエストがコントロールプレーンのフロントエンドに到達する
- クラスタマネージャにリクエストを渡し, タスクの状態を記録するDBにpending状態のタスクをレコードとして追加する
- クラスタマネージャが, キャパシティマネージャにタスク実行に必要なリソースを渡しキャパシティマネージャは使用するインスタンスを決定, 状態記録用のDBにレコードを追加して, レスポンスを返す
- クラスタマネージャは, キャパシティマネージャからのレスポンスであるキャパシティIDを受け取り, DBに追記する
- フロントエンドを通じてユーザに対してペンディング状態のタスクを返す
- 非同期的にキャパシティマネージャは, Fargateサービスで使用するENIを通じてFargateエージェントをアクティベートする
- Fargateエージェントがアクティベートされたのちにクラスタマネージャはタスク定義を渡して実行するように命令する
- Fargateエージェントが必要なDockerコマンドを実行して, コンテナを起動してタスクの状態(Running)をクラスタマネージャに返す
- コントロールプレーンはDBにあるタスク状態を書き換える
EKS on Fargate
- ECS on FargateでRunTaskが実行されたときは, AWSのAPIのみを使用していた
- EKS on Fargateの場合はKubernetes API経由でPodをFargate上で起動する
- Kubernetes APIにPod作成のリクエストを渡す
-
EKS Clusterに新規追加されたWebhookにより, EKS Fargate Profileの内容をもとにルールを評価して, 自動的にPod作成に使用するKubernetesスケジューラの名前を決定する
EKS Fargate ProfileにはユーザアカウントのEC2または, Fargate上でPodを起動するかを決定する条件となるnamespaceやlabelが記載されている 既存のPodに影響を与えずに動的にFargateかEC2にPodを起動するための方法である - Kubernetesスケジューラがデフォルトの場合はユーザアカウントのEC2上に起動され, そうでない場合, Fargate schedulerが使用される場合はFargate上にPodが作成される
Availability
- リージョン障害への対策
- Fargateのアーキテクチャはリージョン単位で独立して動作するようにして, 別リージョンの障害に相関して影響を受けないようにしている
- データプレーンからコントロールプレーンまでのスタックを各リージョンで実行している
- リージョンで障害が起きたとしても, 別リージョンのスタックは影響を受けない
- ソフトウェアの変更をデプロイをする時には1つのリージョンにのみデプロイして問題があれば切り戻して, 問題がなければ別のリージョンにもデプロイすることを繰り返している
- AZ障害への対策
- フロントエンドはパブリックAPIエンドポイントをホストして, リクエストを受け付ける場所であるためリージョナルサービスであるためAZレベルに分割できない
- クラスタマネージャはECSクラスタを管理する場所であり, リージョナルサービスであるためAZレベルまで分割できない
- フロントエンドとクラスタマネージャは論理的にはリージョナルサービスではあるが物理的には複数AZにまたがって展開している
- Fargate VPCで稼働するEC2インスタンスは, ENIやEBS含めてAZサービスである
- キャパシティマネージャもEC2インスタンスと協調して動作するためAZサービスである
- 全てのリージョンに対してキャパシティマネージャとFargate VPCを作成することでAZ障害への対策をしている
Scaling withn a zone
- 1つのゾーンにどれだけのタスクが実行されるかはAWS側で制御できないので, どれだけのEC2インスタンスが1つのVPCで実行されるは予測できない
- そのため1つのVPCではEC2インスタンスを実行するのに十分スケールできるとは言えない
- なのでVPCを小さな固定サイズの複数のVPCに分割した
- 使用できるVPCが全て埋まったらスケールアウトしてVPCを増やすようにしている
- これは "cellular architecture" から発想を得ている
- 副次的なメリットとして, 分割したVPCで障害が起きたとしても影響を最小限にできる可能性がある
Scalability
- Firecrackerがスケーラビリティを助けている
- Firecrackerを使用しない場合, 1つのEC2インスタンスに対して1つのTaskしか起動できない
- 数千万ものタスクが1週間で起動されるため, その数だけEC2インスタンスの起動が必要になる
- 仮想マシンは何度も起動しては破棄するという使い方のために設計されていないい
- EC2ベアメタルインスタンスを利用することで, Firecrackerを利用してタスクをMicroVMで実行すると, 1つのインスタンスに複数のタスクが配置できる
- インスタンスキャパシティの枯渇が発生した場合にインスタンスを追加すればよいのでリソース効率がかなり良くなる
Task Security & Isolation
- AWSにおいてセキュリティは最も重要度が高い
- ECS TaskはEC2上で実行されているため, 仮想化基盤以下の部分はセキュリティが担保されている
- OS上にFargate AgentとContainer Runtimeが実行されている
- コンテナとの分離境界は CgroupsやNamespaces, seccompといった概念から構成されるが, AWSはマルチテナントにおいては十分なセキュリティを満たす要素としていない
- そのためFargateは1つのEC2インスタンスに複数のタスクを, たとえ同じユーザのタスクであったとしても配置することはない
- ECSタスクが完了すると, EC2インスタンスは破棄され2度と使われなくなる
- この方法でタスクレベルでの分離を実行している
- コンテナとOS間の通信は可能であり, セキュリティをいかに保っているか
- コンテナからFargate Agent, Contaier Runtimeにアクセスできる
- 実際にアクセスは可能だが, OS上にあるのは実行中のタスク以外の状態はないので, 攻撃者に取って無益である
- Fargate ENIから外部へのアクセス
- 別EC2インスタンスへのアクセスはセキュリティグループで制御している
- VPC Flow Logsを有効にすることで疑わしいトラフィックがないことの確認もしている
- Fargate Agentとコントロールプレーンの通信
- Fargate Agent自体がコントロールプレーンに対してできる操作はローカルのタスク情報の取得のみとなっている
- そのため, Fargate Agentから攻撃を仕掛けることはできない
- コンテナからFargate Agent, Contaier Runtimeにアクセスできる
- そのためFargateは1つのEC2インスタンスに複数のタスクを, たとえ同じユーザのタスクであったとしても配置することはない
Firecracker based data plane
- Firecrackerはセキュリティのみならず, 起動時間や1つのEC2インスタンスに複数のタスク配置をすることによるリソース効率の向上を実現する
- EC2ベアメタルインスタンス上にAmazon Linux2を起動し, Fargate Agent, containerd, firecracker-containerd, Firecrackerを実行する
- firecracker-containerdがコンテナをMicroVMとして実行できる様にしてくれる
- この上でMicroVMが起動して, ゲストOSの上にタスクが実行される
- ゲストOSはタスク専用で共有されない
- FargateチームはEC2より上でゲストOSまで責任を持つ
How Firecracker helps isolation
- Firecrackerはハードウェアの仮想化をするため, ゲストOSとFirecracker VMMの間に信頼できる境界を設けることができる
- そのため他のゲストOSとの分離のみならず, ベアメタルインスタンスとの分離も実現する
- コンテナとゲストOSについては通信ができ考慮点となる
- EC2ベースのデータプレーンの時と違い, ゲストOS以下にアクセスすることができない
- なのでFargate AgentやENIに対するアクセスはできない
Operational Efficiency
- Fargateはだいたい50種類のCPUとメモリ設定をタスクのために持っている
- EC2ベースのデータプレーンでは, 様々なインスタンスタイプを確保しておく必要がある
- タスク設定に合わせてちょうど良いインスタンスを使用するために必要である
- ちょうど良いインスタンスがない場合には大きなインスタンスを使用する必要があり, キャパシティ効率が非常に悪い
- また様々なインスタンスを一定数動かし続ける必要があることも, キャパシティ効率に響いている
- Firecrackerはこの問題を大幅に改善している
- MicroVMは起動が速いため, RunTask APIがコールされてから起動することが可能
- MicroVMへのリソース設定が柔軟にでき, CPUとメモリ割り当てを自由に行える
- タスク定義に書かれた内容をもとにその時きっかりとリソースを割り当てて作れるため, "Right Sizing" と呼んでいる