AWS Fargateについて

清水崇之氏(以下、清水):2つ目の相談にも進みたいなと思います。2つ目に「AWS Fargateの運用とコスト最適化について」というお話をいただいています。

新しいサービスとしてAWS Fargateというものが出てきたので、こちらもAWSのSAから簡単に紹介したいなと思います。

下川賢介氏(以下、下川):AWSの中でコンテナを扱えるサービスが何個かあるんですが、その1つが「Amazon ECS」という、コンテナオーケストレーションできるようなサービスになってきます。コンテナの実行環境ですね。

このECSには2つのタイプがあって、on EC2で動くECSと、on Fargateで動くECSがあります。それぞれ何が違うかというと、AWSで管理してくれる領域が違います。(スライドを示して)青色で書かれているところがお客さまが管理するレイヤーで、黄色で表されているところがAWSがマネージドで管理してくれるところになります。

これを見ると、on EC2だと、例えばホストOSの管理とかコンテナエージェントの設定みたいなところです。低レイヤーの設定はお客さまのほうでやらないといけないのですが、Fargateはマネージドの部分が大きくて、ビジネス価値を生まないところはFargateがやってくれて、アプリケーションコンテナの管理だけお客さまがやる。そういった、抽象化されたコンテナ管理の提供がFargateになります。

代表的な意味づけとしては、AWSのマネージドなコンテナ実行基盤というところです。インスタンスのプロビジョンとか、スケールとかの管理は不要になってきます。コンテナはネイティブ環境を提供しています。仮想マシンを意識しないような管理運用ができます。

AWSサービスとの連携ですが、もちろんVPCネットワーキングなどと連携できたり、あとはロードバランサーの設定ができたり。そういったAWSのネイティブなサービスとの連携も非常に便利に整っているのがFargateになります。

清水:ありがとうございます。

AWS Fargate導入後の管理システムのアーキテクチャ

清水:では、実際いただいている相談にいきたいかなと思うのですが、TECH PLAYさん、説明をお願いできますか?

鈴木康広氏(以下、鈴木):ありがとうございます。TECH PLAYでは、開発にDockerを使用しています。今紹介いただいたようなFargateの特性もあり、私たちもあんまり大人数でやっている開発チームではないため、エンジニアができるだけインフラの管理とか運用からは離れて、開発、コードを書くとかの業務に専念して、価値提供のスピードを向上させることを実現したいなと思い、最近AWS Fargateを青山さん主導で導入したというのが現在の背景になっています。

現在どういうアーキテクチャでやっているかについて、じゃあここは青山さん、説明してもらっていいですか?

青山稜河氏(以下、青山):(スライドを示して)今のアーキテクチャが右の図に書いてあります。TECH PLAYの管理システムのアーキテクチャになっています。今回はFargateの運用とコスト効率化が主体なので、Fargateを活用しているところを抜粋しています。実際は監視とか、あと冗長化の構成とかを取っています。

アーキテクチャについてですが、Fargateを2体稼働していて、それぞれフロントエンドとAPIのバックエンドをやっていて。こちらは完全に分離させています。フロントエンドはReactとNext.js、バックエンドのAPIはPHPで動いています。

このアーキテクチャを踏まえて相談ですが、2つあります。1個が提供サービスの増加やバックエンドとフロントエンドの切り離しを行う中で、使うFargateの台数がどんどん増えていく見込みです。これらのFargateをコスト効率良く運用するにはどんな方法があるのかが1つ。

もう1つが、コストの効率化の1つの方法としてFargate Spotを検討しているのですが、このFargate Spotは、リソースの割り当てが行われずに一時停止してしまうケースはどれぐらい発生するものなのか。一時停止しにくいアーキテクチャはあるのかがお聞きしたい内容です。こちらはいかがでしょうか?

Fargateをコスト効率良く運用する方法

下川:ありがとうございます。1つ目の質問ですが、今、コスト効率の話が出てきたかなと思っていて。Fargate自体はスケーラブルな機能を持っています。例えばリクエストが来たら自動的にスケールしたりとか、そういった機能を持っています。

例えばTECH PLAYさんの中でコスト効率が悪いと思っているポイントがあれば、そのあたりも聞きたいな思うのですが、どのあたりを「コストが高そうだな」と感じているんですか?

青山:(スライドを示して)まず、こちらが検証環境の部分です。検証環境って、夜中とか朝方とかはあまり使わないんですよね。なので、そこをずっと稼働し続けるのは少しもったいないなと感じていて。そこをなにか改善できる方法はないですか?

下川:なるほど。検証環境をずっと立ち上げっぱなしだと、リクエストも来ないのにお金がかかっている状態ということですかね?

青山:そうです。

下川:なるほど、わかりました。例えば、検証環境でコスト配分をマネジメントコンソールとかから見てもらって、本当にFargateがコストの支配的なものなのか、それとも裏側にある、例えばRDS(Amazon Relational Database Service)とかを立ち上げっぱなしにしていることがコスト的に支配的なのかを見てもらって。

