본문 바로가기

AWS EKS 실습/EKS Beginner

Autoscaling with HPA and CA

K8S의 Autoscaling은 2가지 형태로 제공된다.   

 

- Horizontal Pod Autoscaler (HPA) : Deployment 또는 replica set에서 Pod를 확장한다. K8S API resource와 controller로 구현되고 Conteroller manager는 각각의 HPA 정의에 지정된 메트릭에 대해 리소스 사용률을 쿼리한다.

리소스 메트릭 API(Pod당 리소스 메트릭) 또는 사용자 지정 메트릭 API에서 메트릭 정보를 가져온다. clarkshim.tistory.com/128

포드와 클러스터 노드의 오토스케일링

쿠버네티스의 스케일링 방안  - 포드에서 실행되는 애플리케이션은 리플리케이션컨트롤러, 레플리카셋, 디플로이먼트 또는 확장 가능한 리소스의 복제본 필드를 늘려서 수동으로 스케일링 가

clarkshim.tistory.com

 

- Cluster Autoscaler (CA) : Kubernets 클러스터 크기를 자동으로 조정하여 모든 Pod가 실행될 Node는 있으나 불필요한 Node는 없도록 하는 구성 요소

 

 

ㅁ Install Kube-Ops-View

 

- Henning Jacobs로 부터 kube-ops-view 설치

- kube-ops-view는 클러스터 설정을 시각적으로 이해하는데 도움이 되는 kubernets cluster에 대한 비주얼적인 방법을 제공한다.

 

ㅇ Helm으로 저장소를 업데이트 한 후, LoadBalancer 서비스 유형을 사용하고 Cluster에서 Node 및 Pod정보를 읽기 위한 읽기 전용 서비스 계정을 위한 RBAC을 생성하여 kube-ops-view를 설치한다.

 

helm install kube-ops-view \
stable\kube-ops-view \
--set service.type=LoadBalancer \
--set rbac.create=True

 

 

 

 

잠시 기다리면 위의 url로 접속하여 정상적으로 kube-ops-view가 아래와 같이 보여진다.

 

 

 

 

 

 

해당 이미지의 설명은 아래와 같다. (IP는 무시하고 위치별 항목이 무엇인지만 확인하면 된다.)

 

 

 

ㅁ Configure Horizontal Pod Autoscaler (HPA)

 

HPA를 구성하기 위해 Metrics Server를 배포한다. Metric Server는 Kubernetes에 내장되어 있는 Autoscaling 파이프라인으로 확장 가능하고 효율적인  컨테이너  리소스 메트릭 소스이다.

 

다음을 사용하여 배포한다.

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.1/components.yaml

 

 

정상적으로 설치가 되면 아래와 같이 메트릭 서버의 상태가 확인이 가능하다.

 

 

 

ㅁ Deploy Sample App

 

TCP Port 80으로 한 서비스를 노출 시키는 애플리케이션을 디플로이한다.

 

이 애플리케이션은 php-apache image에 기반한 Custom-built image이고 index.php page는 계산을 수행하여 CPU 부하를 발생한다.

 

kubectl create deployment php-apache --image=us.gcr.io/k8s-artifacts-prod/hpa-example
kubectl set resources deploy php-apache --requests=cpu=200m
kubectl expose deploy php-apache --port 80

kubectl get pod -l app=php-apache

 

 

ㅇ HPA가 할당된 컨테이너 리소스의 50%가 초과하면 확장되도록 설정한다.

kubectl autoscale deployment php-apache `#The target average CPU utilization` \
    --cpu-percent=50 \
    --min=1 `#The lower limit for the number of pods that can be set by the autoscaler` \
    --max=10 `#The upper limit for the number of pods that can be set by the autoscaler`

 

 

kubectl get hpa에서 보는것 처럼 0~50%로 설저되어 있으며 MINPODS 1, MAXPODS 10으로 설정되어 있는것을 볼 수 있다.

 

새로운 터미널(Cloud9에서)을 띄워 다음 커맨드로 부하를 발생 시킨다.

 

kubectl --generator=run-pod/v1 run -i --tty load-generator --imnage=busybox /bin/sh

http://php-apache에 대해서 while loop를 발생 시킨다.

 

