EKSでオートスケール ~ PodとEC2どちらも~
2019/12/06
はじめに
この記事は Amazon EKS #2 Advent Calendar 2019の6日目の記事です。
今回はEKSでオートスケールに挑戦します。
サービスを保守・運用していく中で、リソースが枯渇してサービスの継続が困難になることは避けたいです。
KubernetesではPod(コンテナ)にリソースを割り当てることができ、リソースが不足すると自動でPodを増やす機能があります。
Horizontal Pod Autoscaler
ただEC2インスタンスのリソースが不足した場合は、Podのオートスケールは機能しません。(リソースがないから。。。)
なので、EC2インスタンスのオートスケールも必要になってきます。
cluster-autoscalerという機能を使ってEC2インスタンスのオートスケールも設定します。
これを設定することで、リソースが必要なときのみEC2インスタンスを作成し、リソースが不要になった場合はEC2インスタンスを自動で削除します。
Architecture
- cluster autoscaler
EC2インスタンスのオートスケールを担当する機能です。 -
kube2iam
PodからAWSリソースを操作するためのIAM権限の管理をするツール。
cluster autoscalerを動かすためのIAM Roleをkube2iamを使って管理します。
kube2iamのデプロイは本記事では説明しません。AWSのKubernetesでサービスを公開する最高の方法~ALB,ACM,Route53の自動作成~こちらを参考にしてください。 -
Metrics Server
クラスタのリソース使用量を集計してくれるツール。Podがオートスケールするために必要。前まではheapsterというツールだったが、HeapsterはKubernetes 1.11でDeprecateされた。 -
Helm
Kubernetesのパッケージマネージャーです。
Metrics Serverをインストールするのに使用します。
やっていく
前提
- EKS Clusterが構築済みであること
構築されていない方はeksctlコマンドを使ってみてください!
Install Helm
README通りにやっていきます。
1 2 3 4 |
$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh $ chmod +x get_helm.sh $./get_helm.sh |
RBACマニフェストを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
cat <<EoF > ./rbac.yaml --- apiVersion: v1 kind: ServiceAccount metadata: name: tiller namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: tiller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: tiller namespace: kube-system EoF |
マニフェストファイルをデプロイしてinitコマンドを実行します。
1 2 3 |
$ kubectl apply -f ~/environment/rbac.yaml $ helm init --service-account tiller |
これでHelmのインストールは完了です。
Install Metrics Server
Metrics Serverのインストールはhelmコマンドで一発でできます。
1 2 3 4 5 |
$ helm install stable/metrics-server \ --name metrics-server \ --version 2.0.4 \ --namespace kube-system |
OK!
https://github.com/kubernetes-incubator/metrics-server
https://eksworkshop.com/scaling/deploy_hpa/
cluster autoscaler
Create IAM Role
まずはcluster autoscalerに割り当てるポリシーを記載したclusterAutoscale-iam-policy.json
ファイルを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "autoscaling:DescribeAutoScalingGroups", "autoscaling:DescribeAutoScalingInstances", "autoscaling:DescribeTags", "autoscaling:DescribeLaunchConfigurations", "autoscaling:SetDesiredCapacity", "autoscaling:TerminateInstanceInAutoScalingGroup" ], "Resource": "*" } ] } |
次にcluster-autoscalerという名前のRoleを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
export NODE_INSTANCE_ROLE_ARN=$(aws iam list-roles --query "Roles[?contains(RoleName,`NodeInstanceRole`)].[Arn][]" --output text) cat << EOF | jq > config/pod-role-trust-policy.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" }, { "Effect": "Allow", "Principal": { "AWS": "${NODE_INSTANCE_ROLE_ARN}" }, "Action": "sts:AssumeRole" } ] } EOF $ aws iam create-role \ --role-name cluster-autoscaler \ --assume-role-policy-document file://pod-role-trust-policy.json $ CLUSTER_AUTOSCALER_ARN=$(aws iam create-policy --policy-name clusterAutoscaler-iam-policy --policy-document file://clusterAutoscale-iam-policy.json --query "Policy.[Arn]" --output text) $ aws iam attach-role-policy --role-name cluster-autoscaler --policy-arn $CLUSTER_AUTOSCALER_ARN |
AutoScalingGroupにタグを付与
cluster autoscalerが自動でAutoScalingGroupを見つけるために、AutoScalingGroupにタグを付与します。
Nameがk8s.io/cluster-autoscaler/enabled
でValueはtrue
にします。
もう1つ設定します。
k8s.io/cluster-autoscaler/<Your Cluster Name>
cluster autoscalerのデプロイ
まずはymlファイルをダウンロードします。
1 2 |
$ wget https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-one-asg.yaml |
cluster-autoscaler-one-asg.yamlファイルの中を3箇所変更します。
Deploymentのspecのmetadataにannotationsを追加します。これを追加することでAutoScalintGroupの操作をする権限をPodに付与します。kube2iamの機能になります。
<Arn of cluster-autoscaler Role>
は IAMロールの作成で作成したcluster-autoscalerロールのArnです。
1 2 3 4 5 6 7 8 9 10 11 12 |
spec: replicas: 1 selector: matchLabels: app: cluster-autoscaler template: metadata: labels: app: cluster-autoscaler annotations: iam.amazonaws.com/role: <Arn of cluster-autoscaler Role> |
commandの引数の--nodes
をコメントアウトします。
これはAutoScalingGroupのミニマムとマックスを手動で設定する場合です。今回はAutoScalingGroupにタグを付与したため、自動で設定されます。
複数のNODEGROUPを指定したい場合は,--nodes引数にそれぞれ設定が必要です.
1 2 3 4 5 6 7 8 9 |
command: - ./cluster-autoscaler - --v=4 - --stderrthreshold=info - --cloud-provider=aws - --skip-nodes-with-local-storage=false # - --nodes=1:5:NODEGROUP_NAME_1 # - --nodes=1:5:NODEGROUP_NAME_2 |
EC2インスタンスとKubernetes APIが通信するときに使用するcrtファイルを変更します。OSにAmazon Linux 2を使っている方は、/etc/ssl/certs/ca-bundle.crt
を記述してください。
めちゃめちゃハマりましたが、ちゃんとドキュメントには書いてました。ドキュメント大事。
1 2 3 4 5 6 |
volumes: - name: ssl-certs hostPath: # path: "/etc/ssl/certs/ca-certificates.crt" path: "/etc/ssl/certs/ca-bundle.crt" |
これで準備できました!
デプロイしましょう!
1 2 |
$ kubectl apply -f cluster-autoscaler-one-asg.yaml |
エラーログが出ていなかったら成功です!
1 2 |
$ kubectl logs -n kube-system cluster-autoscaler-XXXXX |
試してみる
それではサンプルアプリをデプロイしてオートスケールを試してみましょう!
下記のymlファイルをデプロイするとDeployment, Service, HorizontalPodAutoscalerが作られます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-test labels: name: nginx-test namespace: default spec: replicas: 1 selector: matchLabels: name: nginx-test template: metadata: labels: name: nginx-test spec: containers: - name: nginx-test image: nginx:stable-alpine ports: - name: nginx-port containerPort: 80 resources: requests: cpu: 100m memory: 30Mi limits: cpu: 100m memory: 30Mi dnsConfig: nameservers: - 8.8.8.8 --- kind: Service apiVersion: v1 metadata: name: nginx-test labels: name: nginx-test namespace: default spec: selector: name: nginx-test ports: - name: nginx-port port: 80 targetPort: 80 protocol: TCP type: "NodePort" --- apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: nginx-test-scale namespace: default spec: scaleTargetRef: # ここでautoscale対象となるscaled resource objectを指定 apiVersion: extensions/v1beta1 kind: Deployment name: nginx-test minReplicas: 1 # 最小レプリカ数 maxReplicas: 10 # 最大レプリカ数 metrics: - type: Resource resource: name: cpu targetAverageUtilization: 5 # CPU使用率が常に5%になるように指定 |
作ったPodに対してGolangで負荷をかけてみます!
(Golangよく分かんないよという方はkubectl execでPodに接続し て yes > /dev/null
コマンドでも負荷かけれます。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package main import ( "net/http" "sync" "log" "time" ) func main() { url := "http://192.168.100.100:30534/" // アクセスするURLだよ! maxConnection := make(chan bool,1000) // 同時に並列する数をしていできるよ!(第二引数) wg := &sync.WaitGroup{} // 並列処理が終わるまでSleepしてくれる便利なやつだよ! count := 0 // いくつアクセスが成功したかをアカウントするよ! start := time.Now() // 処理にかかった時間を測定するよ! for maxRequest := 0; maxRequest < 50000; maxRequest ++{ // 10000回リクエストを送るよ! wg.Add(1) // wg.add(1)とすると並列処理が一つ動いていることを便利な奴に教えるよ! maxConnection <- true // ここは並列する数を抑制する奴だよ!詳しくはググって! go func() { // go func(){/*処理*/}とやると並列処理を開始してくれるよ! defer wg.Done() // wg.Done()を呼ぶと並列処理が一つ終わったことを便利な奴に教えるよ! resp, err := http.Get(url) // GETリクエストでアクセスするよ! if err != nil { // err ってのはエラーの時にエラーの内容が入ってくるよ! return // 回線が狭かったりするとここでエラーが帰ってくるよ! } defer resp.Body.Close() // 関数が終了するとなんかクローズするよ!(おまじない的な) count++ // アクセスが成功したことをカウントするよ! <-maxConnection // ここは並列する数を抑制する奴だよ!詳しくはググって! }() } wg.Wait() // ここは便利な奴が並列処理が終わるのを待つよ! end := time.Now() // 処理にかかった時間を測定するよ! log.Printf("%d 回のリクエストに成功しました!\n", count) // 成功したリクエストの数を表示してくれるよ! log.Printf("%f 秒処理に時間がかかりました!\n",(end.Sub(start)).Seconds()) //何秒かかったかを表示するよ! } |
では負荷をかけます。
1 2 |
$ go run stress.go |
素晴らしい。。。
スクショ忘れましたが、EC2インスタンスの数もAutoScalingGroupのMaxまで増えました!
まとめ
EKS最高!
EKSで何でもできるので、お仕事ください!w
References
kubernetes/autoscaler
https://medium.com/@alejandro.millan.frias/cluster-autoscaler-in-amazon-eks-d9f787176519
Terraformで構築したEKSにHelmでHPA、CA、ALB Ingressまで導入 - Qiita
k8s上でオートスケールするWebアプリケーションを動かす場合、DeploymentとServiceに加え、Ingress、Horizontal Pod Autoscaler (HPA) まで作成することになります。
また...