安定・安価なECS auto scalingを目指して / SRE Lounge #11

安定・安価なECS auto scalingを目指して / SRE Lounge #11

B38b75d449a3b6bc60aaf7a0c44674cf?s=128

Takeshi Arabiki

October 29, 2019
Tweet

Transcript

  1. 2.

    • Twitter: @a_bicky • Blog: あらびき⽇記 • 所属: Repro株式会社 (2017

    年 8 ⽉〜) • SREっぽいことをしたり • 分析基盤っぽいことをしたり • 開発環境整備をしたり • Railsアプリケーション触ったり • アーキテクチャ刷新的なことに関わったり ⾃⼰紹介
  2. 3.

    • ECS auto scalingに必要な最低限の知識 • ReproのECS auto scalingの構成 • ECS

    auto scalingの課題と対処法 • これからの話 • まとめ アジェンダ
  3. 5.

    • Task Definitions • 1つ以上のDockerコンテナの定義、リソースの割当などを定義するもの • Tasks • task definitionの内容を基に起動されたコンテナ郡

    • オブジェクト指向を例にすると、task definitionがクラス、taskがインスタンスみたいなもの • Services • 指定されたtask definitionのtaskを指定されたdesired countの数だけ起動するもの • ALB, NLBとの連携、auto scaling、デプロイの管理なども⾏える • Clusters • taskを動かすためのEC2 instancesを登録したり、servicesを登録したりするための箱 Amazon ECSの⼤雑把な⽤語説明
  4. 6.

    Amazon ECSの⼤雑把な⽤語説明 tasks service 1 EC2 instances (container instances) Cluster

    task definition 1 desired count = 3 tasks service 2 task definition 2 desired count = 1
  5. 7.

    ECSのauto scalingのポイント • servicesのdesired countを調整する必要がある • desired countを増やした際の新しいtasksが起動するまでの時間は短くしたい • clustersを構成するinstancesの数(clustersのサイズ)を調整する必要がある

    • servicesのdesired countを変えてもinstancesの数は固定 • clustersサイズを減らす際にはinstancesのdraining (graceful stop) が必要 • コストを抑えるためにはinstancesにはspot instancesを使いたい
  6. 9.

    ReproのECS auto scailngの構成 Auto scaling group for a ECS cluster

    ECS cluster with reserved instances API tasks API service Worker tasks Worker service ecs_auto_scaler task ecs_auto_scaler service Auto scaling group for a ECS cluster ECS cluster with spot instances API tasks API service Auto scaling group for a ECS cluster ECS cluster with spot instances Worker tasks Worker service
  7. 10.

    • clustersのサイズはauto scaling groupsで管理 • auto scaling⽤のclustersにはspot instancesを使⽤ • servicesのdesired

    countとclustersのサイズを管理するECS serviceがある • spot instancesのinterruption warningsを処理してdrainingするのもこのservice ReproのECS auto scailngの構成
  8. 11.

    ECS scailng時の動作 Auto scaling group for a ECS cluster ECS

    cluster with reserved instances API tasks API service Worker tasks Worker service ecs_auto_scaler task ecs_auto_scaler service Auto scaling group for a ECS cluster ECS cluster with spot instances API tasks API service Auto scaling group for a ECS cluster ECS cluster with spot instances Worker tasks Worker service ① Check CloudWatch alarm state
  9. 12.

    Auto scaling group for a ECS cluster ECS cluster with

    reserved instances API tasks API service Worker tasks Worker service ecs_auto_scaler task ecs_auto_scaler service Auto scaling group for a ECS cluster ECS cluster with spot instances API tasks API service ② Update desired count ECS scailng時の動作 Auto scaling group for a ECS cluster ECS cluster with spot instances Worker tasks Worker service
  10. 13.

    Auto scaling group for a ECS cluster ECS cluster with

    reserved instances API tasks API service Worker tasks Worker service ecs_auto_scaler task ecs_auto_scaler service Auto scaling group for a ECS cluster ECS cluster with spot instances API tasks API service ③ Update desired capacity ECS scailng時の動作 Auto scaling group for a ECS cluster ECS cluster with spot instances Worker tasks Worker service
  11. 14.

    Spot instancesのinterruption時の動作 Auto scaling group for a ECS cluster ECS

    cluster with reserved instances API tasks API service Worker tasks Worker service ecs_auto_scaler task ecs_auto_scaler service ① Receive interruption warnings from SQS Auto scaling group for a ECS cluster ECS cluster with spot instances API tasks API service Auto scaling group for a ECS cluster ECS cluster with spot instances Worker tasks Worker service
  12. 15.

    Auto scaling group for a ECS cluster ECS cluster with

    reserved instances API tasks API service Worker tasks Worker service ecs_auto_scaler task ecs_auto_scaler service ② Drain container instances Auto scaling group for a ECS cluster ECS cluster with spot instances API tasks API service Spot instancesのinterruption時の動作 Auto scaling group for a ECS cluster ECS cluster with spot instances Worker tasks Worker service
  13. 16.

    Auto scaling group for a ECS cluster ECS cluster with

    reserved instances API tasks API service Worker tasks Worker service ecs_auto_scaler task ecs_auto_scaler service ③ Detach instances Auto scaling group for a ECS cluster ECS cluster with spot instances API tasks API service Spot instancesのinterruption時の動作 Auto scaling group for a ECS cluster ECS cluster with spot instances Worker tasks Worker service
  14. 17.

    • github.com/reproio/ecs_deploy で提供されているプログラム • service auto scalingもFargateもなかった頃に導⼊されたもの • CloudWatchのalarmsのstateを基にECS servicesのdesired

    countを増減する • desired countに応じてauto scaling groupのdesired capacityも更新する • scale-outの時間を短縮するためにinstancesを余計に確保する設定がある • desired countを減らす際はタスクの配置されていないinstancesを落とす • Spot instancesのinterruption warningsを受け取ったらdrainingする • 別途CloudWatch ruleとSQSの設定が必要 • ECS_ENABLE_SPOT_INSTANCE_DRAININGパラメータを設定すれば不要 ECS Autoscaler
  15. 19.

    • reserved instances, spot instancesに⽐べるとかなり割⾼ • パフォーマンスが低い • タスクの起動が遅い •

    log driverがawslogs⼀択 • 最近FireLensが正式リリースされたのでこの問題は解消できるはず • Fargateの導⼊をしっかり検討するだけの開発リソースがない Fargateを採⽤しない理由
  16. 21.

    • auto scaling groupsのcapacityを減らすだけだとtasksをgraceful stopできない • 闇雲にdesired countを増やすとtasksの起動に5 分以上かかることがある •

    ECS servicesのscale-inが完了したタイミングを取るにはひと⼿間必要 • availability zoneの均衡が崩れるとtasksの動いているinstancesでも落とされる • spot instancesがinterruptされてAZの均衡が崩れることがある • 起動直後のspot instancesがinterruptされる場合drainingできない ECS auto scalingの課題と対処法
  17. 22.

    • auto scaling groupsのcapacityを減らすだけだとtasksをgraceful stopできない • 闇雲にdesired countを増やすとtasksの起動に5 分以上かかることがある •

    ECS servicesのscale-inが完了したタイミングを取るにはひと⼿間必要 • availability zoneの均衡が崩れるとtasksの動いているinstancesでも落とされる • spot instancesがinterruptされてAZの均衡が崩れることがある • 起動直後のspot instancesがinterruptされる場合drainingできない ECS auto scalingの課題と対処法
  18. 23.

    • CloudWatchのメトリクスの値を使ってECS servicesのdesired countを調整 • ECS clustersのサイズの⾯倒は⾒ない • auto scaling

    groupsで管理してCPUReservationを基にdesired capacityを調整するのが⼀般的 Service Auto Scaling
  19. 26.

    • auto scaling groupsのlifecycle hooksを利⽤してdrainingする • How to Automate Container

    Instance Draining in Amazon ECS • instance protectionを使ってtasksの動いているinstancesを保護する • EC2 Auto-ScalingでECS組んでますか?エラーレート⾼いですか?救ってあげてもいいですか? • ⾃前でauto scalingを実装する • e.g. ECS Autoscaler capacityを安全に減らす⽅法
  20. 27.

    • auto scaling groupsのcapacityを減らすだけだとtasksをgraceful stopできない • 闇雲にdesired countを増やすとtasksの起動に5 分以上かかることがある •

    ECS servicesのscale-inが完了したタイミングを取るにはひと⼿間必要 • availability zoneの均衡が崩れるとtasksの動いているinstancesでも落とされる • spot instancesがinterruptされてAZの均衡が崩れることがある • 起動直後のspot instancesがinterruptされる場合drainingできない ECS auto scalingの課題と対処法
  21. 29.

    リソースが⾜りない状態が続いた場合の起動時間を検証 # (snip) 6.times do |i| puts "#{i + 1}th

    try" sleep_sec = i * 10 ecs.update_container_instances_state( cluster: cluster, container_instances: arns, status: 'DRAINING') ecs.update_service(cluster: cluster, service: svc, desired_count: 1) updated_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) sleep sleep_sec ecs.update_container_instances_state( cluster: cluster, container_instances: arns, status: 'ACTIVE') ecs.wait_until(:services_stable, { cluster: cluster, services: [svc] }, delay: 1, max_attempts: nil) elapsed_sec = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - updated_time).round puts "Sleep: #{sleep_sec} sec, Elapsed: #{elapsed_sec} sec" # (snip)
  22. 30.

    リソースが⾜りない状態が続いた場合の起動時間を検証 1th try Sleep: 0 sec, Elapsed: 12 sec 2th

    try Sleep: 10 sec, Elapsed: 23 sec 3th try Sleep: 20 sec, Elapsed: 32 sec 4th try Sleep: 30 sec, Elapsed: 42 sec 5th try Sleep: 40 sec, Elapsed: 51 sec 6th try Sleep: 50 sec, Elapsed: 353 sec
  23. 33.

    • auto scaling groupsのcapacityを減らすだけだとtasksをgraceful stopできない • 闇雲にdesired countを増やすとtasksの起動に5 分以上かかることがある •

    ECS servicesのscale-inが完了したタイミングを取るにはひと⼿間必要 • availability zoneの均衡が崩れるとtasksの動いているinstancesでも落とされる • spot instancesがinterruptされてAZの均衡が崩れることがある • 起動直後のspot instancesがinterruptされる場合drainingできない ECS auto scalingの課題と対処法
  24. 34.

    危険なコード # Stop all tasks and terminate all instances in

    the cluster ecs.update_service(cluster: cluster, service: svc, desired_count: 0) ecs.wait_until(:services_stable, cluster: cluster, services: [svc]) ec2.terminate_instances(instance_ids: container_instance_ec2_ids)
  25. 35.

    ECSにおけるservice stable https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-lifecycle.html { "expected" => true, "matcher" => "path",

    "state" => "success", "argument" => "length(services[?!(length(deployments) == `1` && running_count == desired_count)]) == `0`" } • desired countを減らした場合はstoppingな
 タスクがあってもstableになる aws-sdk-ecs/waiters.rb#L57-L111
  26. 36.

    安全なコード # Stop all tasks and terminate all instances in

    the cluster running_task_arns = ecs.list_tasks( cluster: cluster, service_name: svc, desired_status: 'RUNNING' ).flat_map(&:task_arns) ecs.update_service(cluster: cluster, service: svc, desired_count: 0) ecs.wait_until(:services_stable, cluster: cluster, services: [svc]) stopping_task_arns = running_task_arns - ecs.list_tasks( cluster: cluster, service_name: service, desired_status: 'RUNNING' ).flat_map(&:task_arns) stopping_task_arns.each_slice(100) do |arns| ecs.wait_until(:tasks_stopped, cluster: cluster, tasks: arns) end ec2.terminate_instances(instance_ids: container_instance_ec2_ids)
  27. 39.

    • auto scaling groupsのcapacityを減らすだけだとtasksをgraceful stopできない • 闇雲にdesired countを増やすとtasksの起動に5 分以上かかることがある •

    ECS servicesのscale-inが完了したタイミングを取るにはひと⼿間必要 • availability zoneの均衡が崩れるとtasksの動いているinstancesでも落とされる • spot instancesがinterruptされてAZの均衡が崩れることがある • 起動直後のspot instancesがinterruptされる場合drainingできない ECS auto scalingの課題と対処法
  28. 44.

    • auto scaling groupsのlifecycle hooksでinstancesをdrainingする • AZRelabanceをsuspendする • capacityを頻繁に変えていればそのうちバランスが取れるので⼤して問題にならない •

    ⾃前でdetachする場合はAZのバランスを考慮する • ※その他の要因でバランスが崩れた場合は対処できない AZRebalanceにtasksを強制終了させられない⽅法
  29. 45.

    • auto scaling groupsのcapacityを減らすだけだとtasksをgraceful stopできない • 闇雲にdesired countを増やすとtasksの起動に5 分以上かかることがある •

    ECS servicesのscale-inが完了したタイミングを取るにはひと⼿間必要 • availability zoneの均衡が崩れるとtasksの動いているinstancesでも落とされる • spot instancesがinterruptされてAZの均衡が崩れることがある • 起動直後のspot instancesがinterruptされる場合drainingできない ECS auto scalingの課題と対処法
  30. 49.

    • auto scaling groupsのlifecycle hooksでinstancesをdrainingする • AZRelabanceをsuspendする • capacityを頻繁に変えていればそのうちバランスが取れるので⼤して問題にならない •

    ⾃前でdetachする場合はAZのバランスを考慮する • ※その他の要因でバランスが崩れた場合は対処できない AZRebalanceにtasksを強制終了させられない⽅法(再掲)
  31. 50.

    • auto scaling groupsのcapacityを減らすだけだとtasksをgraceful stopできない • 闇雲にdesired countを増やすとtasksの起動に5 分以上かかることがある •

    ECS servicesのscale-inが完了したタイミングを取るにはひと⼿間必要 • availability zoneの均衡が崩れるとtasksの動いているinstancesでも落とされる • spot instancesがinterruptされてAZの均衡が崩れることがある • 起動直後のspot instancesがinterruptされる場合drainingできない ECS auto scalingの課題と対処法
  32. 51.

    あるInstanceの情報 Launch time: October 21, 2019 at 11:55:52 AM UTC+9

    State transition reason: Service initiated (2019-10-21 02:58:26 GMT) State transition reason: message Service.SpotInstanceTermination 起動から削除までわずか2.5分
  33. 55.

    • 解像度1分のCloudWatchのmetricsだとauto scalingが間に合わないことが度々 • 平⽇・休⽇の傾向も考慮するだけでかなり良くなるはず • ⾼解像度のmetricsの使⽤やCloudWatchに依存しないauto scalingも良さそう • 明らかに異常なリクエスト数があっても許容してしまっている

    • 429を返したい • お客さんのサービスによって使われ⽅が全然違うので異常かどうかの判断が⾮常に難しい • FargateやKubernetesの検証をやれてない • "SRE"と呼ばれる⼈たちが機能開発やら開発環境整備やらもやっている現状 • ⼈が!⾜り!!ない!!!! 課題はたくさん
  34. 56.
  35. 57.

    • auto scaling groupsのcapacityを減らすだけだとtasksをgraceful stopできない • → lifecycle hooks, instance

    protectionで対処するか⾃前でauto scalingの仕組みを構築する • 闇雲にdesired countを増やすとtasksの起動に5 分以上かかることがある • → clustersのリソースを確保してからdesired countを増やすことを徹底する • ECS servicesのscale-inが完了したタイミングを取るにはひと⼿間必要 • → services stable waiterだけでなくtasks stopped waiterも併⽤する まとめ (1/2)
  36. 58.

    • availability zoneの均衡が崩れるとtasksの動いているinstancesでも落とされる • → lifecycle hooksでdrainingする、AZRebalanceをsuspendする、detachする時に頑張る • spot instancesがinterruptされてAZの均衡が崩れることがある

    • → lifecycle hooksでdrainingする、AZRebalanceをsuspendする • 起動直後のspot instancesがinterruptされる場合drainingできない • → clustersに登録されるまで待ってdrainingする、instance⾃⾝にdrainingさせる まとめ (2/2)