🐥

[AWS/ECS]ECSはEC2に比べて何が嬉しいのか?

2022/10/28に公開

こんにちは。Opt Fit CROの森田です。

今回は、EC2と比較したECSのメリットと、ECSの基本的?な運用イメージについて書いてみようと思います。
EC2のAMIをクローンしたら別に一緒じゃね?と思っていた時期が私にもありましたが、実際に使ってみていろんなメリットを実感したので、同じような境遇の方のご参考になれば幸いです。

背景

弊社サービスにおいて、クライアント毎に1台のEC2を立てて処理を実行していました。
最初はそれで全く問題なかったのですが、クライアントが増えていくにつれてEC2台数も増え、なんらかの修正が発生したときにすべてのEC2へSSH接続してプログラムを書き換えるのがしんどくなってきました。
そこでECSの出番です。ECSのメリットはいろいろあると思いますが、個人的にはこのプログラム更新作業を一括で処理できるというのが一番嬉しかったです。

ECSの基本

ざっくりどんなものか

何らかの処理をするDockerコンテナを、EC2/Fargate/外部サーバーいずれかの上で動かす仕組みです。
Fargateというのは、AWSが管理するEC2をよしなに使ってやってくれる仕組みです。
どれがよいのかは場合によりますが、基本はFargateが楽でしょう[1]

構成

ECSは、クラスター・サービス・タスクという単位で構成されています。
クラスターには複数のサービスを登録できます。
サービスには1つのタスク定義を登録します。
タスク定義は複数のDockerコンテナから構成され、例えば、センサーから情報取得するコンテナ、AIを動かすコンテナ、のような感じです。
Docker Composeのイメージですね。
抽象的でよくわからないと思いますので、構成の具体例を後述します。

EC2と比較したECSのメリット

EC2のAMIクローンは大変

昔は、ある程度EC2で構築した後にAMIクローンしてポチポチやっていました。
完成版AMIを未来永劫修正しない場合はそれでもいいかもしれません。
しかしそんなことはほぼあり得ないので、修正する場合に数十~数百台とかの規模になるとやってられなくなりますし、プログラム書き換えミスも発生します。

ECSのサービス一括更新

1台のEC2で処理していたものを、1つのサービスに丸ごと置き換えるイメージです。
ブラウザのAWSコンソールではサービスごとに更新ボタンを押さないといけませんが、プログラムでAWS CLIをループ処理させればよいです。

#!/bin/bash -eux

for service in `aws ecs list-services --cluster クラスター名 --output text | cut -d '/' -f 3`
do
    echo $service
    aws ecs update-service \
    --cluster クラスター名 \
    --service ${service} \
    --force-new-deployment
done

ECSの運用イメージ

想定

今回の例では、クラスターをセンサー情報取得用途として作成し、その中で各クライアントに対するサービスをクライアントの数だけ登録します。
センサー情報取得タスクのみとなるので、タスク定義のコンテナは1つだけとなります。
クライアントによって必要なCPU・メモリリソースは変わりますので、各サービス内のタスク定義にてリソースを個々に設定します。

ECSの設定

先ほどの最小ヘルス率・最大ヘルス率とは何かというと、稼働するタスク数範囲の設定です。(厳密には他の設定で意味合いが変わりますが、今回はローリングアップデート設定での話に留めます)
最小ヘルス率100、最大ヘルス率200であれば、基本はデフォルトの100%(つまり本例ではタスク1個)で稼働し、サービス更新が走ったタイミングで最大200%(つまり本例ではタスク2個)稼働しますよということになります。
基本的にサービスはダウンタイムなく稼働させたい場合が多いと思いますので、この設定にしておけば旧タスク1個→新旧タスク2個→新タスク1個の流れで更新処理が走ります。
昔の私は、よく理解しないまま参考サイトの下記部分だけを採用し、最小ヘルス率0、最大ヘルス率100にしてしまっていました…(「検証」ではいいのですが、実運用では好ましくないと思います)