例えば、RDSが支配的なのであれば時間とともに停止させておくとか、1つの開発が終わったら開発環境のRDSは停止しておくとか。そういった運用も1つあるのかなと思います。

Fargateに関して言うと、今回アーキテクチャとしてはコンテナオーケストレーションでECS Fargateを使っているわけですが、本当に0まで落としたい場合、リクエストが来ない時はスケールを0まで落としたい場合は、例えば先ほど出てきたようなAWS Lambdaみたいなサービスを使ってもらうとか、そういったことも今後のビジネス展開ではあり得るのかなと思いました。

青山:ありがとうございます。あとはスケーリングの設定(の話)になるんですが、ターゲットの追跡方法みたいなスケーリングの方法だったり、いろいろあるんですけれども、それぞれを活用したらいいのかがいまいちはっきりしてなくて。ここってどうしたらいいですか?

下川:今回の場合、今はWebシステム、Webアプリケーションとして利用されているのかなと思うので。例えば「非同期のアーキテクチャです」「SQSの裏側でECSを使います」とかだと、SQSのメッセージのキューの長さによってスケールさせるなどの組み方はあるのですが、基本的には同期的なAPIとして公開しているようなサービスだと、リクエスト数が伸びてくれればスケールするような仕組みがふさわしいんじゃないのかなとは思います。

2つ目にもけっこうつながる話ですかね。「Fargate Spotインスタンスを使っていきましょう」というところはそうですね。合わせて話したほうがいいのかもしれないです。

福井:そうですね。

Fargate Spotについて

下川:2つ目に入る前に、視聴者の方が「Fargate Spot」というものが何なのか、わからない方もいると思うので(説明します)。

通常Fargateを使う時に、On-DemandとSpotというものを選べます。On-Demandというのは「それを使いますよ」とデベロッパーの方が指示をすれば、それだけの容量が確保されるものです。

Spotインスタンスも一応確保はされるのですが、これは実は裏側の仕組みで、余剰割り当てが取れる場合にSpotを割り当てられて、余剰がなくなればOn-Demand優先でSpotはAWS側に回収されるような仕掛けになっています。

インスタンスが回収されると何が困るかというと、今まで立ち上がっていたAPIサーバーみたいなものが、シャットダウンみたいなかたちで閉じられてしまう。回収されてしまうということになってしまいます。ただ、そのぶん値段が安く提供されているので、コスト効率は非常に良くなります。というのが、2つ目の問いで出てきたFargate Spotの意味になります。

Fargate Spotの停止の影響を受けにくくする方法

下川:相談は「影響を受けにくいアーキテクチャはあるでしょうか?」「停止の影響を受けにくいようにするためにはどうするか?」ということですが、Fargate Spotを使い続ける限り、いつかは回収される可能性はあります。可能性を0にすることはできないです。

可能性を0にしたければOn-Demand側を使っていくことになるのですが、ただOn-DemandはSpotに比べてコストが高い。

じゃあどうするかという話ですが、1つはバランス良くOn-DemandとSpotを使う方法があります。例えば、全体の容量を6と考えた時に、Spotに4を割り当ててOn-Demandを2にするとか。そういったかたちでバランスをとっておくと、可能性的には低いのですが、(Spotが)4つともなくなった場合でもOn-Demand は2つ立ち上がった状態を維持する。

そういった設定ができます。どういった割り当てがいいのかはビジネスとかワークロードによるかと思うのですが、そういったバランスを取ってもらうのがいいんじゃないのかなと思います。

青山:ちなみに、仮に一時停止した場合はどういう対策をとったらいいんですか?

下川:Spotが回収されるタイミングで、ECS側のコントロールプレーンからSIGTERMというシグナルが飛んでいきます。これをコンテナ側で受け入れます。なので、例えばJobの中断とかリクエストの中断処理みたいな。あとはメモリの解放とか、いろいろな後作業をして2分間の猶予が与えられるので、その間になにか後処理をしておく。次のリクエストは別のインスタンスに振られるので、そういったかたちでやっていくのが1つかな。

あと、先ほど出てきたEventBridgeを使う方法もあります。今、2分間の猶予にDispose処理をしましょうという話をしましたが、それはコンテナ側のアプリケーション実装に処理が入り込んでしまう。

オーケストレーションとかスケーリングの仕組みとビジネスロジックを切り離したいからコンテナを使っているのに、アプリケーションロジックの中にDispose処理が入ってくるのは「本末転倒だよ」というような声はよく聞くんですね。

そのために、ESCのコントロールプレーンからSIGTERMのほかに、EventBridgeにもイベントが飛んできます。なのでEventBridgeにそのイベントが来たら、Lambda側にEventを投げて、Lambdaがイベントを受けたらその内容に従って、例えばロードバランサーから対象のターゲットを切り離したりとかDispose処理をしていくということで、コンテナのソース実装の中にはDispose処理、回収処理を入れないことはできるので、EventBridgeの方式は比較的おすすめかなと思います。

