Kubernetes

Kubernetes - Metrics Server, PodAutoScaling

사실 나도 모름 2024. 2. 3. 02:06
  1. Horizontal Pod Autoscaling이란
  2. 동작 원리
  3. 메트릭 서버 구성
  4. Horizontal Pod Autoscaling 실습

1. Horizontal Pod Autoscaling 이란

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/

 

Horizontal Pod Autoscaling

In Kubernetes, a HorizontalPodAutoscaler automatically updates a workload resource (such as a Deployment or StatefulSet), with the aim of automatically scaling the workload to match demand. Horizontal scaling means that the response to increased load is to

kubernetes.io

 

 

해석하면 '수평적 파드 자동확장' 이다.

말 그대로 파드의 개수를 증가시켜 확장하는 것을 말한다.

서버에 수많은 요청이 들어오면 그 요청을 처리하기 위해 파드의 리소스가 많이 소모되는데 파드에 리소스 제한이 걸려있다면 많은 요청을 모두 처리하기 힘들다.

이를 메트릭 서버를 통해 파드의 리소스 사용량을 확인하고 일정 수준을 넘어서면 파드의 개수를 자동으로 확장하여 요청이 분산되도록 한다.

이것이 파드 오토스케일링의 목적이다.

확장된 파드는 시간이 지나면 자동으로 축소되며 파드 수에 대한 모든 관리를 HPA 리소스 오브젝트가 수행한다.

 

 

 

 


2. 동작 원리

https://kubernetes.io/docs/tasks/debug/debug-cluster/resource-metrics-pipeline/#metrics-server

 

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/

 

  1. 메트릭 서버가 클러스터 및 파드의 메트릭 정보를 수집한다.
  2. Horizontal Pod Autoscaler(HPA) 리소스 오브젝트를 통해 오토스케일링 정책을 설정한다.
  3. 메트릭 서버로 부터 받은 파드의 메트릭 정보와 HPA 정책 정보를 비교하여 기준에 부합되면 HPA가 디플로이먼트 혹은 레플리카셋의 스케일 정보를 변경하도록 지시한다.
  4. Kubernetes는 스케일 정보를 바탕으로 파드를 생성하거나 제거하는 작업을 수행한다.
  5. 주기적으로 제공되는 메트릭 정보를 바탕으로 파드의 개수를 유지하거나 변경하도록 관리한다.

 

 


3. 메트릭 서버 구성

메트릭 서버는 CPU 사용률, 메모리 사용률, 네트워크 입출력 등 클러스터와 파드로 부터 메트릭 정보를 수집한다.

HPA를 구성하고 작업이 수행되도록 하기 위해서는 메트릭 서버 구성은 반드시 필요한 작업이다.

 

https://github.com/kubernetes-sigs/metrics-server?tab=readme-ov-file#readme

 

GitHub - kubernetes-sigs/metrics-server: Scalable and efficient source of container resource metrics for Kubernetes built-in aut

Scalable and efficient source of container resource metrics for Kubernetes built-in autoscaling pipelines. - GitHub - kubernetes-sigs/metrics-server: Scalable and efficient source of container reso...

github.com

 

 

메트릭 서버를 구성하기 위해 각 리소스를 설치한다.

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

다양한 리소스를 실행한다.

 

시스템 메트릭을 수집하려면 여러 권한이 필요하다.

그래서 ServiceAccount, ClusterRole, ClusterRoleBinding, Service, Deployment, ApiService 등 다양한 리소스들이 생성되어 시스템 메트릭을 수집한다.

 

아래는 우리가 실행한 yaml 파일의 내용이다.

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
    rbac.authorization.k8s.io/aggregate-to-admin: "true"
    rbac.authorization.k8s.io/aggregate-to-edit: "true"
    rbac.authorization.k8s.io/aggregate-to-view: "true"
  name: system:aggregated-metrics-reader