ECSインスタンス1台で検証している場合は、『最小ヘルス率 0』『最大率 100』としてください。

この場合は、旧タスク1個→タスク0個→新タスク1個の流れで更新処理が走ります。
仮に最小ヘルス率100、最大ヘルス率100の場合、タスクが1個以外の状態になれないので、一生更新できません。

タスク定義

使用するDockerコンテナイメージやCPU・メモリリソース等を設定します。
個人的に一番ややこしかったのはCPU・メモリリソース設定で、まず全体像は下表のようになっています。
リソース制限にはソフトとハードの2種類がありますが、選択肢があるのはEC2の場合のコンテナメモリだけです。
ソフト制限はいわゆる目安で、他のタスクもリソースオーバーして競合した際にこのソフト制限値が考慮されてリソース配分される形です。
ハード制限は本当の限界値で、リソースオーバーした場合、CPUであれば100%となって処理が重くなり、メモリであればタスクが落ちます。
詳細は後述します。

CPU メモリ
Fargate ハード ハード
EC2(タスク) ハード ハード
EC2(コンテナ) ソフト ソフト/ハード

Fargateの場合

タスクメモリ設定で指定した値が上限となり、これをオーバーするとタスクが落ちます。
尚、CPUに関しては100%になってもタスクは落ちず、処理が重くなるだけです。

EC2の場合

Fargateと同じく、タスクのCPU・メモリ設定と、それに加えてコンテナのCPU・メモリ設定があります。とてもややこしいです。

タスクのCPU・メモリ設定

EC2の場合、必須ではありません。
設定しない場合の上限は自ずとEC2のリソース上限となります。

コンテナのCPU・メモリ設定

コンテナメモリ設定では、ソフトorハード制限の選択肢があります。
ソフト制限の場合は、最大でタスクメモリ設定上限あるいはEC2インスタンス全体のメモリ上限まで使うことができ、先述の通り他タスクもリソースオーバーした際に制限値によって配分されます。
CPUに関してはソフト制限のみのようです。

つまりどうすればいいのか

どのように運用したいのかで方針が変わります。
他タスクに影響を与えないようにリソースオーバーしたタスクのみを強制で落としたい場合はハード制限がよいです。
コストを極限まで下げるために多少リスクを負ってでも余剰リソースを減らしたい場合はソフト制限になると思います。
CPU・メモリ制限を設定すると、EC2でその分のリソースが確保されます。
これを適切な値に設定すれば、あとは勝手にECS側でどのEC2にタスクを乗っけるかを判断してくれます。(タスク配置戦略というもので乗っけ方をある程度決めることができます)

サービス更新

コンテナイメージに何らかの修正が発生したら、先述の通りサービス一括更新を実施すればよいです。
ECSインフラがEC2の場合、更新中に新タスクがどのインスタンスに乗っかるかは、タスク定義のリソース設定値とタスク配置戦略で自動判断されます。
タスク定義を変える場合は、個々に設定値をいじる必要があります。

まとめ

ざっくりとECSの嬉しさの一部についてご紹介しました。
規模が大きくスケールする状況では必須レベルのECSでした。

参考

https://dev.classmethod.jp/articles/ecs-resources-knowledge-for-ecs-with-ec2/

https://nishinatoshiharu.com/ecs-release-procedure/

🔔採用情報

ジム施設向けDXソリューションGYMDXではエンジニアを積極採用中です。
ジュニア層のエンジニアからリーダー職まで幅広く募集しています。

2022年7月にプレシリーズAラウンドにて資金調達を実施しました。
https://prtimes.jp/main/html/rd/p/000000015.000055404.html

リードエンジニア

https://herp.careers/v1/optfit/GpvSeC-fA995

バックエンドエンジニア

https://herp.careers/v1/optfit/KsDmlZ1VhTmU

脚注
  1. コスト的には、リソースをフルで使うことを前提とするとFargateの方が若干割高になるケースが多いです ↩︎

Opt Fit テックブログ

Discussion