Slide 1

Slide 1 text

Amazon ECS の安定運用 Kohei Suzuki

Slide 2

Slide 2 text

アウトライン - コンテナインスタンスの管理 - スポットインスタンス対応 - コンテナインスタンスのオートスケーリング - ログ - 配送、保存、検索 - モニタリング

Slide 3

Slide 3 text

規模感 - ほとんどのアプリケーションが ECS 上で動いている - hako (自作ツール) を使ってデプロイやバッチジョブの起動を行っている - ECS クラスタ数: 40 - 合計 ECS サービス数: 500 - 1日あたりの RunTask 数: 80,000

Slide 4

Slide 4 text

コンテナインスタンスの管理

Slide 5

Slide 5 text

コンテナインスタンスの管理 - オンデマンドインスタンスは AutoScaling Group - ECS クラスタと AutoScaling Group が一対一対応 - スポットインスタンスは Spot Fleet - ECS クラスタと Spot Fleet が一対一対応 - オンデマンド・スポット比: 1:4

Slide 6

Slide 6 text

Fargate? - 一部では Fargate も使っているが、基本は自前管理のインスタンス - スポットインスタンスを使ったほうが安い - Fargate だと起動が遅い、起動までの時間が安定しない - Web アプリではそこまで困らない - そこそこの頻度で起動するバッチジョブだとつらい - Fargate を使うケース - ECS クラスタ自体を操作するジョブ (ECS クラスタのオートスケーリング等 ) - 特別に大きな CPU、メモリリソースを必要とするジョブ

Slide 7

Slide 7 text

オンデマンドクラスタ - 全クラスタで共通の AMI から起動 (※GPU クラスタを除く) - オートスケールは自前 (後述) - AutoScaling Group の役割 - 「desired capacity を上下するだけで ECS クラスタの増減ができる」状態にする - インスタンス障害からのオートヒール

Slide 8

Slide 8 text

AutoScaling Group でのサービスアウト - スケールアウトは簡単だが、スケールインをするには事前にサービスアウトして おく必要がある - lifecycle hook の Terminating:Wait の間にコンテナインスタンスを DRAINING 状態にしてサービスアウト

Slide 9

Slide 9 text

スポットクラスタ - オンデマンド同様、共通の Ubuntu ベースの AMI から起動 - Spot Fleet で管理 - こちらもオートスケールは自前 (後述) - Spot Fleet の役割 - 「target capacity を上下するだけで ECS クラスタの増減ができる」状態にする - スポット価格上昇やインスタンス障害からのオートヒール

Slide 10

Slide 10 text

Spot Fleet でのサービスアウト - Spot Fleet の target capacity を下げてスケールインするときも、スポット価格上 昇で terminate されるときと同じように interruption notice が通知される - interruption notice を CloudWatch Events から SQS キュー経由で受け取り、 デーモンがサービスアウト処理を行う

Slide 11

Slide 11 text

Spot Fleet でのサービスアウト - AutoScaling Group とは異なり、通知がきてから2分以内にサービスアウトしき る必要がある - バッチジョブは諦めて StopTask API で止める - スポットクラスタでバッチジョブを動かすときはアプリケーション側に冪等性を要求する - DRAINING 状態にして ECS に任せるだけでは間に合わない可能性がある

Slide 12

Slide 12 text

Spot Fleet でのサービスアウト - 先に自前で ELB の target group から deregister する - 先に DeregisterTargets してしまえば新規のリクエストはそのタスクにはこなくなる - DeregisterTargets し終わったら StopTask で止める - ECS や ELB に邪魔されないように deregistration_delay.timeout_seconds を一定 以上にしておく - 突然一部のタスクが停止しても問題無いようにやや過剰なキャパシティを常に 確保しておく - そうしてもスポットインスタンスのほうが安い

Slide 13

Slide 13 text

Spot Fleet でのサービスアウト (w/o ELB) 1. interruption notice Terminator 3. StopTask 2. UpdateContainerInstancesState (DRAINING)

Slide 14

Slide 14 text

Spot Fleet でのサービスアウト (w/ ELB) 1. interruption notice Terminator 5. StopTask 2. UpdateContainerInstancesState (DRAINING) 3. DeregisterTargets 4. DescribeTargetHealth

Slide 15

Slide 15 text

オートスケーリング

Slide 16

Slide 16 text

オートスケーリング - オンデマンドクラスタとスポットクラスタの間で戦略に差は無い - AutoScaling Group の desired capacity を調整するか、Spot Fleet の target capacity を調整するかの違いだけ - 3種類のスケールアウトと1種類のスケールイン

Slide 17

Slide 17 text

スケールアウト - クラスタの CPUReservation、MemoryReservation を見て閾値を超えてたらス ケールアウト - 各 service の desired_count、running_count、pending_count を チェックして足りてなさそうだったらスケールアウト - hako oneshot (バッチジョブの起動) がリソース不足で RunTask に失敗した らスケールアウト

Slide 18

Slide 18 text

スケールアウト (1) - CloudWatch に入っている CPUReservation、MemoryReservation を定期的に チェックして、閾値を超えていたらスケールアウト - スポットクラスタの場合はオンデマンドクラスタより閾値を低くしている

Slide 19

Slide 19 text

スケールアウト (2) - 各 service の desired_count、running_count、pending_count を定 期的にチェックして、desired_count > running_count + pending_count となっていたらリソースが足りずにデプロイが停滞している可 能性があるので、スケールアウトする

