쿠버네티스(Kubernetes) 환경에 관심 많으시죠! 관련해 오늘 꼭 알아야 할 팁하나 소개합니다.
쿠버네티스는 컨테이너 오케스트레이션 부문의 사실상의 표준이 되었습니다. 관련해 점점 더 많은 곳에서 컨테이너 기반 환경으로 전환하는 데 쓰이고 있습니다. 컨테이너 환경을 구축할 때 관리자의 관심사는 ‘자동화’입니다. 오토스케일링 측면에서 어느 정도까지 자동화가 가능한가? 이를 알고 싶어 합니다. 쿠버네티스의 경우 다들 아시는 것과 같이 Horizontal Pod Autoscaler와 Cluster Autoscaler를 통해 자동 확장을 지원합니다. 이름만 봐도 알 수 있듯이 전자는 포드 수준에서 수평 확장을 하는 것이고, 후자는 클러스터 측면에서 접근하는 것입니다.
이 두 자동 확장 기능은 구글이 제공하는 클라우드 기반 관리형 서비스인 GKE(Google Kubernetes Engine)에서 당연히 이용할 수 있습니다. 다만 오픈 소스 쿠버네티스 환경과 차이가 있다면 단일 클러스터 환경에서 제한적으로 동작하는 기능이 아니라 클라우드 스케일로 확장이 이루어진다는 것입니다.
무슨 소리냐 하면 GKE는 클러스터 확장을 위해 노드 풀을 활용합니다. 노드 풀은 컨테이너 클러스터 내에서 같은 설정 정보를 갖는 노드 인스턴스의 서브셋입니다. 이를 이용하면 관리자는 다양한 크기로 구성된 노드 풀을 조성해 놓고, 이를 토대로 너무 작거나 또는 너무 큰 포드를 프로비져닝하여 생기는 성능 이슈나 자원 낭비 문제를 해결할 수 있습니다.
“Autoscaling – 쿠버네티스가 제공하는 자동 확장 기능의 2% 부족함 채우기”
Horizontal Pod Autoscaler와 Cluster Autoscaler는 훌륭한 기능이지만 아쉬움도 있습니다. 퍼센트로 따지면 2% 정도 아쉽습니다. 특히 DevOps를 실행하는 조직에서 부족함을 크게 느낍니다. 두 기능을 활성화한 환경에서 DevOps를 지원하기 위해 포드를 프로비져닝하다 보면 CPU와 메모리 자원 할당량이 너무 크거나 또는 너무 작은 문제가 생길 수 있습니다. 이 아쉬움을 풀기 위해 구글은 Vertical Pod Autoscaler와 Node Auto Provisioning 기능을 개발했습니다. 이 둘을 더하면 Horizontal Pod Autoscaler와 Cluster Autoscaler는 정말 완소템이 됩니다. 참고로 Vertical Pod Autoscaler와 Node Auto Provisioning 기능은 현재 베타 단계이며 GKE 어드밴스드 에디션의 일부로 테스트해 볼 수 있습니다.
“DevOps – 100명 개발자 조직을 예로 들어 볼까요!“
100명의 개발자로 조직된 DevOps 팀이 있다고 가정하겠습니다. 이 팀에서 워크로드와 인프라를 관리하는 철수라는 관리자가 있다고 하겠습니다. 이 팀은 매주 빈번하게 서비스를 배포합니다. 프로덕션에 배포해 운영하다 보면 간혹 메모리 부족 같은 자원 제약으로 인한 문제가 발생합니다. 테스트를 충분히 한 다음 프로덕션에 배포하지만 자원 부족으로 인한 성능 저하나 서비스 중단의 문제는 사라지지 않았습니다. 그래서 철수와 개발자들은 원인을 찾아보았습니다.
왜, 테스트 단계에서 멀쩡하던 서비스가 프로덕션만 가면 문제가 생길까? 원인은 생각보다 단순했습니다. 안정적으로 워크로드를 운영하는 데 필요한 CPU와 메모리 용량을 정확히 추정하는 이가 하나도 없었던 것입니다. 대략 이 정도면 되겠지, 그리고 평소 하던 데로 자원 용량을 잡았던 것입니다. 그렇다면 테스트 단계에서 큰 부하를 주어서 평가해, 자원이 부족한지 살펴보면 되지 않을까? 이렇게 접근하면 필요 이상으로 많은 자원을 할당해 리소스가 평소 남아도는 낭비 문제가 생길 수 있습니다. 결국 필요한 것은 ‘정확한 리소스의 양’이 어느 정도인지 아는 것인데, 이는 현실적으로 불가능합니다. 모든 상황을 가정해 정확한 자원 요구 사항을 안다? 누구도 알 수 없습니다.
철수는 최적의 자원 배치와 활용은 사람이 할 일이 아니라 자동화 기능이 해야 하는 일이라 판단하고 해결책을 찾았습니다. 철수는 Vertical Pod Autoscaler와 Node Auto Provisioning을 적용했고, 원하는 해결책을 찾았습니다.
철수가 테스트한 내용을 살펴보시죠. 철수는 테스트를 위해 새로운 클러스터를 생성했습니다.
gcloud beta container clusters create test-vpa --project <user_project> --enable-vertical-pod-autoscaling --enable-autoprovisioning --max-cpu 50 --max-memory 1000 --zone <zone> --cluster-version 1.12.5-gke.10
그런 다음 간단한 쉘 스크립트를 배포했는데요, 1.3 CPU를 사용해야 하는데, 일단 0.3으로 포드의 리소스 요청량을 작게 잡았습니다. deplyomnet.yaml 파일 내용을 보시죠.
apiVersion: apps/v1 kind: Deployment metadata: name: stress namespace: default spec: replicas: 2 selector: matchLabels: app: stress template: metadata: labels: app: stress spec: affinity: # One pod per node podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 podAffinityTerm: topologyKey: kubernetes.io/hostname labelSelector: matchExpressions: - key: app operator: In values: - stress containers: - name: cpu-demo image: k8s.gcr.io/ubuntu-slim:0.1 resources: requests: cpu: "0.3" command: ["sh"] args: ["-c", "while true; do (timeout 1s yes >/dev/null &) && (timeout 0.3s yes >/dev/null; sleep 0.7s); done"] # consume 1.3 CPU
그리고 다음과 같이 배포를 하였습니다.
$ kubectl create -f deployment.yaml deployment.apps/stress created
철수는 배포 후 무슨 일이 일어나는지 보았습니다. CPU 자원 할당을 작게 잡았으니, 배포 후 분명 문제가 생길 것이라 예상한 것이죠.
$ kubectl top pods NAME CPU(cores) MEMORY(bytes) stress-686b5c67f-tnvkl 970m 1Mi stress-686b5c67f-zdcwx 955m 1Mi
철수는 자원 부족 현상이 일어날 때 Vertical Pod Autoscaler가 어떻게 동작하는지 보고자 했습니다. 이를 위해 먼저 vpa.yaml 파일을 만들었습니다.
apiVersion: autoscaling.k8s.io/v1beta2 kind: VerticalPodAutoscaler metadata: name: my-vpa spec: targetRef: apiVersion: "extensions/v1beta1" kind: Deployment name: stress updatePolicy: updateMode: "Off"
그리고 나서 Vertical Pod Autoscaler를 생성했습니다.
$ kubectl create -f vpa.yaml verticalpodautoscaler.autoscaling.k8s.io/my-vpa created
몇 분을 기다린 다음 이 기능이 자원 관련해 어떤 추천을 하는지 보았습니다.
$ kubectl describe vpa Name: my-vpa Namespace: default Labels: <none> Annotations: <none> API Version: autoscaling.k8s.io/v1beta2 Kind: VerticalPodAutoscaler Metadata: Creation Timestamp: 2019-02-28T10:53:57Z Generation: 1 Resource Version: 1319 Self Link: /apis/autoscaling.k8s.io/v1beta2/namespaces/default/verticalpodautoscalers/my-vpa UID: 25d32046-3b47-11e9-b244-42010af00060 Spec: Target Ref: API Version: extensions/v1beta1 Kind: Deployment Name: stress Update Policy: Update Mode: Off Status: Conditions: Last Transition Time: 2019-02-28T10:54:07Z Message: Fetching history in progress Status: True Type: FetchingHistory Last Transition Time: 2019-02-28T10:54:07Z Message: Some containers have a small number of samples Reason: cpu-demo Status: True Type: LowConfidence Last Transition Time: 2019-02-28T10:54:07Z Status: True Type: RecommendationProvided Recommendation: Container Recommendations: Container Name: cpu-demo Lower Bound: Cpu: 595m Memory: 262144k Target: Cpu: 1168m Memory: 262144k Uncapped Target: Cpu: 1168m Memory: 262144k Upper Bound: Cpu: 421648m Memory: 4151500k Events: <none>
Vertical Pod Autoscaler는 포드 스펙을 조정하기 위한 추천을 제안하는 데요, 철수는 자동으로 포드 자원 요청이 조정되도록 automatic actuation 모드를 활성화했습니다. 관련 내용은 다음 vpa_auto.yaml을 참조 바랍니다.
apiVersion: autoscaling.k8s.io/v1beta2 kind: VerticalPodAutoscaler metadata: name: my-vpa spec: targetRef: apiVersion: "extensions/v1beta1" kind: Deployment name: stress updatePolicy: updateMode: "Auto"
$ kubectl apply -f vpa_auto.yaml verticalpodautoscaler.autoscaling.k8s.io/my-vpa configured
참고로 위 작업은 kubectl edit vpa 명령을 통해서도 할 수 있습니다. 편집시 udatemode를 Auto로 하면 됩니다.
설정을 마치고 철수는 포드의 상태를 확인해 봤습니다.
$ kubectl get pod -o=custom-columns=NAME:.metadata.name,PHASE:.status.phase,CPU-REQUEST:.spec.containers\[0\].resources.requests.cpu NAME PHASE CPU-REQUEST stress-686b5c67f-2kvhr Running 1168m stress-686b5c67f-zwrmj Running 1168m
상태 정보를 보고 철수는 깜짝 놀랐습니다. 클러스터 환경에서 1168개의 mCPU가 할당되어 돌아가고 있는 것을 눈으로 확인한 것이죠. 알아서 자원 할당량이 최적화되는 현장을 목격한 것입니다.
$ kubectl get nodes gke-test-vpa-default-pool-a83c9ac3-c58p Ready <none> 1h v1.12.5-gke.10 gke-test-vpa-default-pool-a83c9ac3-m5cj Ready <none> 1h v1.12.5-gke.10 gke-test-vpa-default-pool-a83c9ac3-xh2t Ready <none> 1h v1.12.5-gke.10 gke-test-vpa-nap-n1-highcpu-2-1551354-4454d396-j779 Ready <none> 27s v1.12.5-gke.10 gke-test-vpa-nap-n1-highcpu-2-1551354-4454d396-xphj Ready <none> 25s v1.12.5-gke.10
너무 작지도, 너무 크지도 않게 포드에 자원을 할당하는 것! 관리자가 할 일이 아닙니다. 자동화 기술을 잘 활용하는 것이 필요합니다. 더 자세한 내용은 메가존으로 문의 바랍니다.