기존의 탭에서 kubectl get hpa -w 로 부하및 Replica의 상태를 모니터링한다.

kubectl get hpa -w

 

 

 

ctrl+c 로 테스트 수행 쉘을 멈추면 HPA가 replicas를 줄이는 것을 확인할 수 있다.

 

 

 

ㅁ Cluster Autoscaler(CA) 구성

 

AWS Cluster Autoscaler는 Auto Scaling Groups과 Integration되어 제공된다. deployment를 위해서는 4가지 다른 옵션과 같이 제공된다.

  - One Auto Scaling group

  - Multiple Auto Scaling group

  - Auto-Discovery

  - Control-Plane Node Setup

 

최소, 최대 및 원하는 용량을 설정하여 Auto Scaling 그룹의 크기를 구성한다. 클러스터를 만들 때 이런한 설정을 3으로 했으며 아래는 어떻게 구성되어 있는지 볼 수 있다. 클러스터 이름을 다르게 설정했다면 Value = 'ekx ~~ ' 부분을 자신이 만든 클러스터 이름으로 변경해서 조회한다.

aws autoscaling \
    describe-auto-scaling-groups \
    --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='eks-newelite-eksctl']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" \
    --output table

 ㅇ 다음으로는 MAXIMUM CAPACITY를 4로 조절한다.

 

# we need the ASG name
export ASG_NAME=$(aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='eks-newelite-eksctl']].AutoScalingGroupName" --output text)

# increase max capacity up to 4
aws autoscaling \
    update-auto-scaling-group \
    --auto-scaling-group-name ${ASG_NAME} \
    --min-size 3 \
    --desired-capacity 3 \
    --max-size 4

# Check new values
aws autoscaling \
    describe-auto-scaling-groups \
    --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='eks-newelite-eksctl']].[AutoScalingGroupName, MinSize, MaxSize,DesiredCapacity]" \
    --output table

 

 

ㅇ 서비스 어카운트를 위한 IAM role 설정

 

현 클러스트 환경의 서비스 어카운트를 위한 IAM roles을 설정한다.

eksctl utils associate-iam-oidc-provider \
  --cluster eks-newelite-eksctl \
  --approve

 

 

 

CA Pod가 Auto Scaling Group과 상호 작용할 수 있도록 서비스 계정에 대한 IAM 정책을 만든다.

mkdir ~/environment/cluster-autoscaler

cat <<EoF > ~/environment/cluster-autoscaler/k8s-asg-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"
        }
    ]
}
EoF

aws iam create-policy   \
  --policy-name k8s-asg-policy \
  --policy-document file://~/environment/cluster-autoscaler/k8s-asg-policy.json

 

 

ㅇ 마지막으로 cluster-autoscaler 서비스 어카운트를 위해 kube-system namespace에 IAM 역할을 생성한다.

 

eksctl create iamserviceaccount \
    --name cluster-autoscaler \
    --namespace kube-system \
    --cluster eks-newelite-eksctl \
    --attach-policy-arn "arn:aws:iam::${ACCOUNT_ID}:policy/k8s-asg-policy" \
    --approve \
    --override-existing-serviceaccounts

 

 

IAM 역할에 대한 Annotation이 제대로 적용되었는지 확인해 본다.

 

kubectl -n kube-system describe sa cluster-autoscaler

 

 

 

ㅇ Cluster Autoscaler (CA) 배포

 

다음과 같은 명령어로 Cluster Autoscaler를 cluster에 배포한다.

 

kubectl apply -f https://www.eksworkshop.com/beginner/080_scaling/deploy_ca.files/cluster-autoscaler-autodiscover.yaml

 

 

 

아래는 cluster-autoscaler-autodiscover.yaml 내용이다.

더보기
# ---
# 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:
      - "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"]
    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:
      serviceAccountName: cluster-autoscaler
      containers:
        - image: k8s.gcr.io/cluster-autoscaler:v1.14.7
          name: cluster-autoscaler
          resources:
            limits:
              cpu: 100m
              memory: 300Mi
            requests:
              cpu: 100m
              memory: 300Mi
          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/eksworkshop-eksctl
            - --balance-similar-node-groups
            - --skip-nodes-with-system-pods=false
          volumeMounts:
            - name: ssl-certs
              mountPath: /etc/ssl/certs/ca-certificates.crt
              readOnly: true
          imagePullPolicy: "Always"
      volumes:
        - name: ssl-certs
          hostPath:
            path: "/etc/ssl/certs/ca-bundle.crt"