福井厚氏(以下、福井):落ちないようにするのではなくて、いつ落ちてもいいような設計をするのが大事なポイントなんですね。そのためにはどうするかというと、リクエストをまたがって状態を保持しないとか、あるいは1つのリクエスト処理の処理時間をできるだけ短くするとか。

そういったことをやることによって、たとえSIGTERMが来てコンテナが落ちたとしても、次のリクエストは次の別のタスクが受けられるようにするということを考えておくのが大事なポイントで、いわゆるステートレスなアプリケーションの実装をするということがまず第一になります。

そうすることでスケーラビリティも上がるし、耐障害性も上がるかたちになります。そういった、いわゆる「The Twelve-Factor App」に書かれているようなアプリケーション設計の原則で、バックエンドサービスに状態を持たせるとか、あるいは設定情報を外出しするとか、それから並行性を担保するとか。こういったところを守ることによって、よりSpotを有効に活用できるようになるかと思います。そのあたりが1つポイントかなと思いますね。

青山:ありがとうございます。

強制停止してしまうコンテナがあった場合にどう対策をとるか

青山:1個気になったんですが、SIGTERMでしたっけ? 停止する時に通知して、それが送られてきたら……。ちょっとうろ覚えで、nginxか何かでシグナルが送られてきたら強制停止(する)みたいな仕様だった気がするんですけれど。

聞きたいのですが、もしそのSIGTERMというシグナルが送られてきて強制停止してしまうコンテナがあった場合、どういう対策をとったらいいですか?

下川:先ほど福井さんが言っていたステートレスとかっていう言葉がすごく大切かなと思っていて。例えば強制停止でリクエストが処理されなかったケースですが、たぶんリクエストが処理されないケースって、SIGTERM以外にも別にいろいろあるかなと思っていて。

例えば間欠的なネットワーク障害が起きるとか、そういったことによってリクエストが失われるということはあるかなと思います。

なので、基本的にはどんな状況でもステートレスかつ冪等で作っておくことによって、次のクライアントからのリクエストによって、例えば状態が復元できたり再実行ができたりする環境を作っておく。Fargate Spotだけの対応というよりは、もう少し広い視野で対応していくのがいいんじゃないのかなと思いました。

福井:そうですね。あと、加えて今再実行させるためには、クライアント側も必ずリトライ処理を入れるのが重要なポイントになりますね。

清水:おそらく今お話しのあたりが、先ほど福井さんおっしゃっていた「The Twelve-Factor App」になってくるのかなと思うんですけれども。このあたりが何なのか軽く教えていただけないですか?

福井:簡単に言うと、これはもともとHerokuのエンジニアの方が書かれた12の要素ですね。アプリケーションの可搬性を高めるための12の要素で書かれています。例えば、バージョン管理された1つのコードベースですべての環境をデプロイするとか、依存関係を明示的に宣言してそれぞれに依存関係を持つようにするとか、共通の依存関係を持たないとかですね。

こういった考え方を12個定義したものを「The Twelve-Factor App」と呼んでいて。これが今の時代にもけっこう通用する部分があるので、特にコンテナとかアプリケーションを実装される時には参考になるかなということで紹介しました。

清水:先ほどのステートレスなどもこの中に含まれてくるよ、という考え方ですかね。

福井:はい。そうですね。

清水:いかがですか、TECH PLAYさんのほうは? けっこう抽象的な回答になってしまったのかなという気もするのですが(笑)。

青山:Fargate Spotって、自分でインスタンスを落とすみたいなことではなくて、AWS側のリソースを見てインスタンスが停止するという流れだと思うんですけれど、実際にテストする時はどういうふうにしたらいいですか?

福井:実際にテストする時は、いくつか方法はあるかと思います。例えばカオスエンジニアリングのようなものを使ってもいいですが、もっと簡単にするのであれば、プロセスにSIGTERMを自分で送ってみるみたいなことでも、ある程度テストはできるかなと思います。

青山:じゃあ、実際にAWSの環境を使ってテストするのはやはり難しいのですね。

福井:そうですね。一応Fargateでもタスクをkillすることはできるので、そういうやり方で試すことはできると思いますが。ただ、Spotのような再現をするのはちょっと難しいかなと思います。

青山:ありがとうございます。EventBridgeにイベントが行くということは、イベントの引数みたいなのがあって、それをモックとして入れてテストするのでも良さそうですかね?

福井:そうです。先ほど下川さんが紹介した方法であれば十分できます。

青山:ありがとうございます。一時停止はどれぐらいの頻度で起こるかわかりますか?

福井:これは本当になんとも言えないという感じですね。

下川:我々もちょっと予想はできないですね。

福井:そうですね。先ほど言ったように、それを予想するよりは、いつ落ちてもいいようにするのが正しいかなと思います。

青山:わかりました。ありがとうございます。

下川:必ずいつかは落ちると思って設計・運用されるのがいいのかなとは思いますね。

清水:ということで「The Twelve-Factor App」のお話が出てきましたが、非常に大事なポイントかなと思うので、視聴者のみなさんもぜひ意識してもらえればなと思います。