rules:
- apiGroups:
  - metrics.k8s.io
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
rules:
- apiGroups:
  - ""
  resources:
  - nodes/metrics
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server-auth-reader
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server:system:auth-delegator
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:metrics-server
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: metrics-server
  strategy:
    rollingUpdate:
      maxUnavailable: 0
  template:
    metadata:
      labels:
        k8s-app: metrics-server
    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=10250
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
        - --kubelet-use-node-status-port
        - --metric-resolution=15
        - --kubelet-insecure-tls
        image: registry.k8s.io/metrics-server/metrics-server:v0.7.0
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /livez
            port: https
            scheme: HTTPS
          periodSeconds: 10
        name: metrics-server
        ports:
        - containerPort: 10250
          name: https
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /readyz
            port: https
            scheme: HTTPS
          initialDelaySeconds: 20
          periodSeconds: 10
        resources:
          requests:
            cpu: 100m
            memory: 200Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 1000
          seccompProfile:
            type: RuntimeDefault
        volumeMounts:
        - mountPath: /tmp
          name: tmp-dir
      hostNetwork: true
      nodeSelector:
        kubernetes.io/os: linux
      priorityClassName: system-cluster-critical
      serviceAccountName: metrics-server
      volumes:
      - emptyDir: {}
        name: tmp-dir
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  labels:
    k8s-app: metrics-server
  name: v1beta1.metrics.k8s.io
spec:
  group: metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: true
  service:
    name: metrics-server
    namespace: kube-system
  version: v1beta1
  versionPriority: 100

 

 

 

하지만 우리가 실행한 yaml 파일을 보면 메트릭 서버가 제대로 실행되지 않는다.

메트릭 서버의 READY 상태가 0/1 이다.
원인을 알아보면 Readiness Probe의 Healthy 체크가 실패했다.

 

Readiness Probe는 파드가 실행될 준비가 되었는지 Healthy 체크를 하는 역할을 한다.

실패한 원인은 메트릭 서버가 안전하게 시스템 메트릭을 수집하기 위해 TLS 인증서를 사용하는데 이 인증서가 없어서 요청을 보낼 수 없는 것이다.

우리는 인증을 위한 과정을 알아보기 위한 것이 아니니 일단 메트릭 서버 파드의 설정을 변경하여 TLS 통신을 수행하지 않도록 한다.

 

메트릭 서버의 Deployment 명세를 편집한다.

kubectl edit deployments.apps -n kube-system metrics-server

 

 

Deployment 설정에서 다음 플래그를 추가한다.

--kubelet-insecure-tls

메트릭 서버가 실행된다.

 

 

위와 같이 메트릭 서버가 실행된다면 다음 명령이 수행되어야 한다.

kubectl top node
kubectl top pod

top 명령 결과

 

kubectl top 명령은 각 오브젝트들의 리소스 사용량을 확인하는 명령이다.

메트릭 서버는 이러한 메트릭 정보를 수집하여 전달함으로 HPA가 파드의 확장/축소를 결정하게 된다.

 

 

 


4. Horizontal Pod Autoscaling 실습

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/

 

HorizontalPodAutoscaler Walkthrough

A HorizontalPodAutoscaler (HPA for short) automatically updates a workload resource (such as a Deployment or StatefulSet), with the aim of automatically scaling the workload to match demand. Horizontal scaling means that the response to increased load is t

kubernetes.io

 

 

공식 문서에서 제공하는 yaml 파일을 그대로 사용한다.

 

Deployment

다음 명령을 실행한다.

kubectl apply -f https://k8s.io/examples/application/php-apache.yaml

 

 

위 yaml 파일의 명세는 다음과 같다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  selector:
    matchLabels:
      run: php-apache
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - name: php-apache
        image: registry.k8s.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
  labels:
    run: php-apache
spec:
  ports:
  - port: 80
  selector:
    run: php-apache

 

 

HorizontalPodAutoscaler (HPA)

이번에는 HPA를 생성한다.

다음 명령을 실행하거나 yaml 파일로 구성한다.

kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10

 

 

yaml 파일의 명세는 다음과 같다.

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  creationTimestamp: null
  name: php-apache
spec:
  maxReplicas: 3
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  targetCPUUtilizationPercentage: 50
status:
  currentReplicas: 1
  desiredReplicas: 1

 

 

우선 세션을 하나 더 생성하여 오토 스케일링이 어떻게 실행되고 변화하는지 확인하기 위해 아래 명령을 실행한다.

kubectl get hpa php-apache --watch

 

 

이제 파드에 부하를 발생시켜 리소스 사용량을 증가시켜 보자.

kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

계속 HTTP 요청을 보낸다.

 

Ctrl + C를 눌러 HTTP 요청을 중단한다.

발생한 부하율과 REPLICAS를 확인하면 파드의 개수가 증가한 것을 볼 수 있다.

부하 발생을 중단한 후 시간이 조금 지나면 다시 파드가 축소된다.

부하율과 파드의 개수 변화

 

 

위에서 살펴본 HPA는 apiVersion이 autoscaling/v1으로 되어있다.

apiVersion이 autoscaling/v2로 지정하면 더 다양하고 세밀한 오토스케일 정책을 생성할 수 있다.

 

다음 명령을 실행하고 열어본다.

kubectl get hpa php-apache -o yaml > /tmp/hpa-v2.yaml

 

 

불필요한 부분을 제거하고 표시하면 다음과 같다.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  maxReplicas: 3
  metrics:
  - resource:
      name: cpu
      target:
        averageUtilization: 50
        type: Utilization
    type: Resource
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
status:
  currentMetrics:
  - resource:
      current:
        averageUtilization: 106
        averageValue: 213m
      name: cpu
    type: Resource
  currentReplicas: 3
  desiredReplicas: 3
  lastScaleTime: "2024-02-02T16:43:57Z"

 

 

주요 차이를 보자면 targetCPUUtilizationPercentage라는 필드가 metrics라는 필드로 대체되었다.

 

metrics 하위 필드들의 설정은 다음과 같이 다양하게 설정할 수 있다.

# 파드로 들어오는 초당 트래픽으로 제어
type: Pods
pods:
  metric:
    name: packets-per-second
  target:
    type: AverageValue
    averageValue: 1k
    
    
# 쿠버네티스 오브젝트로 들어오는 초당 트래픽으로 제어
type: Object
object:
  metric:
    name: requests-per-second
  describedObject:
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    name: main-route
  target:
    type: Value
    value: 2k


# 구체적인 지표(HTTP GET 요청)로 제어
type: Object
object:
  metric:
    name: http_requests
    selector: {matchLabels: {verb: GET}}
  describedObject:
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    name: main-route
  target:
    type: Value
    value: 2k


# 쿠버네티스 오브젝트가 아닌 외부 객체를 통해 제어
- type: External
  external:
    metric:
      name: queue_messages_ready
      selector:
        matchLabels:
          queue: "worker_tasks"
    target:
      type: AverageValue
      averageValue: 30

 

 

위에서 실습한 HPA 오브젝트를 autoscaling/v2로 변경하여 사용하면 다음과 같다.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

 

 

파드의 확장과 축소에 대한 설정도 behavior 필드를 통해 변경이 가능하다.

자세한 내용은 공식 문서의 설명을 읽어보면 도움이 될 것이다.

 

이와 같이 파드 오토스케일 기능을 통해 서버의 가용성을 증가시키고 요청에 안정적으로 대응할 수 있는 시스템을 구축할 수 있다.

'Kubernetes' 카테고리의 다른 글

Kubernetes - ETCD backup and restore  (0) 2024.03.04
Kubernetes - Network Policy  (0) 2024.03.04
Kubernetes 기초 - Helm(3)  (0) 2024.01.30
Kubernetes 기초 - Helm(2)  (0) 2024.01.27
Kubernetes 기초 - Helm(1)  (0) 2024.01.25