Kubernetes는 HPA(Horizontal Pod Autoscaling), VPA(Vertical Pod Autoscaling)이라는 Pod 자동 확장 기능을 제공해 필요에 따라 Pod의 수를, 혹은 리소스 자체를 자동으로 확장할 수 있는 기능을 제공하고 있습니다.
이 기능들의 특징은 자동확장을 메트릭, 즉 CPU 사용률과 같은 수치를 기준으로 사용한다는 것인데요.
그렇다면 자동확장 기능이 올바르게 작동하기 위해서는 메트릭을 실시간으로, 그리고 안정적으로 확보하는 것이 중요할 것입니다.
Kubernetes에서 이 역할을 하는 것이 바로 Metric-server입니다.
Metric-server는 Kubernetes 내에 존재하는 Pod의 메트릭을 실시간으로 수집해 kube-api 서버에 안정적으로 전달하는 역할을 합니다.
이번 포스팅에서는 이 metric-server를 설치하는 방법부터 metric-server의 디자인, 거대한 클러스터 환경 등 다양한 환경에서 metric-server를 잘 사용하는 방법까지 알아보도록 하겠습니다.
1. Metrics Server 디자인
Metrics Server는 Kubernetes의 Autoscaling 기능을 위한 메트릭 파이프라인 리소스입니다.
중요한 것은 Metric Server가 수집하는 메트릭의 목적이 Autoscaling 기능의 구현이라는 것인데요.
보통 메트릭은 시스템의 상태를 체크하거나 모니터링하는데 사용되기 떄문에 이 같은 활용은 이질적으로 느껴집니다. 모니터링 용도로 metrics server를 사용할 수는 없을까요?
하지만 Metrics server는 수집한 메트릭을 kube-api 서버로 보내기 때문에 위와 같은 목적으로 사용하면 안됩니다.
만약 모니터링 목적의 메트릭 수집을 원한다면 kubelet의 /metrics/resources 엔드포인트에서 직접 수집하는 것이 더 효율적입니다.
metrics server는 kube-api 서버와 각 Node에서 돌아가는 kubelet 프로세스 사이에서 메트릭을 안전하게 전달하는 역할을 합니다.
위 그림을 보면
1. cAdvisor가 Pod내 Container들의 Metrics을 수집 ->
2. kubelet이 cAdvisor가 노출한 메트릭을 수집 ->
3. Metrics server가 kubelet이 노출한 메트릭을 수집 ->
4. kube-api 서버가 Metrics server가 노출한 메트릭을 수집
순서로 파이프라인을 따라 메트릭이 이동하는 것을 볼 수 있습니다. 최종적으로 메트릭은 사용자의 kubectl top 명령어나 HPA, VPA 리소스에 사용됩니다.
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq 명령어를 통해 실제 api 서버에서 돌아온 응답 컨텐츠를 볼 수 있습니다.
2. Metrics server 설치
GKE, EKS와 같은 Managed Kuberentes 환경이라면 Metrics server가 설치되어 있을 수도 있지만 직접 Kuberenetes를 배포하는 Self-hosted 환경에서는 Metrics server를 직접 설치해야 합니다.
다음은 Document에서 밝힌 Metrics server를 설치하기 위한 Requirements입니다.
- The kube-apiserver must enable an aggregation layer.
- Nodes must have Webhook authentication and authorization enabled.
- Kubelet certificate needs to be signed by cluster Certificate Authority (or disable certificate validation by passing --kubelet-insecure-tls to Metrics Server)
- Container runtime must implement a container metrics RPCs (or have cAdvisor support)
- Network should support following communication:
- Control plane to Metrics Server. Control plane node needs to reach Metrics Server's pod IP and port 10250 (or node IP and custom port if hostNetwork is enabled). Read more about control plane to node communication.
- Metrics Server to Kubelet on all nodes. Metrics server needs to reach node address and Kubelet port. Addresses and ports are configured in Kubelet and published as part of Node object. Addresses in .status.addresses and port in .status.daemonEndpoints.kubeletEndpoint.port field (default 10250). Metrics Server will pick first node address based on the list provided by kubelet-preferred-address-types command line flag (default InternalIP,ExternalIP,Hostname in manifests).
대부분의 requirements들이 kubeadm이나 kubespray 등의 bootstarap 도구를 사용해 kubernetes를 배포한다면 무리없이 충족시킬 수 있는 조건들입니다.
Metric server의 설치는 아래 명령어를 사용합니다.
1
|
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
|
cs |
다만 kubelet과 metrics server가 tls 통신을 주고받기 위한 CA 인증서를 신뢰하는 과정을 수행하지 않았으므로 그대로 배포하면 x509 에러가 발생합니다.
프로덕션 환경에서는 CA 인증서를 신뢰하는 과정을 수행해야 겠지만 현재는 테스트 과정이므로 CA 인증서를 확인하지 않도록 Deployment의 파라미터를 변경하겠습니다.
위와 같이 metrics server Deployment의 metrics server 컨테이너에서 spec.containers.args 란에 "--kubelet-insecure-tls"를 추가하면 더 이상 kubelet의 CA 인증서를 확인하지 않습니다.
kubectl top 명령어로 metrics server가 정상적으로 동작하고 있는지 확인할 수 있습니다.
3. Metrics-server를 더 잘 이용하기
3-1. High availability of Metrics server
Metrics server는 기본적으로 Deployment로 배포되지만 1개의 Replica로 배포되기 때문에 Node failure, Pod failure 등 장애 상황이 발생하면 이에 대응할 수 있는 방법이 없습니다.
이럴 경우 Kubernetes에서 HPA,VPA 등 메트릭을 이용하는 리소스의 장애가 발생할 수도 있는데요.
이에 대비하여 Metrics server를 HA(High Availability)로 구성할 수 있습니다.
Metrics server의 HA 구성은 아래 명령어로 배포할 수 있습니다. HA 구성을 배포하기 위해서는 Metrics server pod를 스케쥴할 수 있는 최소 2대의 Node가 필요합니다.
1
|
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/high-availability.yaml
|
cs |
HA 구성 yaml 매니페스트와 기존 yaml 매니페스트의 차이점을 살펴보겠습니다.
가장 먼저 metrics-server Deployment의 Replica가 2로 늘어나 있는 것을 확인할 수 있습니다. metrics server pod를 2대로 유지해 더 가용성 있는 구조가 되었습니다.
metrics-server Deployment의 affinity 속성이 추가되었습니다. podAntiAffinity 속성이 추가되어 metrics-server pod끼리는 같은 Node에 스케쥴링되지 않도록 변경되었습니다.
이렇게 함으로써 Node failure 시 Metrics server pod가 같은 Node에 몰려 있어 장애가 발생하는 상황을 방지할 수 있게 되었습니다.
마지막으로 PodDistruptionBudget 오브젝트가 추가되었습니다. PDB는 Pod가 최소로 유지할 개수를 명시하는 오브젝트로 metrics-server의 PDB는 최소 1개의 pod를 남겨두도록 설정하고 있습니다.
이를 통해 Node drain이나 maintenance같은 event 발생 시에도 모든 pod가 terminating될 염려 없이 최소 1개의 pod는 가동을 보장할 수 있게 되었습니다.
Document에서는 HA Metrics server의 효율적인 사용을 위해서는 kube-api 서버에서 "--enable-aggregator-routing=true" 플래그를 추가하라고 권장하고 있습니다.
이 플래그를 통해 2대의 API 서버가 Metrics server pod 2대를 load balancing하며 메트릭을 요청하므로 성능상으로도 효율적인 구성을 할 수 있습니다. kube-api 서버 리소스에 파라미터를 추가해 해당 플래그를 활성화합시다.
하지만 kube-api 서버는 Control plane에 소속된 특수한 pod이므로 일반적인 pod의 수정 방법(kubectl edit 등..)으로는 수정할 수 없습니다. kube-api, kube-scheduler, kube-controller, etcd 이 4개의 오브젝트는 Static pod라고 하여 마스터 노드의 /etc/kubernetes/manifest 디렉토리에 존재하는 yaml파일의 변경으로만 수정할 수 있습니다.
마스터 노드의 /etc/kubernetes/manifest/kube-apiserver.yaml 파일을 아래와 같이 수정해 플래그를 활성화합니다.
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
|
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 10.128.0.30:6443
creationTimestamp: null
labels:
component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
...
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.96.0.0/12
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
- --enable-aggregator-routing=true
image: k8s.gcr.io/kube-apiserver:v1.23.4
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 8
httpGet:
host: 10.128.0.30
...
|
cs |
잠시 시간이 지난 후 kube-api 서버 pod를 확인했을때 아래와 같이 --enable-aggregator-rouing=true 파라미터가 활성화되어 있음을 확인합니다.
3-2. Vertical Scaling of Metrics server
위에서 Metrics server의 HA(High Availablity)를 위해 pod의 개수를 늘리는 Horizontal scaling을 알아봤다면, 이제는 Metrics server의 성능을 향상시키기 위한 Vertical scaling을 알아보겠습니다.
Vertical scaling에 대해 알아보기 전에 과연 Metrics server에게는 얼마 만큼의 리소스(CPU,memory)가 필요할까요? 이는 클러스터가 소유한 노드 개수에 따라 다릅니다. 노드가 많아질수록 수집해야 할 메트릭 엔드포인트도 많아지기 떄문입니다.
친절하게도 Metrics server의 Document에는 클러스터가 소유한 노드 당 Metrics server가 필요한 리소스를 명시해두고 있습니다.
Document에 따르면 노드 100개까지는 cpu 100m, memory 200Mi으로 충분하다고 하며, 이 값이 Metrics server의 기본값입니다. 실제로 당장 사용 중인 Metrics server pod의 리소스 스펙도 동일한 것을 확인할 수 있습니다.
단 이 리소스 스펙은 아래 테이블의 리소스 한계를 넘지 않는 선에서만 유효합니다.
Quantity | Namespace threshold | Cluster threshold |
#Nodes | n/a | 100 |
#Pods per node | 70 | 70 |
#Deployments with HPAs | 100 | 100 |
이후 늘어나는 노드 개수 당 아래에 따라 필요한 리소스가 늘어납니다.
- 노드 당 1m CPU 코어
- 노드 당 2MiB memory
예를 들어 300개의 노드를 소유한 클러스터에서 Metrics server의 적절한 리소스는 아래와 같습니다.
- CPU : 100 + 300 * 1 = 400 m
- memory : 200 + 300 * 2 = 800 Mi
노드의 개수가 고정적이면 필요한 리소스만큼 변경해놓고 사용하면 되겠지만, Kubernetes 환경은 노드의 개수가 가변적입니다. 그렇다면 노드의 개수가 변할때마다 Metrics server의 리소스 사용량도 일일이 변경해줘야 할까요?
이같은 불편함을 덜기 위해 노드 개수에 따라 Vertical Auto Scaling을 가능케 해주는 addon-resizer를 사용할 수 있습니다.
https://github.com/kubernetes/autoscaler/tree/master/addon-resizer
addon-resizer는 메트릭에 따라 Vertical scaling을 해주는 기존의 VPA와 달리 노드 개수에 따라 Vertical Scaling을 자동으로 해주는 컨테이너 이미지입니다. 이 컨테이너를 Metrics server Deployment에 배치해서 Metrics server가 노드 개수에 따라 자동으로 Vertical Scaling되도록 설정할 수 있습니다.
아래와 같이 Metrics server Deployment를 수정합니다.
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
|
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
components.gke.io/layer: addon
deployment.kubernetes.io/revision: "2"
labels:
addonmanager.kubernetes.io/mode: Reconcile
k8s-app: metrics-server
version: v0.5.2
name: metrics-server-v0.5.2
namespace: kube-system
...
spec:
containers:
- command:
- /metrics-server
- --metric-resolution=30s
- --kubelet-port=10255
- --deprecated-kubelet-completely-insecure=true
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
- --cert-dir=/tmp
- --secure-port=10250
image: gcr.io/gke-release/metrics-server-amd64:v0.5.2-gke.0
imagePullPolicy: IfNotPresent
name: metrics-server
---
- command:
- /pod_nanny
- --config-dir=/etc/config
- --cpu=100m
- --extra-cpu=1m
- --memory=200Mi
- --extra-memory=2Mi
- --threshold=100
- --deployment=metrics-server-v0.5.2
- --container=metrics-server
- --poll-period=30000
- --estimator=exponential
- --scale-down-delay=24h
- --minClusterSize=5
- --use-metrics=true
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
image: gke.gcr.io/addon-resizer:1.8.14-gke.0
imagePullPolicy: IfNotPresent
name: metrics-server-nanny
resources:
limits:
cpu: 100m
memory: 300Mi
requests:
cpu: 5m
memory: 50Mi
volumeMounts:
- mountPath: /etc/config
|
cs |
아래 "addon-resizer" 이미지를 사용한 metrics-server-nanny 컨테이너가 추가된 것이 변경점입니다.
커맨드 값을 통해 여러가지 플래그를 활성화하는 것을 볼 수 있는데요. 중요한 플래그만 하나씩 살펴보겠습니다.
- --config-dir : 컨피그 파일의 디렉토리 위치입니다. 컨피그 파일이 플래그의 설정을 덮어씁니다.
- --cpu : 목표 컨테이너(여기서는 metrics-server)에게 기본적으로 설정할 CPU값입니다.
- --extra-cpu : 목표 컨테이너에게 늘어나는 노드 당 추가할 CPU 값입니다.
- memory, --extra-memory : cpu와 동일합니다.
- --container : resizer가 vertical scaling할 목표 컨테이너입니다.
resizer가 사용할 컨피그 파일은 아래와 같이 작성하여 Confimap 오브젝트로 저장해 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
apiVersion: v1
data:
NannyConfiguration: |-
apiVersion: nannyconfig/v1alpha1
kind: NannyConfiguration
baseCPU: 100m
cpuPerNode: 1m
baseMemory: 200Mi
memoryPerNode: 2Mi
kind: ConfigMap
metadata:
creationTimestamp: "2022-04-18T04:59:49Z"
labels:
addonmanager.kubernetes.io/mode: EnsureExists
kubernetes.io/cluster-service: "true"
name: metrics-server-config
namespace: kube-system
|
cs |
이제 resizer가 정상적으로 동작하는지 확인하기 위해 노드 개수를 10개로 늘려보겠습니다.
설정한 컨피그에 따르면 노드 개수가 10개일때 Metrics server의 CPU는 100+10*1 = 110 m , memory는 200+10*2 = 220 Mi 여야 할 것입니다.
노드 개수가 늘어나면 resizer가 이를 감지하고 Vertical scaling을 위해 Metrics server pod를 재기동합니다.
새로운 Metrics server가 Running하는 것을 확인한 후, 리소스 스펙을 확인해보겠습니다.
위와 같이 계산한 것과 같은 cpu 110m, memory 220Mi 를 정확히 요청하고 있는 것을 볼 수 있습니다.
이렇게 resizer를 사용하면 노드 개수에 따라 자동으로 Vertical scaling을 수행해 Metrics server를 수동으로 scaling하지 않아도 된다는 편리한 점이 존재합니다.
4. 마무리
이번 포스팅에서는 Kubernetes에서 메트릭의 파이프라인을 담당하는 metrics server에 대해서 알아봤습니다.
metrics server는 kubelet과 kube-api 서버 사이에서 컨테이너의 메트릭을 수집하고 보내주는 중요한 역할을 하며, 이를 통해 우리는 kubectl top, HPA, VPA 등 메트릭을 사용하는 다양한 기능을 수행할 수 있었습니다.
이처럼 중요한 역할을 하기 때문에, Metrics server Deplyoment는 Replica의 개수를 2개로 늘리고 PodDistruptionBudget을 설정하는 등 HA(High Availability) 구성도 고려해 봐야 합니다.
클러스터가 거대해져 노드의 개수가 많아지면 Metrics server가 수집해야 하는 메트릭 엔드포인트도 늘어나므로 성능을 늘릴 Vertical scaling도 중요합니다. 이를 위해 Metrics server에서는 노드 개수별 적절한 리소스를 기재해 놓았으며, 자동 확장을 위해서 resizer를 고려해볼 수 있습니다.
이 포스팅을 보는 분들이 Metrics server에 관해서 많은 인사이트를 얻어갔으면 합니다.
'Devops' 카테고리의 다른 글
GCP에서 Terraform을 사용하기 위한 Best Practice (1) | 2022.09.16 |
---|---|
CKA(Certified Kubernetes Administrator) 자격증 시험 및 합격 후기 (2) | 2022.08.13 |
Apache Kafka란? Apache Kafka를 Kubernetes에서 구성해보자 (1) | 2022.06.16 |
Mysql Operator로 Kubernetes 환경에서 Mysql DB 운영하기 (3) | 2022.05.31 |
오픈소스 컨테이너 레지스트리 Harbor로 컨테이너 레지스트리 간 복제 수행하기 (0) | 2022.05.15 |