DevOps 잡다구리/DevOps Tools

[Devops] EKS auto scaling 하기 by cluster autoscaler

WhiteGoblin 2024. 4. 23. 12:59
반응형

 

 

클러스터를 운영하는 이유중 하나는 리소스의 효율적인 운용이지 않으까 싶습니다. 

 

그래서 저는 아직 실감을 잘하지 못했지만 차후 EKS 에서 pod 를 scaling 할때 다양한 방법으로 automatically 하게 배치할 수 있지만 제가 한 방법에 대해서 공유 하고자 합니다. 

 

우선 저는 HPA ( Horizontal Pod Autoscaling ) 을 활용해서 pod 가 사용하는 resource 에 따라서 pod 를 스케일링 중이었습니다. 

 

CPU , Memory usage 를 기반으로 pod 를 autoscaling 하게 되는데 문제는 이 과정에서 node 가 허용 할 수 있는 범위를 벗어나게 되면 결과적으로 pending 상태의 pod 들이 노드에 배치 되지 못한체 돌아가게 된다. 

그렇기에 이 경우에는 cluster 의 node 를 scale up 해야 한다. 

 

manual 하게 eks 의 desired node 를 변경할 수 있지만 간단하게 이를 자동으로 해주는 Cluster autoscaler 를 활용하고자 한다. 

 

https://github.com/kubernetes/autoscaler

 

GitHub - kubernetes/autoscaler: Autoscaling components for Kubernetes

Autoscaling components for Kubernetes. Contribute to kubernetes/autoscaler development by creating an account on GitHub.

github.com

 

eksctl, wget, aws, kubectl 을 필수적으로 필요합니다.

 

1. AWS policy 추가하기 

2. eks oidc provider 추가하기 

3. eks iam service account 추가하기 

4. cluster autoscaler deploy 하기 


이렇게 진행해보았습니다. 

 

1. AWS Policy 추가하기 

우선 service account 를 만들기 전에 해당 service account 가 필요로 하는 policy 를 추가해줄 필요가 있다. 

 

* cluster-autoscaler-policy.json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:DescribeLaunchConfigurations",
                "autoscaling:DescribeTags",
                "autoscaling:SetDesiredCapacity",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "ec2:DescribeLaunchTemplateVersions"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

 

 

보시면 알 수 있듯이 autoscaling group , instance 에 대한 정보들이 필요하고 이후 아마 SetDesiredCapacity 를 조절할 것으로 보인다. Terminate 이 있는것으로 보아서 node autoscaling group 이 scale down 할때를 위한 policy 로 보인다. 

 

aws configure 를 통해서 aws credential 을 설정 한 다음에 

aws iam create-policy \
    --policy-name AmazonEKSClusterAutoscalerPolicy \
    --policy-document file://cluster-autoscaler-policy.json

 

이렇게 진행하면 policy 는 준비가 되었습니다.

 

2. eks oidc provider 추가하기

eks 를 설치할 때 자동으로 추가 되는 경우도 있지만 그렇지 않은 경우도 있기에 추가한 섹션입니다. 

eksctl utils associate-iam-oidc-provider --region=<REGION> --cluster=<CLUSTER_NAME> --approve\n

 

우와 같이 추가 하게 되면 aws console -> EKS 로 가서 cluster info 에 oidc 가 세팅되어 있음을 확인 할 수 있습니다. 

 

3. eks iam service account 추가하기  

 이제 이러한 policy 를 사용할 service account 를 추가 해줍니다. 

eksctl create iamserviceaccount \
  --cluster=<CLUSTER_NAME> \
  --namespace=kube-system \
  --name=cluster-autoscaler \
  --attach-policy-arn=<POLICY_ARN> \
  --override-existing-serviceaccounts \
  --approve

 

4. cluster autoscaler deploy 하기 

 이제 Cluster autoscaler 를 배포 해보겠습니다.
