Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

• Twitter: @a_bicky • Blog: あらびき⽇記 • 所属: Repro株式会社 (2017 年 8 ⽉〜) • SREっぽいことをしたり • 分析基盤っぽいことをしたり • 開発環境整備をしたり • Railsアプリケーション触ったり • アーキテクチャ刷新的なことに関わったり ⾃⼰紹介

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

ECS auto scalingに必要な最低限の知識

Slide 5

Slide 5 text

• 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の⼤雑把な⽤語説明

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

ECSのauto scalingのポイント • servicesのdesired countを調整する必要がある • desired countを増やした際の新しいtasksが起動するまでの時間は短くしたい • clustersを構成するinstancesの数(clustersのサイズ)を調整する必要がある • servicesのdesired countを変えてもinstancesの数は固定 • clustersサイズを減らす際にはinstancesのdraining (graceful stop) が必要 • コストを抑えるためにはinstancesにはspot instancesを使いたい

Slide 8

Slide 8 text

ReproのECS auto scalingの構成

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

• 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の構成

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

• 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

Slide 18

Slide 18 text

Fargate https://aws.amazon.com/jp/fargate/

Slide 19

Slide 19 text

• reserved instances, spot instancesに⽐べるとかなり割⾼ • パフォーマンスが低い • タスクの起動が遅い • log driverがawslogs⼀択 • 最近FireLensが正式リリースされたのでこの問題は解消できるはず • Fargateの導⼊をしっかり検討するだけの開発リソースがない Fargateを採⽤しない理由

Slide 20

Slide 20 text

ECS auto scalingの課題と対処法

Slide 21

Slide 21 text

• 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の課題と対処法

Slide 22

Slide 22 text

• 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の課題と対処法

Slide 23

Slide 23 text

• CloudWatchのメトリクスの値を使ってECS servicesのdesired countを調整 • ECS clustersのサイズの⾯倒は⾒ない • auto scaling groupsで管理してCPUReservationを基にdesired capacityを調整するのが⼀般的 Service Auto Scaling

Slide 24

Slide 24 text

Automatic Scaling with Amazon ECS https://aws.amazon.com/blogs/compute/automatic-scaling-with-amazon-ecs/

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

• 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を安全に減らす⽅法

Slide 27

Slide 27 text

• 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の課題と対処法

Slide 28

Slide 28 text

ある⽇のscale-out spot fleet requestsのhistory(当時はASGの代わりに使⽤) ECS servicesのevents インスタンスが起動してから新しいtasksが起動するまでに約6分

Slide 29

Slide 29 text

リソースが⾜りない状態が続いた場合の起動時間を検証 # (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)

Slide 30

Slide 30 text

リソースが⾜りない状態が続いた場合の起動時間を検証 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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

• 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の課題と対処法

Slide 34

Slide 34 text

危険なコード # 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)

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

安全なコード # 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)

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

• 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の課題と対処法

Slide 40

Slide 40 text

ある⽇のscale-in auto scaling groupsのactivity history

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

• auto scaling groupsのlifecycle hooksでinstancesをdrainingする • AZRelabanceをsuspendする • capacityを頻繁に変えていればそのうちバランスが取れるので⼤して問題にならない • ⾃前でdetachする場合はAZのバランスを考慮する • ※その他の要因でバランスが崩れた場合は対処できない AZRebalanceにtasksを強制終了させられない⽅法

Slide 45

Slide 45 text

• 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の課題と対処法

Slide 46

Slide 46 text

ある⽇のscale-in auto scaling groupsのactivity history

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Let's suspend AZRebalance

Slide 49

Slide 49 text

• auto scaling groupsのlifecycle hooksでinstancesをdrainingする • AZRelabanceをsuspendする • capacityを頻繁に変えていればそのうちバランスが取れるので⼤して問題にならない • ⾃前でdetachする場合はAZのバランスを考慮する • ※その他の要因でバランスが崩れた場合は対処できない AZRebalanceにtasksを強制終了させられない⽅法(再掲)

Slide 50

Slide 50 text

• 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の課題と対処法

Slide 51

Slide 51 text

ある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分

Slide 52

Slide 52 text

• interruption warningsを受け取った時点では何もできない • 新しいinstanceが起動してからauto scaling groupsでInServiceになるのに約30秒 • 新しいinstanceが起動してからECS clusterに登録されるのに約30秒 起動直後のSpot Instancesをinterruptされることの問題点

Slide 53

Slide 53 text

• instancesがclustersに登録されるまで待ってからdrainingする • instances⾃⾝がinstance metadataのinstance-actionを監視してdrainingする 対策(未対応)

Slide 54

Slide 54 text

これからの話

Slide 55

Slide 55 text

• 解像度1分のCloudWatchのmetricsだとauto scalingが間に合わないことが度々 • 平⽇・休⽇の傾向も考慮するだけでかなり良くなるはず • ⾼解像度のmetricsの使⽤やCloudWatchに依存しないauto scalingも良さそう • 明らかに異常なリクエスト数があっても許容してしまっている • 429を返したい • お客さんのサービスによって使われ⽅が全然違うので異常かどうかの判断が⾮常に難しい • FargateやKubernetesの検証をやれてない • "SRE"と呼ばれる⼈たちが機能開発やら開発環境整備やらもやっている現状 • ⼈が!⾜り!!ない!!!! 課題はたくさん

Slide 56

Slide 56 text

まとめ

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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