Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

B38b75d449a3b6bc60aaf7a0c44674cf?s=128

Takeshi Arabiki

October 29, 2019
Tweet

Transcript

  1. 安定・安価なECS auto scalingを⽬指して SRE Lounge #11(2019-10-29) Repro株式会社 Takeshi Arabiki (@a_bicky)

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

    年 8 ⽉〜) • SREっぽいことをしたり • 分析基盤っぽいことをしたり • 開発環境整備をしたり • Railsアプリケーション触ったり • アーキテクチャ刷新的なことに関わったり ⾃⼰紹介
  3. • ECS auto scalingに必要な最低限の知識 • ReproのECS auto scalingの構成 • ECS

    auto scalingの課題と対処法 • これからの話 • まとめ アジェンダ
  4. ECS auto scalingに必要な最低限の知識

  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の⼤雑把な⽤語説明
  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
  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を使いたい
  8. ReproのECS auto scalingの構成

  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
  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の構成
  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
  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
  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
  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
  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
  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
  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
  18. Fargate https://aws.amazon.com/jp/fargate/

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

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

  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の課題と対処法
  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の課題と対処法
  23. • CloudWatchのメトリクスの値を使ってECS servicesのdesired countを調整 • ECS clustersのサイズの⾯倒は⾒ない • auto scaling

    groupsで管理してCPUReservationを基にdesired capacityを調整するのが⼀般的 Service Auto Scaling
  24. Automatic Scaling with Amazon ECS https://aws.amazon.com/blogs/compute/automatic-scaling-with-amazon-ecs/

  25. Automatic Scaling with Amazon ECS https://aws.amazon.com/blogs/compute/automatic-scaling-with-amazon-ecs/ capacityを減らすとタスクが強制終了させられるかもよ

  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を安全に減らす⽅法
  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の課題と対処法
  28. ある⽇のscale-out spot fleet requestsのhistory(当時はASGの代わりに使⽤) ECS servicesのevents インスタンスが起動してから新しいtasksが起動するまでに約6分

  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)
  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
  31. ECS Autoscalerの改修 https://github.com/reproio/ecs_deploy/pull/53

  32. • リソースが確保できてから増やす desired countを増やす時のポイント

  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の課題と対処法
  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)
  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
  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)
  37. ECS Autoscalerの改修 https://github.com/reproio/ecs_deploy/pull/50

  38. • service stable後、serviceから外れたtasksがstoppedになったことを確認する scale-inの完了を判断する⽅法

  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の課題と対処法
  40. ある⽇のscale-in auto scaling groupsのactivity history

  41. AZRebalance https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-benefits.html#AutoScalingBehavior.InstanceUsage

  42. AZRebalance https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-benefits.html#AutoScalingBehavior.InstanceUsage ⾃分でdetachする場合はAZのバランスを考慮しないといけない

  43. ECS Autoscalerの改修 https://github.com/reproio/ecs_deploy/pull/52

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

    ⾃前でdetachする場合はAZのバランスを考慮する • ※その他の要因でバランスが崩れた場合は対処できない AZRebalanceにtasksを強制終了させられない⽅法
  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の課題と対処法
  46. ある⽇のscale-in auto scaling groupsのactivity history

  47. • 短い間に特定AZのinsntacesが複数落とされることがある • AZの均衡を考慮してinterruptionするわけじゃない Spot Instance Interruptions

  48. Let's suspend AZRebalance

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

    ⾃前でdetachする場合はAZのバランスを考慮する • ※その他の要因でバランスが崩れた場合は対処できない AZRebalanceにtasksを強制終了させられない⽅法(再掲)
  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の課題と対処法
  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分
  52. • interruption warningsを受け取った時点では何もできない • 新しいinstanceが起動してからauto scaling groupsでInServiceになるのに約30秒 • 新しいinstanceが起動してからECS clusterに登録されるのに約30秒

    起動直後のSpot Instancesをinterruptされることの問題点
  53. • instancesがclustersに登録されるまで待ってからdrainingする • instances⾃⾝がinstance metadataのinstance-actionを監視してdrainingする 対策(未対応)

  54. これからの話

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

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

  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)
  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)