공식 문서에는 kubectl apply -f 를 통해서 바로 배포 하는것을 설명하지만 저는 우선 다운 받아서 제가 필요로 하는 옵션들을 변경하고자 합니다. 

 

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
  name: cluster-autoscaler
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["events", "endpoints"]
    verbs: ["create", "patch"]
  - apiGroups: [""]
    resources: ["pods/eviction"]
    verbs: ["create"]
  - apiGroups: [""]
    resources: ["pods/status"]
    verbs: ["update"]
  - apiGroups: [""]
    resources: ["endpoints"]
    resourceNames: ["cluster-autoscaler"]
    verbs: ["get", "update"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["watch", "list", "get", "update"]
  - apiGroups: [""]
    resources:
      - "namespaces"
      - "pods"
      - "services"
      - "replicationcontrollers"
      - "persistentvolumeclaims"
      - "persistentvolumes"
    verbs: ["watch", "list", "get"]
  - apiGroups: ["extensions"]
    resources: ["replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["policy"]
    resources: ["poddisruptionbudgets"]
    verbs: ["watch", "list"]
  - apiGroups: ["apps"]
    resources: ["statefulsets", "replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses", "csinodes", "csidrivers", "csistoragecapacities"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["batch", "extensions"]
    resources: ["jobs"]
    verbs: ["get", "list", "watch", "patch"]
  - apiGroups: ["coordination.k8s.io"]
    resources: ["leases"]
    verbs: ["create"]
  - apiGroups: ["coordination.k8s.io"]
    resourceNames: ["cluster-autoscaler"]
    resources: ["leases"]
    verbs: ["get", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["create", "list", "watch"]
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"]
    verbs: ["delete", "get", "update", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    app: cluster-autoscaler
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cluster-autoscaler
  template:
    metadata:
      labels:
        app: cluster-autoscaler
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '8085'
    spec:
      priorityClassName: system-cluster-critical
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534
        fsGroup: 65534
        seccompProfile:
          type: RuntimeDefault
      serviceAccountName: cluster-autoscaler
      containers:
        - image: registry.k8s.io/autoscaling/cluster-autoscaler:v1.26.2
          name: cluster-autoscaler
          resources:
            limits:
              cpu: 100m
              memory: 600Mi
            requests:
              cpu: 100m
              memory: 600Mi
          command:
            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --expander=least-waste
            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/<YOUR CLUSTER NAME>
          volumeMounts:
            - name: ssl-certs
              mountPath: /etc/ssl/certs/ca-certificates.crt # /etc/ssl/certs/ca-bundle.crt for Amazon Linux Worker Nodes
              readOnly: true
          imagePullPolicy: "Always"
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
            readOnlyRootFilesystem: true
      volumes:
        - name: ssl-certs
          hostPath:
            path: "/etc/ssl/certs/ca-bundle.crt"

 

다운 받으면 위와 같은 파일이 있습니다 , 다른 데이터의 경우 필요시 조정 및 수정 하면 되고 우리의 경우 클러스터의 이름을 변경 해주겠습니다. 
<YOUR CLUSTER NAME> 이라는 항목을 찾아서 aws console 에 저장되어 있는 EKS 의 이름으로 변경 해주고 나서 deploy 합니다. 

 

kubectl apply -f cluster-autoscaler-autodiscover.yaml

 

그리고 deployment 에서 safe-to-evict 을 사용해주기 위해서 patch 해줍니다.

 

kubectl patch deployment cluster-autoscaler \\n  -n kube-system \\n  -p '{"spec":{"template":{"metadata":{"annotations":{"cluster-autoscaler.kubernetes.io/safe-to-evict": "false"}}}}}'

 

이렇게 해주면 필요한 준비는 다 마치게 되었습니다.

 

이후 저는 pod 를 강제로 늘려서 1 -> 30 늘린 결과 정상적으로 노드가 늘어나고 해당 node 에 pod 가 배치 되는것을 확인 했습니다. 

 

** 결론 ** 

cluster autoscaler 에 대해서 전부 다 이해한것은 아니지만 그래도 사용하는 방법에 대해서는 확인하게 되었습니다. 
로그를 확인 해보면 cluster autoscaler 는 CPU , Mem, 서비스, pod 을 확인하고 불필요한 노드인지 아닌지 판단하고 그에 따라서 node group 을 조정하게 됩니다. 

 

반응형