AWS ECS について
AWS ECS は、
クラスタの中にサービスがあり、
サービスの中にタスクがあり、
タスクの中にコンテナ(Dockerコンテナ)がある
箇条書きで表すとこのようになっている
- クラスタ
- サービス
- タスク
- コンテナ
- タスク
- サービス
- タスク
- コンテナ
- コンテナ
- タスク
- サービス
僕も一応意識はしてサービスを分けていたが、この前失敗したことがあったので、その失敗談と合わせてまとめておく。
失敗例1: オートスケールで壊れる
こういうサービスの構成を組んでいたことがあった
- クラスタ
- サービス
- タスク
- Web API コンテナ
- Cron コンテナ
- タスク
- サービス
特に何も考えず、一つのサービスの中に Web API コンテナと Cron コンテナ(定期処理を行うコンテナ)を一緒に突っ込んでいた。
しかし、オートスケールをしようとした時に問題が発生する。サービスに対してオートスケールの設定を追加すると、負荷に応じてタスクを増やすことができる。
- クラスタ
- サービス
- タスク
- Web API コンテナ
- Cron コンテナ
- タスク
- Web API コンテナ
- Cron コンテナ
- タスク
- サービス
すると、Cron コンテナも増えてしまい、日次の定期処理が2つ動いておかしなことになる。
Cron コンテナは常に1つだけ起動して、Web API コンテナは負荷に応じて増減してほしい。必要タスク数が違う場合はサービスを分けるのが正しい。
- クラスタ
- Web API サービス
- タスク
- Web API コンテナ
- タスク
- Web API コンテナ
- タスク
- Cron サービス
- タスク
- Cron コンテナ
- タスク
- Web API サービス
デプロイ時にも同じ問題が発生する
オートスケールに限らず、デプロイ時にも同じ問題が発生する。サービスの定義では、デプロイの戦略も定義することができる。
- Web API サービスは、デプロイ時に API が止まってほしくないため、新しいバージョンのタスクを追加したあとに、古いタスクを終了させたい
- minimumHealthyPercent=100, maximumPercent=200 のような設定になる
- Cron コンテナでは、多重起動を防ぎたいので、古いタスクを終了させてから、新しいバージョンのタスクを起動したい
- minimumHealthyPercent=0, maximumPercent=100 になる
この観点でも、サービスを適切に分ける必要がある。
失敗例2: コンテナが死んでタスクが落ちる
これは、以前書いたこの記事と関連する失敗例である。
このようなサービスを組んでいた
- クラスタ
- Web API サービス
- タスク
- Web API コンテナ
- Queue Worker コンテナ
- タスク
- Web API コンテナ
- Queue Worker コンテナ
- タスク
- Web API サービス
Queue Worker コンテナとは、Amazon SQS というキューイングサービスからメッセージを受け取って処理するサービスだ。Queue Worker は常時起動し、Amazon SQS からメッセージを受け取って処理する。
Queue Worker は複数起動していても問題ないので、失敗例1で書いたオートスケール問題は大丈夫なのだが、別の問題が発生した。
Queue Worker コンテナが処理中にコンテナごと落ちる問題が発生した。Queue Worker コンテナが落ちると、ECS によってまるっとそのタスクが終了するため、Web API コンテナもまとめて落ちてしまう。こうなると、タスクが再起動するまで API が叩けなくなったり、LB のターゲットから外れるまで一部の API リクエストが失敗したりする。
そこで、Queue Worker と Web API はサービスを分けることにした
- クラスタ
- Web API サービス
- タスク
- Web API コンテナ
- タスク
- Web API コンテナ
- タスク
- Worker サービス
- Queue Worker コンテナ
- Web API サービス
今回の場合、Web API のような高いサービスレベルを要求されるものと、すぐ落ちる Queue Worker が同じサービスの中に入っていたのが良くなかったかな、と思います。
もっとシンプルに言うと、一つのサービスの中にいろいろ詰め込みすぎるのが良くないです。
まとめ
サービスはシンプルに保ち、タスクの数などの設定項目に応じて適切にサービスを分割すること。