CA가 자신의 Pod를 실행중인 노드를 제거하지 못하도록 방지하기 위해 다음 명령을 사용하여 deployment에 cluster-autoscaler.kubernetes.io/safe-to-evict annotation을 추가한다.

kubectl -n kube-system \
    annotate deployment.apps/cluster-autoscaler \
    cluster-autoscaler.kubernetes.io/safe-to-evict="false"

 

 

 

마지막으로 autoscaler image를 업데이트 한다.

 

# we need to retrieve the latest docker image available for our EKS version
export K8S_VERSION=$(kubectl version --short | grep 'Server Version:' | sed 's/[^0-9.]*\([0-9.]*\).*/\1/' | cut -d. -f1,2)
export AUTOSCALER_VERSION=$(curl -s "https://api.github.com/repos/kubernetes/autoscaler/releases" | grep '"tag_name":' | sed -s 's/.*-\([0-9][0-9\.]*\).*/\1/' | grep -m1 ${K8S_VERSION})

kubectl -n kube-system \
    set image deployment.apps/cluster-autoscaler \
    cluster-autoscaler=us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v${AUTOSCALER_VERSION}

 

최종적으로 로그 확인을 한다.

 

kubectl -n kube-system logs -f deployment/cluster-autoscaler

 

ㅁ CA를 통한 Cluster Scale

 

ㅇ Deploy a Sample App

Pod의 ReplicaSet이 1로 설정된 샘플 nginx 애플리케이션을 Deploy 한다.

 

cat <<EoF> ~/environment/cluster-autoscaler/nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-to-scaleout
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        service: nginx
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx-to-scaleout
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 500m
            memory: 512Mi
EoF

kubectl apply -f ~/environment/cluster-autoscaler/nginx.yaml

kubectl get deployment/nginx-to-scaleout

 

 

 

 

ㅇ replicaset 을 10으로 scale-out 한다.

kubectl scale --replicas=10 deployment/nginx-to-scaleout

cluster-autoscaler log를 확인

kubectl -n kube-system logs -f deployment/cluster-autoscaler

 

 

 

kubectl을 사용하여 nodes의 증가 상태를 확인한다.

 

아래는 테스트 완료 후 전체 내용을 삭제하는 shell 이다.

 

kubectl delete -f ~/environment/cluster-autoscaler/nginx.yaml

kubectl delete -f https://www.eksworkshop.com/beginner/080_scaling/deploy_ca.files/cluster-autoscaler-autodiscover.yaml

eksctl delete iamserviceaccount \
  --name cluster-autoscaler \
  --namespace kube-system \
  --cluster eks-newelite-eksctl \
  --wait

aws iam delete-policy \
  --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/k8s-asg-policy

export ASG_NAME=$(aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[? Tags[? (Key=='eks:cluster-name') && Value=='eks-newelite-eksctl']].AutoScalingGroupName" --output text)

aws autoscaling \
  update-auto-scaling-group \
  --auto-scaling-group-name ${ASG_NAME} \
  --min-size 3 \
  --desired-capacity 3 \
  --max-size 3

kubectl delete hpa,svc php-apache

kubectl delete deployment php-apache

kubectl delete pod load-generator

cd ~/environment

rm -rf ~/environment/cluster-autoscaler

kubectl delete -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.1/components.yaml

kubectl delete ns metrics

helm uninstall kube-ops-view

unset ASG_NAME
unset AUTOSCALER_VERSION
unset K8S_VERSION

 

'AWS EKS 실습 > EKS Beginner' 카테고리의 다른 글

Kubernetes access 관리를 위한 IAM Groups 사용  (1) 2021.02.25
Intro to RBAC  (0) 2021.02.24
HEALTH CHECKS 실습 (Liveness Probe/Readiness Probe)  (0) 2021.02.22
Helm으로 nginx 설치  (0) 2021.02.19
Sample Application 배포  (0) 2021.02.18