【re:Invent2022レポート】サーバレスコンテナを使ってより使いやすく、効率的なアプリケーションを構築しよう (CON309)

本記事はre:Invent 2022のセッションである「Build your application easily & efficiently with serverless containers (CON309)」のレポートとなります。

AWSのコンテナサービスであるAWS App Runner、AWS Lambdaコンテナ、AWS Fargateの違いやユースケースについての内容となっており、個人的に面白かったので要約してみます。
# セッション概要
> **Detail**
In this session, explore concurrency and scaling across AWS App Runner, AWS Lambda containers, and AWS Fargate. Consider value and performance differences with a focus on helping you make the best platform decisions for your use case.

**翻訳**
このセッションでは、AWS App Runner、AWS Lambdaコンテナ、AWS Fargateの並行処理とスケーリングについて検討します。このセッションでは、AWS App Runner、AWS Lambdaコンテナ、AWS Fargateの並行処理とスケーリングについて説明し、価値とパフォーマンスの違いについて、ユースケースに最適なプラットフォームの決定を支援します。

[セッション動画はこちら](https://youtu.be/MqPxzWqttJs)

# 内容
まず新規ソフトウェアを苗木、既存のソフトウェアを木に例えて、木に対してジョウロを使っても意味がなく、苗木に対して熊手を使ってしまうと苗木を枯らしてしまう。
つまりソフトウェアを作成する上で、そのソフトウェアに適したツールを使う必要性を説いています。
![スクリーンショット 2022-12-08 15.10.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/8ed4f44d-ca0d-c5dd-5842-dbcda3b367b4.png)


では適切なツールを選定する上で考慮することは何かというと、
「**使いやすさ**」と「**効率性**」
この2つです。

そして、新規ソフトウェア（苗木）にも既存のソフトウェア（木）のどちらにも適したツールとして推奨されるのはコンテナとなります。
![スクリーンショット 2022-12-08 15.10.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/e7b79f2d-8440-449c-6e39-1dd78a0cc0b2.png)


新規プロジェクトでコンテナを使うメリットとして以下が挙げられていました。
- ビルド済みのコンテナイメージを使ってすぐに開発を始められる
- ツールの選定や環境構築に時間をかけなくていい
![スクリーンショット 2022-12-08 15.09.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/34002196-e227-00cf-6e98-76ca9cc3fcce.png)


一方、既存プロジェクトでコンテナを使うメリットとしては、以下が挙げられています。
- 標準化されたフォーマット
- 高額なVMを多く抱える必要がない
- ロールバックが簡単にできるので、デプロイの信頼性と再現性を担保できる
![スクリーンショット 2022-12-08 15.09.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/3e8e1c5a-2671-6254-db5f-b6ebcbc63ebc.png)

続いてアプリケーションの同時実行性と効率性に関するお話です。
![スクリーンショット 2022-12-08 15.08.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/0f1444b1-5b37-bea2-3bda-c60d46b79050.png)

ビルダーはアプリケーションが小規模なときは低い同時実効性、アプリケーションを使用するユーザが増えてきたり、規模が大きくなってきた際は高い同時実効性に対処する必要があります。
![スクリーンショット 2022-12-08 15.08.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/1be2dfe7-30d4-a81f-c3c3-8ab1a4052714.png)

その同時実効性に対処する上で検討されるAWSのサーバレスコンテナのサービスとして以下の3つが挙げられます。
- AWS Lambda
- AWS App Runner
- AWS Fargate
![スクリーンショット 2022-12-08 15.07.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/9ae14491-1898-a82d-0b4f-0da720a5ee68.png)

### AWS Lambda
![スクリーンショット 2022-12-08 15.14.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/02912806-7755-3f6e-7b82-bcaabf5a22cf.png)

AWS Lambda APIやAmazon Event Bridge経由でイベントトリガーでコードを実行できます。
![スクリーンショット 2022-12-08 15.15.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/b163c3da-20de-4407-f761-acd09851d458.png)

Application Load Balancer(ALB)やAmazon API Gateway、Lambda function URLを使えば、Webリクエスト経由でコードを実行できます。
![スクリーンショット 2022-12-08 15.20.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/4128d36a-fa71-1fc2-798a-e7618a31b3e4.png)

関数は毎回個別のマイクロVM上で実行されるので、強力な独立性を持ちます。
![スクリーンショット 2022-12-08 15.28.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/90f951b9-eb8b-393d-a0b5-7806693a9a49.png)

続いてLambdaの関数が呼び出されるまでの流れについて説明となります。
1. 何も実行されていないコールドスタートという状態から始まる
1. マイクロVMを起動
1. コードのダウンロード、zipの解凍、コードの初期化
1. イベントやリクエストに応じてハンドラの関数を複数回実行できるようになる
![スクリーンショット 2022-12-08 15.31.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/52be41a2-a4e9-525f-c7b3-ccbd21397ac1.png)

料金はコードの初期化から関数の実行までにかかった時間（ミリ秒）単位で支払うことになります。
![スクリーンショット 2022-12-08 15.48.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/9c241cbf-ffdd-1e4c-aa71-6fdd7b5957f7.png)

つまり、以下の図のようにLambdaを実行した場合、処理が実行されていない時間には料金は発生しません。
![スクリーンショット 2022-12-08 15.52.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/1a47b61d-b623-efd6-bb4e-60eeee927402.png)

ただし、1つのLambdaが実行中に他のLambdaがリクエストされた場合、2つ目はコールドスタートから始まります。3つ目も同様です。
![スクリーンショット 2022-12-09 14.28.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/6ea646e3-78da-07af-75a0-b22db5468376.png)

### AWS App Runner
![スクリーンショット 2022-12-13 17.08.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/2611d4ab-3468-1bc2-f4c7-701d75376e74.png)

App Runnerはコードの実行からロードバランシング、インターネットからのインバウンドトラフィック制御、スケーリングまで幅広く処理してくれます。
![スクリーンショット 2022-12-13 17.09.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/58be3317-adbc-b059-e3cd-cd10da065e4a.png)

裏側はどうなっているかというと、まずクライアントからリクエストを受け取るエンドポイントが存在します。
そして、エンドポイントはAWSが管理するEnvoy Proxyのロードバランサに送られます。
また、インスタンスに送信される同時リクエストの数をアプリケーションの自動スケーリング設定で制限することもできます。

ここで「Envoyって何？」となりましたが、以下の記事にわかりやすい解説がありました。
https://openstandia.jp/oss_info/envoy/

AWS App Meshにも使われているマイクローサビス向けのオープンソースのソフトウェアとなります。
個人的にはロードバランシングといえばELBというイメージだったため驚きました。
![スクリーンショット 2022-12-13 17.30.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/48777e5b-6f83-5012-b583-5028a0301c3c.png)

インスタンスに送信される同時リクエスト制限の数を超えた場合は、新たなアプリケーションコンテナのコピーが起動され、より多くのリクエストを処理できるようになります。

![スクリーンショット 2022-12-13 18.29.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/4bfa1d7d-c697-ff7d-7c54-693662b11f69.png)

また、コンテナ数を制限し、一定の同時リクエスト数を超えた場合は「too many request (エラーコード429)」をクライアントに返すことも可能です。

この制限をうまく活用することによってAWS App Runnerは状況に応じて大量の容量を追加することが可能となります。
![スクリーンショット 2022-12-13 18.45.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/c2024ae4-7916-b09d-c9dd-117dcbc187e6.png)

AWS App Runnerの料金体系は確保されるCPUとメモリに対して1分単位で課金が発生します。
ただし、リクエストが発生していない時はCPUに対する課金は発生しません。
つまり、Lambdaとの違いは1度プロセスを起動すれば、同じ金額で指定した上限までいくらでもリクエストを捌くことが可能となる点になります。
また、1秒に1回のリクエストでも100回のリクエストでも確保されているCPUとメモリが一緒なら料金は変わらないため、トラフィックが多いほどリクエストあたりのコストが低くなります。

ただし注意点としては、1分ごとに課金対象となってしまうため、10秒単位で些細なリクエストを受けただけでも、100%アクティブな状態と同等のCPUに対する料金が発生してしまいます。

最適なユースケースとして業務時間中だけ稼働するビジネスアプリケーションが挙げられていました。
![スクリーンショット 2022-12-13 19.03.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/855fabb4-1501-a7a4-c5c5-c1fc4a711d16.png)

### AWS Fargate
![スクリーンショット 2022-12-13 19.42.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/291a9af8-aec7-44df-0b16-f0c1f331a8a2.png)

AWS FargateではオンデマンドでマイクロVMを起動します。
過去に発生した問題に対するSSLパッチの適用などはAWSが対応するため、アプリケーションが動くマイクロVMについて、ユーザが考える必要はありません。
つまり、ユーザが考えるのはマイクロVM上で動くコンテナアプリケーションのランタイムやライブラリーなどに対するパッチ適用のみで良いのです。
![スクリーンショット 2022-12-13 20.13.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/dff08fe1-54bb-0f01-ac95-d8458f4dbc95.png)

AWS FargateはAWS App Runnerと異なり、ロードバランサーとアプリケーションで料金が分離されています。
![スクリーンショット 2022-12-13 20.47.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/8b9866ca-dc4e-dd81-4ade-53e9f8267a75.png)

また、スケーリングという観点だと、App RunnerとLambdaにはスケーリングモデルが組み込まれていますが、Fargateには組み込まれていません。
なので、ユーザ自身で時間内で実行したいFargateコンテナの数を選択し、実際に受け取るトラフィック量を処理できるだけのFargateコンテナが実行されていることを確認する必要があります。
![スクリーンショット 2022-12-13 20.51.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/0767f58a-8fa9-7eb1-bb6e-821a9c0d171b.png)

その点を補うためにオーケストラーを使用します。
オーケストラーは例えば「CPUが80%を超えたらアプリケーションのコピーを10個作成してロードバランサに登録してして欲しい」といった要望を叶えることが可能となります。
![スクリーンショット 2022-12-13 20.58.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/21e506ea-ebd4-1d6d-3efc-abad99b464b7.png)

そして、AWSではFargate内のVMコンテナを処理してくれるオーケストレーションAPIとしてAmazon Elastic Container Service(ECS)とAmazon Elastic Kubernetes Service（EKS）があります。

ECSはAWSのフルマネージドサービスです。
オンデマンドで使用できFargateのオーケストレーションを肩代わりしてくれます。
また、支払いはFargateのタスクに対してのみとなります。

一方、EKSはオープンソースのソフトウェアであるKubernetesを実行するためのハードウェアの管理をAWSが肩代わりしてくれます。
支払いはEKSを実行するハードウェアとFargateのタスクの両方で発生します。
![スクリーンショット 2022-12-13 21.04.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/227cefe5-2ae3-f873-66d9-aaef73f24138.png)

さらにFargateではインバウンドトラフィックをどのように受け取るのかについても考慮する必要があります。

Application Load Balancer(ALB)はHTTPやgRPC、WebSocketなどバックエンドにレイヤー7のアプリケーションが存在しているケースに適しています。

Network Load Balancer(NLB)はTCP, UDPといった低レイヤーでコネクション数が少ないロードバランシングをしたいケースに適しています。

Amazon API Gatewayはリクエストがあった際だけ料金が発生します。
ただしデメリットとして、多くのリクエストが発生した場合、ALBやNLBと比較して非常に高額な料金が発生します。
![スクリーンショット 2022-12-13 21.21.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/5160be57-0c94-8c76-6d10-5a4b14d624cd.png)

そしてスケーリングに関して、ECSではAmazon Auto ScalingとAmazon CloudWatchに統合されています。

ステップスケーリングは「CPUが一定の閾値を超えた時にコンテナをいくつ追加して欲しい」といったカスタムなスケーリングルールを定義したい時に使用することができます。

ターゲット追跡では「CPU使用率80%を維持して欲しい」といった定義をすると、AWSで動的に調整してくれます。

スケジューリングポリシーはユーザがトラフィックの多い時間帯、少ない時間帯を理解している場合に有効です。

CloudWatchに関しては、CPUやメモリ、ネットワークIOといったすでに組み込まれているメトリクスもあれば、独自のカスタムメトリクスやアプリケーション固有のメトリクスを見ることも可能です。
![スクリーンショット 2022-12-13 21.41.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/383d9eee-d04b-1c69-bac4-2d03961572bb.png)

FargateがLambdaとApp Runnerと大きく異なる点は料金体系がアクティビティではなく時間に基づいている点にあります。
つまり、トラフィックが0であっても確保されているCPUとメモリに対して料金が発生してしまいます。
![スクリーンショット 2022-12-13 21.55.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/d34c5a67-aeb6-bf58-ad48-f37f25abcb34.png)

ここまでの話から、Fargateのタスク管理が多忙だと思うかもしれません。
しかし、FargateはLambdaと比べるとリクエストあたりの料金が最も低く、同程度のトラフィックであればメリットがあります。

CPUとメモリのサイズを小さくすることで、よりコストを下げることが可能です。
リスクを無視するのであれば、CPUは256vCPU,メモリは512MBまで下げることができます。

アプリケーションを長期間、何年も使うということであれば、Savings Planでコストを事前に支払い、そのコストから一律数パーセントの割引を受けることができます。

また、GravitonとARMベースのインスタンスを使用することでより低コストで使用することが可能となります。
![スクリーンショット 2022-12-13 22.01.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/a838d132-dd01-a46c-ae40-275a1c92a901.png)

### どのサーバレスモデルが自分のアプリケーションに適しているのか
まず価格モデルを並べてみます。

Lambdaはメモリサイズに基づくミリ秒単位の起動に対して課金が発生します。
そして同時に実行されるアプリケーション一つ一つが別々に課金されることになります。
つまり、Lambdaではあるリクエストが届いた後に次のリクエストが届くまでの数秒から吸うミリ秒の間に発生するコストをゼロにすることができます。

App RunnerはCPUとメモリサイズに基づいて、秒単位の課金となります。
トラフィックが無い場合、メモリに対してのみ課金が発生しますが、トラフィックが発生した場合は、CPUに一律で課金し、そのコンテナにどれだけトラフィックが到着したかを計算します。
アプリケーションインスタンスが起動するたびに最低1分間起動し、その期間はリクエストがある度に秒単位で繰り上げられます。

Fargateはトラフィックの有無に関係なく、CPUとメモリに対して秒単位で一定の料金が発生します。


![スクリーンショット 2022-12-13 22.16.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/7f124232-f893-aed9-bb8d-85b0fdb90142.png)

続いてスケーリングモデルについてです。

Lambdaはスケーリングを内蔵しています。
1つのインスタンスで実行できるのは1つのファンクションだけですが、インスタンスの数は非常に早く、確実に増やすことができるため、スパイクに対して迅速に対応できます。

App Runnerはインスタンスを追加すると同時実行可能な容量が一気に増えることになり、応答が遅くなる可能性があります。
ただし、大きな容量の塊を持っているため、急激なスパイクがない限りはトラフィックを維持することができます。

Fargateはスケーリングは一切組み込まれていません。
そのため、ユーザは自身の最適なスケーリングルールを見つけ、ある期間に実行する適切なコンテナ数を決定する必要があります。
しかし、AWS Auto Scalingなどを使うことで負担を減らすことは可能です。
![スクリーンショット 2022-12-13 22.44.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/aa664cc1-e7a7-22d3-8462-ef9110e58055.png)

インバウンドのWEBトラフィックについて

LambdaはLambda function URLという無料で使用できる機能か、リクエスト単位で課金が発生するAPI Gatewayを使用するかを選ぶ必要があります。

AppRunnerにはインバウンドでWEBトラフィックを受け入れる機能が内蔵されているため、この観点で料金を意識する必要がありません。

Fargateには一切内蔵されていないため、API GatewayやALBを使う必要があります。
トラフィックが少ない場合はAPI Gateway,トラフィックが多い場合はALBが適しています。
![スクリーンショット 2022-12-13 23.06.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/cbd49e12-ead4-01b8-4981-22333c7ae40f.png)

使いやすさと効率性を比較したマップが以下になります。
並列処理という観点で強度と安定性という次元を用意します。

強度とは「どの程度同時に実行できるか」を示します。
1度に1つなのか、それとも大量にリクエストがあるのかといった側面です。
もう一方は「トラフィックがどれくらい予測可能か」といった側面となります。

つまり、この図が示すこととしては非常に突発的なトラフィックが発生するアプリケーションに対してはLambda、トラフィックが安定している予測可能なパターンを持つ場合にはFargateが適しています。
App Runnerはその中間に属しており、先ほど記載した日中業務で使用するアプリケーションといった用途に適しています。

Fargateのような独自のスケーリングルールの構築は簡単とは言えませんが、一度に10万件のリクエストを受けるようになれば、スケーリングを理解するために多少の開発労力を費やしても構わないでしょう。
一方で新規アプリケーションにおいてスケーリングやWEBトラフィックからのインバウンドの考慮に関しそれほど時間を費やしたくない場合、Lambdaといった選択肢があります。
![スクリーンショット 2022-12-13 23.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/4285c957-ff70-a474-50e6-2561556abcd1.png)

規制要件や高いセキュリティ要件があるアプリケーションの場合に考慮すべき点についても考えていきます。

Lambdaはリクエストごとに異なるマイクロVMで起動されるため、リクエストごとの独立性があります。
つまり、あるリクエストに悪意のあるコードが含まれていても、他のリクエストには影響を及ぼすことはありません。

しかし、インメモリキャッシュのような特定の最適化手段を用いることができないという欠点もあります。
そういった場合はApp RunnerやFargateを使用することになります。
![スクリーンショット 2022-12-13 23.38.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/85bc1b47-8c6a-92c6-3beb-69dce82ce4bc.png)

簡単に使用することができるかという観点で見ると、Fargateは多くの制御が可能ですが、少し複雑で多くの設定を入れる必要があることです。
一方でLambdaは非常に簡単に設定することができ、AWSで完全に管理されています。
しかし、大量のトラフィックが発生した場合、コストを最適化することができない可能性があります。
![スクリーンショット 2022-12-13 23.49.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2109911/4bfc3459-2fa6-7e9b-7af1-26e3ec69ac05.png)

## おわりに
初めて1時間の英語のセッションを翻訳し読み解いて行きましたが結構大変でした。
でもLambda, App Runner, FargateといったAWSのコンテナサービスの理解はかなり深まったように感じます。

App Runnerに関してはまだ触ったことがないので、どこかのタイミングで触ってみたいと思います。