- Horizontal Pod Autoscaling이란
- 동작 원리
- 메트릭 서버 구성
- Horizontal Pod Autoscaling 실습
1. Horizontal Pod Autoscaling 이란
https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
해석하면 '수평적 파드 자동확장' 이다.
말 그대로 파드의 개수를 증가시켜 확장하는 것을 말한다.
서버에 수많은 요청이 들어오면 그 요청을 처리하기 위해 파드의 리소스가 많이 소모되는데 파드에 리소스 제한이 걸려있다면 많은 요청을 모두 처리하기 힘들다.
이를 메트릭 서버를 통해 파드의 리소스 사용량을 확인하고 일정 수준을 넘어서면 파드의 개수를 자동으로 확장하여 요청이 분산되도록 한다.
이것이 파드 오토스케일링의 목적이다.
확장된 파드는 시간이 지나면 자동으로 축소되며 파드 수에 대한 모든 관리를 HPA 리소스 오브젝트가 수행한다.
2. 동작 원리
- 메트릭 서버가 클러스터 및 파드의 메트릭 정보를 수집한다.
- Horizontal Pod Autoscaler(HPA) 리소스 오브젝트를 통해 오토스케일링 정책을 설정한다.
- 메트릭 서버로 부터 받은 파드의 메트릭 정보와 HPA 정책 정보를 비교하여 기준에 부합되면 HPA가 디플로이먼트 혹은 레플리카셋의 스케일 정보를 변경하도록 지시한다.
- Kubernetes는 스케일 정보를 바탕으로 파드를 생성하거나 제거하는 작업을 수행한다.
- 주기적으로 제공되는 메트릭 정보를 바탕으로 파드의 개수를 유지하거나 변경하도록 관리한다.
3. 메트릭 서버 구성
메트릭 서버는 CPU 사용률, 메모리 사용률, 네트워크 입출력 등 클러스터와 파드로 부터 메트릭 정보를 수집한다.
HPA를 구성하고 작업이 수행되도록 하기 위해서는 메트릭 서버 구성은 반드시 필요한 작업이다.
https://github.com/kubernetes-sigs/metrics-server?tab=readme-ov-file#readme
메트릭 서버를 구성하기 위해 각 리소스를 설치한다.
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 파일을 보면 메트릭 서버가 제대로 실행되지 않는다.
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
kubectl top 명령은 각 오브젝트들의 리소스 사용량을 확인하는 명령이다.
메트릭 서버는 이러한 메트릭 정보를 수집하여 전달함으로 HPA가 파드의 확장/축소를 결정하게 된다.
4. Horizontal Pod Autoscaling 실습
https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/
공식 문서에서 제공하는 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"
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 |