Slide 20

Slide 20 text

スケールアウト (3) - hako oneshot (バッチジョブの起動) がリソース不足で RunTask に失敗した ときに SNS トピックに通知するので、それを SQS 経由で受け取ってスケールア ウト

Slide 21

Slide 21 text

スケールアウト (3) AutoScaler Hako 1. RunTask (failed) 2. Publish 3. ModifySpotFleetRequest 3. SetDesiredCapacity

Slide 22

Slide 22 text

スケールイン - クラスタの CPUReservation、MemoryReservation を見て閾値を下回っていた らスケールイン - スポットクラスタの場合はオンデマンドクラスタより閾値を低くしている

Slide 23

Slide 23 text

ログ

Slide 24

Slide 24 text

ログ - コンテナの stdout/stderr に出たログをどこにどう保存するか - 現在のクックパッドでは Docker の fluentd logging driver から fluentd を経由 して Amazon S3 に保存し、Amazon Athena で簡易検索できるようにしている

Slide 25

Slide 25 text

CloudWatch Logs? - マネージドなログの保存、検索、閲覧サービス - しかしログの量が膨大すぎてピークタイムでは CloudWatch Logs にリアルタイ ムに入りきらない - 入っても検索したり取り出したりするのが遅い - ログを入れるときの料金 (ingestion) だけでもかなり高価に - 閲覧できるまでのラグや検索の柔軟性をやや犠牲にして、スケーラブルで安価 な S3 をログストレージとして選択

Slide 26

Slide 26 text

ログ配送 Container instances service logs task logs S3 Event ecs-logs-router fluentd aggregator

Slide 27

Slide 27 text

ログ配送 Container instances service logs task logs S3 Event ecs-logs-router fluentd aggregator

Slide 28

Slide 28 text

ログ配送 - コンテナインスタンスのホスト側に fluentd を起動し、Docker の logging driver の設定でそこへ送信 - 各コンテナインスタンスから fluentd の集約ノードへと転送する - 集約ノードには大量のログが送信されてくる - fluentd v1.0 からは複数プロセスで処理できるようになっているので、それを利用してがんばっ て処理しきる - https://docs.fluentd.org/v1.0/articles/multi-process-workers

Slide 29

Slide 29 text

ログ配送 Container instances service logs task logs S3 Event ecs-logs-router fluentd aggregator

Slide 30

Slide 30 text

ログ配送 - 集約ノードの fluentd が1分毎に s3://service-logs/${task_definition_family}/${container _name}/%Y/%m/%d/%Y%m%d%H%M_%{index}_%{flush_uuid}.gz に ログを出力する - タスクを横断して、service 毎 (task definition 毎) に閲覧するためのログ

Slide 31

Slide 31 text

ログ配送 Container instances service logs task logs S3 Event ecs-logs-router fluentd aggregator

Slide 32

Slide 32 text

ログ配送 - s3://service-logs に置かれたログを ecs-logs-router がタスク ID 毎に分 解して s3://task-logs/${task_definition_family}/${container_na me}/${task_id}/ 以下に置く - タスク単位で閲覧するためのログ

Slide 33

Slide 33 text

ログ検索 - Amazon Athena で検索できるように、AWS Glue でカタログを日次で更新して いる - ${task_definition_family}_${container_name} というテーブル名 - 日付でパーティションを切っている - 例: my-awesome-app の app コンテナの今日のログから ERROR を探す - select time, log from "my_awesome_app_app" where year = 2018 and month = 11 and day = 28 and log like '%ERROR%' order by time

Slide 34

Slide 34 text

モニタリング

Slide 35

Slide 35 text

モニタリング - CloudWatch に service 単位のメトリクスは存在しているが、タスク単位、コンテ ナ単位でのメトリクスは存在していない - したがって RunTask で起動した場合はメトリクスが一切存在しない - アプリケーション開発者にとって、主に見たいのはアプリケーションコンテナだけ のメトリクス - サイドカーとして起動している fluentd や Envoy 等は要らない

Slide 36

Slide 36 text

モニタリング - cAdvisor でメトリクスを取得し、Prometheus からそれを scrape し、Grafana で 可視化することにした - cAdvisor 自体に Prometheus 用のメトリクスを返すエンドポイントがあるので、 これが一番簡単そうだった - cAdvisor は ECS の daemon scheduling を使って各コンテナインスタンスに配 置した

Slide 37

Slide 37 text

モニタリング

Slide 38

Slide 38 text

モニタリング

Slide 39

Slide 39 text

まとめ

Slide 40

Slide 40 text

まとめ - ECS で様々なサービスを動かすためにやってることの一部を紹介した - オンデマンドインスタンス管理、スポットインスタンス対応 - オートスケーリング戦略 - ログ配送 - モニタリング - 今回話さなかったトピック - ECS API の rate limit を回避するための工夫 - コンテナインスタンス側の問題を調査するためのロギング

Slide 41

Slide 41 text

今後 - センシティブな値を環境変数に入れる機能がついにきたので移行したい - https://aws.amazon.com/about-aws/whats-new/2018/11/aws-launches-secrets-support-f or-amazon-elastic-container-servic/ - AutoScaling Group でスポットインスタンスを管理できるようになったので移行し たい - https://aws.amazon.com/jp/blogs/aws/new-ec2-auto-scaling-groups-with-multiple-instan ce-types-purchase-options/