on
12. 애플리케이션 스케줄링과 라이프사이클 관리 (2)
12. 애플리케이션 스케줄링과 라이프사이클 관리 (2)
반응형
이 문서는 인프런 강의 "데브옵스를 위한 쿠버네티스 마스터"을 듣고 작성되었습니다. 최대한 요약해서 강의 내용을 최소로 하는데 목표를 두고 있어서, 더 친절하고 정확한 내용을 원하신다면 강의를 구매하시는 것을 추천드립니다. => 강의 링크
컨테이너 리소스 요청과 제한하는 방법
이번 절은 GCP 에서 진행한다. k8s 에서 컨테이너 생성 시 CPU, 메모리를 요청 및 제한할 수 있다.
request : 최소 스펙 요청 사항
limit : 최대 리소스 제한
CPU는 다음 단위를 사용한다.
m (0.1 = 100m)
메모리는 다음 단위를 사용한다.
Ti (1024 ^ 4)
Gi (1024 ^ 3)
Mi (1024 ^ 2)
Ki (1024)
T (1000 ^ 4)
G (1000 ^ 3)
M (1000 ^ 2)
K (1000)
이제 한 번 리소스를 요청/제한에서 컨테이너를 만들어보자. 다음과 같이 만들 것이다.
request cpu: 1m memory: 200Mi
limit cpu: 2m memory: 400Mi
다음과 같이 container-limit-request.yaml 을 만들어보자.
src/ch12/k8s/container-limit-request.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 resources: requests: cpu: "1m" memory: "200Mi" limits: cpu: "2m" memory: "400Mi"
요청은 Pod 의 다음 필드로 할 수 있다.
spec.resources.requests.cpu
spec.resources.requests.resource
제한은 Pod 의 다음 필드로 할 수 있다.
spec.resources.limits.cpu
spec.resources.limits.resource
이제 다음 명령어로 리소스를 생성한다.
$ kubectl create -f container-limit-request.yaml deployment.apps/nginx-deployment created $ kubectl get pod -w NAME READY STATUS RESTARTS AGE ... nginx-deployment-7fdbdd879d-gtlzp 1/1 Running 0 74s nginx-deployment-7fdbdd879d-m55nv 1/1 Running 0 74s nginx-deployment-7fdbdd879d-s28ch 1/1 Running 0 74s
이제 describe 명령어를 실행하여 Pod 에서 리소스 요청/제한이 잘 되었는지 확인해보자.
$ kubectl describe pod nginx Name: nginx-deployment-7fdbdd879d-gtlzp ... Containers: nginx: ... Limits: cpu: 2m memory: 400Mi Requests: cpu: 1m memory: 200Mi ...
그리고 GKE 같은 클라우드 프로바이더에서 제공하는 쿠버네티스 클러스터에는 top 명령어를 사용하여 리소스 요청/제한 사항을 확인할 수 있다. (0m이 뜨는 이유는 왜인지 모르겠다..)
$ kubectl top pod NAME CPU(cores) MEMORY(bytes) nginx-deployment-7fdbdd879d-gtlzp 0m 3Mi nginx-deployment-7fdbdd879d-m55nv 0m 3Mi nginx-deployment-7fdbdd879d-s28ch 0m 3Mi
LimitRange
이번 절은 VM 에서 진행한다. LimitRange 는 Namespace 에서 Pod 혹은 Container , PersistentVolumeClaim 별로 리소스를 제한하는 "정책"이다. 다음과 같은 제약 조건을 제공한다.
Namespace 별 Pod 혹은 Container 별 CPU, Memory 사용량을 지정한다.
Namespace 별 StorageClass 별 최소 및 최대 스토리지 요청을 지정한다.
Namespace 별 리소스에 대한 request, limit 사이의 비율을 지정한다.
Namespace 별 컴퓨팅 리소스에 대한 기본 request/limit 설정하고, 런타임에 있는 컨테이너에 자동으로 설정한다.
이번 절에서는 Container 에 대한 리소스를 제한하는 정책만을 다룬다.
먼저 공통적으로 필요한 부분을 작업해보자. k8s 설정을 변경해주어야 한다. /etc/kubernetes/manifests/kube-apiserver.yaml 을 다음과 같이 수정한다.
apiVersion: v1 kind: Pod metadata: annotations: kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 10.0.2.15:6443 creationTimestamp: null labels: component: kube-apiserver tier: control-plane name: kube-apiserver namespace: kube-system spec: containers: - command: - kube-apiserver - --advertise-address=10.0.2.15 - --allow-privileged=true - --authorization-mode=Node,RBAC - --client-ca-file=/etc/kubernetes/pki/ca.crt # 수정 (, LimitRanger) 추가 - --enable-admission-plugins=NodeRestriction,LimitRanger - --enable-bootstrap-token-auth=true - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key - --etcd-servers=https://127.0.0.1:2379 - --insecure-port=0
그 후 얼마 정도 시간이 지나서 get 명령어를 사용해서 결과가 나오면 설정이 잘 변경된 것이다.
$ kubectl get pod NAME READY STATUS RESTARTS AGE mongodb 1/1 Running 1 8d
이제 Namespace 를 생성한다. 다음 명령어를 사용한다.
$ kubectl create namespace cpu-constraints
아니면 다음과 같이 cpu-constraints-ns.yaml 을 만들고 kubectl create -f 로 리소스를 생성해도 좋다.
src/ch12/k8s/cpu-constraints-ns.yaml
apiVersion: v1 kind: Namespace metadata: creationTimestamp: null name: cpu-constraints spec: {} status: {}
그 후 이제 LimitRange 를 만들어보자. 위에 생성한 Namespace 에 CPU를 200m에서 800m까지의 제한 정책을 둘 것이다. 다음과 같이 cpu-constraints-lr.yaml 을 생성한다.
src/ch12/k8s/cpu-constraints-lr.yaml
apiVersion: v1 kind: LimitRange metadata: name: cpu-constraints-lr namespace: cpu-constraints spec: limits: - max: cpu: "800m" min: cpu: "200m" type: Container
그 후 터미널에 다음을 입력하여 리소스를 생성한다.
$ kubectl create -f cpu-constraints-lr.yaml limitrange/cpu-constraints-lr created
이제 다음 명령어를 이용해서 리소스 제한 정책이 잘 만들어졌는지 확인하자.
$ kubectl get limitranges cpu-constraints-lr --output=yaml -n cpu-constraints apiVersion: v1 kind: LimitRange metadata: creationTimestamp: "2021-08-19T11:35:59Z" name: cpu-constraints-lr namespace: cpu-constraints resourceVersion: "55564" uid: a69c11c3-b2fc-427a-b19d-948f613ba6f1 spec: limits: - default: cpu: 800m defaultRequest: cpu: 800m max: cpu: 800m min: cpu: 200m type: Container
기본 값을 지정하지 않더라도 자동으로 만들어진다는 것을 확인할 수 있다. 이제 해당 범위에 맞는 Pod 을 생성해보자. cpu-constraints-pod-1.yaml 을 다음과 같이 생성한다.
src/ch12/k8s/cpu-constraints-pod-1.yaml
apiVersion: v1 kind: Pod metadata: name: constraints-cpu-demo1 namespace: cpu-constraints spec: containers: - name: constraints-cpu-demo1 image: nginx resources: limits: cpu: "800m" requests: cpu: "500m"
이제 리소스를 생성하면 잘 만들어지는 것을 확인할 수 있다.
$ kubectl create -f cpu-constraints-pod-1.yaml pod/constraints-cpu-demo1 created $ kubectl get pod -w -n cpu-constraints NAME READY STATUS RESTARTS AGE constraints-cpu-demo1 1/1 Running 0 16s
이번엔 CPU "limit"이 LimitRange 의 "max"보다 크게 설정하는 Pod 을 만들어본다. cpu-constraints-pod-2.yaml 를 다음과 같이 작성한다.
src/ch12/k8s/cpu-constraints-pod-2.yaml
apiVersion: v1 kind: Pod metadata: name: constraints-cpu-demo2 namespace: cpu-constraints spec: containers: - name: constraints-cpu-demo2 image: nginx resources: limits: cpu: "1.5" requests: cpu: "500m"
max가 800인데 1.5를 제한을 걸었다. 리소스를 생성해보자.
$ kubectl create -f cpu-constraints-pod-2.yaml Error from server (Forbidden): error when creating "cpu-constraints-pod-2.yaml": pods "constraints-cpu-demo2" is forbidden: maximum cpu usage per Container is 800m, but limit is 1500m
limits > max 조건이 성립되기 때문에 생성되지 않는다. 이번엔 Pod 의 리소스 "request"가 LimitRange 에 설정한 "min"보다 낮은 리소스를 요청하면 어떻게 될까? cpu-constraints-pod-3.yaml 를 다음곽 같이 작성한다.
src/ch12/k8s/cpu-constraints-pod-3.yaml
apiVersion: v1 kind: Pod metadata: name: constraints-cpu-demo3 namespace: cpu-constraints spec: containers: - name: constraints-cpu-demo3 image: nginx resources: limits: cpu: "800" requests: cpu: "100m"
다음 명령어를 이용해서 리소스를 생성한다.
$ kubectl create -f cpu-constraints-pod-3.yaml Error from server (Forbidden): error when creating "cpu-constraints-pod-3.yaml": pods "constraints-cpu-demo3" is forbidden: [minimum cpu usage per Container is 200m, but request is 100m, maximum cpu usage per Container is 800m, but limit is 800]
이것도 만들어지지 않는다. requests < min 조건이 성립하기 때문이다. 즉, min <= requests <= limit <= max 라는 조건이 성립되어야 잘 만들어진다는 것을 알 수 있다.
ResourceQuota
이번 절은 VM 환경에서 진행된다. ResourceQuota 는 Namespace 별 만들 수 있는 총 리소스의 양을 제한한다. Namespace 당 1개씩 지정할 수 있다. cpu, memory. storage 뿐 아니라 Pod , Deployment 같은 오브젝트 개수까지 제한이 가능하다.
먼저 Namespace 를 생성한다. mem-cpu-ns.yaml 을 다음과 같이 작성한다.
src/ch12/k8s/mem-cpu-ns.yaml
apiVersion: v1 kind: Namespace metadata: creationTimestamp: null name: mem-cpu-demo spec: {} status: {}
그리고 다음 멸령어로 리소스를 생성한다.
$ kubectl create -f mem-cpu-ns.yaml namespace/mem-cpu-demo created
그 후 ResourceQuota 를 만들면 된다. mem-cpu-rq.yaml 을 다음과 같이 작성한다.
src/ch12/k8s/mem-cpu-rq.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: mem-cpu-demo-rq namespace: mem-cpu-demo spec: hard: requests.cpu: "1" requests.memory: 1Gi limits.cpu: "2" limits.memory: 2Gi
위 ResourceQuata 는 cpu는 request는 1까지, limit은 2까지, memory는 request는 1Gi, limit은 2Gi 까지 생성할 수 있다. 리소스를 생성해보자.
$ kubectl create -f mem-cpu-rq.yaml resourcequota/mem-cpu-demo-rq created
describe 명령어로 한 번 확인해보자.
$ kubectl describe resourcequota mem-cpu-demo-rq -n mem-cpu-demo Name: mem-cpu-demo-rq Namespace: mem-cpu-demo Resource Used Hard -------- ---- ---- limits.cpu 0 2 limits.memory 0 2Gi requests.cpu 0 1 requests.memory 0 1Gi
자 이제 Pod 을 1개 만들어보자. mem-cpu-pod-1.yaml 을 다음과 같이 작성한다.
src/ch12/k8s/mem-cpu-pod-1.yaml
apiVersion: v1 kind: Pod metadata: name: mem-cpu-demo-1 namespace: mem-cpu-demo spec: containers: - name: mem-cpu-demo-1 image: nginx resources: limits: memory: "800Mi" cpu: "800m" requests: memory: "600Mi" cpu: "400m"
리소스 생성을 위해 다음 명령어를 입력한다.
$ kubectl create -f mem-cpu-pod-1.yaml pod/mem-cpu-demo-1 created
그 후 ResourceQuota 를 다시 한 번 확인해서 리소스를 얼마나 사용했는지 확인해보자.
$ kubectl describe resourcequota mem-cpu-demo-rq -n mem-cpu-demo Name: mem-cpu-demo-rq Namespace: mem-cpu-demo Resource Used Hard -------- ---- ---- limits.cpu 800m 2 limits.memory 800Mi 2Gi requests.cpu 400m 1 requests.memory 600Mi 1Gi
리소스를 얼마나 사용한지 확인할 수 있다. 이제 새로운 Pod 을 하나 더 만들어보자. mem-cpu-pod-2.yaml 을 다음과 같이 작성한다.
src/ch12/k8s/mem-cpu-pod-2.yaml
apiVersion: v1 kind: Pod metadata: name: mem-cpu-demo-2 namespace: mem-cpu-demo spec: containers: - name: mem-cpu-demo-2 image: nginx resources: limits: memory: "1Gi" cpu: "800m" requests: memory: "700Mi" cpu: "400m"
위의 리소스를 생성하면 cpu request는 0.8, limit은 1.6, memory request는 1.3Gi, limit은 1.8Gi가 된다. 하지만, memory request가 ResourceQuota 에 총 제한량보다 커지니까 이 리소스는 만들어지지 않을 것이다. 다음 명령어를 입력해보자.
$ kubectl create -f mem-cpu-pod-2.yaml Error from server (Forbidden): error when creating "mem-cpu-pod-2.yaml": pods "mem-cpu-demo-2" is forbidden: exceeded quota: mem-cpu-demo-rq, requested: requests.memory=700Mi, used: requests.memory=600Mi, limited: requests.memory=1Gi
역시 예상대로 리소스가 만들어지지 않는 다는 것을 확인할 수 있다.
DaemonSet
이번 절에서는 GCP 에서 진행한다. DaemonSet 은 ReplicaSet 과 거의 유사하다. ReplicaSet 은 Pod 가 임의의 Node 에서 생성된다면, DaemonSet 은 각 Node 에 1개씩 배치된다. 보통은 HostPath 로 설정된 Volume 과 함께 사용되어 Node 의 리소스를 모니터링하는데 사용된다.
자 이제 DaemonSet 을 한 번 만들어보자. daemonset.yaml 을 다음과 같이 생성한다.
src/ch12/k8s/daemonset.yaml
apiVersion: apps/v1 kind: DaemonSet metadata: name: nginx labels: name: nginx spec: selector: matchLabels: name: nginx template: metadata: labels: name: nginx spec: tolerations: - key: node-role.kubernetes.io/master operator: Exists effect: NoSchedule containers: - name: nginx image: nginx terminationGracePeriodSeconds: 30
ReplicaSet 과 거의 유사하다. 몇 가지 추가사항이 있는데 Pod.spec.tolerations 설정이 필요하다. 각 키와 효과는 다음과 같다.
node.kubernetes.io/not-ready effect: NoExecute version: 1.13+ description: 네트워크 파티션과 같은 노드 문제가 발생해도 데몬셋 파드는 축출되지 않는다.
node.kubernetes.io/unreachable effect: NoExecute version: 1.13+ description: 네트워크 파티션과 같은 노드 문제가 발생해도 데몬셋 파드는 축출되지 않는다.
node.kubernetes.io/disk-pressure effect: NoSchedule version: 1.8+ description: 데몬셋 파드는 기본 스케줄러에서 디스크-압박(disk-pressure) 속성을 허용한다.
node.kubernetes.io/memory-pressure effect: NoSchedule version: 1.8+ description: 데몬셋 파드는 기본 스케줄러에서 메모리-압박(memory-pressure) 속성을 허용한다.
node.kubernetes.io/unschedulable effect: NoSchedule version: 1.12+ description: 데몬셋 파드는 기본 스케줄러의 스케줄할 수 없는(unschedulable) 속성을 극복한다.
node.kubernetes.io/network-unavailable effect: NoSchedule version: 1.12+ description: 호스트 네트워크를 사용하는 데몬셋 파드는 기본 스케줄러에 의해 이용할 수 없는 네트워크(network-unavailable) 속성을 극복한다.
그리고 Pod.spec.terminationGracePeriodSeconds 속성도 추가된다. 이제 리소스를 생성해보자. 다음 명령어를 입력한다.
$ kubectl create -f daemonset.yaml daemonset.apps/nginx created
실제 kubectl get pod -o wide 명령어를 이용하면, 어디 노드에 Pod 이 구성되었는지 확인할 수 있다. 다음 명령어를 입력해보자.
$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES # 각 기 다른 노드에 생성된 것을 확인할 수 있다. nginx-2v72b 1/1 Running 0 24s 10.20.0.47 gke-gurumee-gke-default-pool-d6d0240d-xvwr nginx-nhtvq 1/1 Running 0 24s 10.20.2.26 gke-gurumee-gke-default-pool-d6d0240d-sj3x nginx-pnjq4 1/1 Running 0 24s 10.20.1.10 gke-gurumee-gke-default-pool-d6d0240d-f439
각기 다른 노드에 구성됨을 확인할 수 있다.
Static Pod
이번 절은 VM 에서 진행된다. Static Pod 은 kubectl 명령어로 생성하는 것이 아닌 kubelet 이 관리하는 Pod 을 의미한다. 대표적으로 kube-system 에 존재하는 Pod 들이 바로 그들인다.
$ kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-558bd4d5db-5z4jv 1/1 Running 13 48d coredns-558bd4d5db-z45ck 1/1 Running 10 37d etcd-master 1/1 Running 16 48d kube-apiserver-master 1/1 Running 1 23h kube-controller-manager-master 1/1 Running 17 48d kube-proxy-hvpz5 1/1 Running 17 48d kube-proxy-kdtb5 1/1 Running 15 48d kube-proxy-qthkm 1/1 Running 13 48d kube-scheduler-master 1/1 Running 17 48d weave-net-46bsq 2/2 Running 29 48d weave-net-fgxbv 2/2 Running 29 48d weave-net-qr5v6 2/2 Running 34 48d
또한 이들은 kubectl 로 삭제할 수 없다. 한 번 Static Pod 을 한 번 만들어보자. kubelet 이 실행될 때 옵션으로 경로를 주면 하위 경로에 존재하는 Static Pod 리소스들은 생성된다.
기본 경로는 /etc/kubernetes/manifests/ 다. 한 번 해당 경로에는 어떤 리소스가 있는지 확인해보자.
# sudo 권한 획득 $ ls /etc/kubernetes/manifests/ etcd.yaml kube-controller-manager.yaml kube-apiserver.yaml kube-scheduler.yaml
여기다 우리 리소스를 추가하자. 다음 명령어를 입력한다.
# 파일 생성 $ sudo tee /etc/kubernetes/manifests/staticpod.yaml <
소스 코드는 여기 링크 로 확인할 수 있다. 한 번 get pod 명령어를 실행해보자.
$ kubectl get pod -w NAME READY STATUS RESTARTS AGE static-pod-master 0/1 ContainerCreating 0 11s static-pod-master 1/1 Running 0 15s
우리는 리소스를 생성하지 않았음에도 Pod 이 생성되었다. 주목할 점은 static-pod 뒤에 -master 가 붙었다는 것이다. kube-system 네임스페이스 아래에도 이런 Pod 들이 있었다.
$ kubectl get pod -n kube-system | grep master etcd-master 1/1 Running 16 48d kube-apiserver-master 1/1 Running 1 23h kube-controller-manager-master 1/1 Running 17 48d kube-scheduler-master 1/1 Running 17 48d
그렇다 바로 /etc/kubernetes/manifests/ 에 있던 리소스들로 인해서 위의 Pod 들이 생성된 것이다. 이렇게 생성된 Static Pod 은 kubectl 로 지울 수 없다.
$ kubectl delete all --all pod "static-pod-master" deleted service "kubernetes" deleted $ kubectl get pod -w NAME READY STATUS RESTARTS AGE static-pod-master 1/1 Running 0 4s
지우는 방법은 /etc/kubernetes/manifests/ 경로에서 리소스 파일을 삭제하는 것 뿐이다.
$ sudo rm /etc/kubernetes/manifests/staticpod.yaml $ kubectl get pod No resources found in default namespace.
수동 스케줄링
이번 절은 GCP 에서 진행한다. 수동 스케줄링은 자신이 원하는 Node 에 Pod 들을 배치할 수 있는 기능이다. 2가지 방법이 있다.
첫 번째 방법은 Node 의 이름을 지정하는 것이다. 먼저 scheduling-1.yaml 을 다음과 같이 생성한다.
src/ch12/k8s/scheduling-1.yaml
apiVersion: v1 kind: Pod metadata: name: scheduling-1 spec: containers: - name: scheduling-1 image: nginx # node 이름 nodeName: gke-gurumee-gke-default-pool-d6d0240d-sj3x
그 후 다음 명령어를 입력하여 리소스를 생성한다.
$ kubectl create -f scheduling-1.yaml pod/scheduling-1 created
kubectl get pod -o wide 명령어를 입력하면 어떤 노드에 생성되는지 확인할 수 있다. 우리가 nodeName 에 지정한 Node 에 생성됨을 확인할 수 있다.
$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES scheduling-1 1/1 Running 0 7s 10.20.2.27 gke-gurumee-gke-default-pool-d6d0240d-sj3x
두 번째 방법은 Node 의 레이블을 지정하는 것이다. scheduling-2.yaml 을 다음과 같이 생성한다.
src/ch12/k8s/scheduling-2.yaml
apiVersion: v1 kind: Pod metadata: name: scheduling-2 spec: containers: - name: scheduling-2 image: nginx # node 이름 nodeSelector: gpu: "true"
nodeSelector 에 원하는 Node 의 레이블 값을 달면 된다. 이제 다음 명령어를 입력하여 리소스를 생성한다.
$ kubectl create -f scheduling-2.yaml pod/scheduling-2 created $ kubectl get pod -w NAME READY STATUS RESTARTS AGE scheduling-1 1/1 Running 0 2m26s scheduling-2 0/1 Pending 0 9s
아무리 기다려도 scheduling-2 는 생성되지 않는다. 왜냐하면 현재 GKE 클러스터 Node 중 gpu=true 인 레이블이 없기 때문이다.
$ kubectl get nodes -L gpu NAME STATUS ROLES AGE VERSION GPU gke-gurumee-gke-default-pool-d6d0240d-f439 Ready 9d v1.20.8-gke.900 gke-gurumee-gke-default-pool-d6d0240d-sj3x Ready 9d v1.20.8-gke.900 gke-gurumee-gke-default-pool-d6d0240d-xvwr Ready 9d v1.20.8-gke.900
위 3개의 노드 중 마음 가는 아무거나 레이블을 붙여준다.
$ kubectl label node gke-gurumee-gke-default-pool-d6d0240d-xvwr gpu="true" $ kubectl get nodes -L gpu NAME STATUS ROLES AGE VERSION GPU gke-gurumee-gke-default-pool-d6d0240d-f439 Ready 9d v1.20.8-gke.900 gke-gurumee-gke-default-pool-d6d0240d-sj3x Ready 9d v1.20.8-gke.900 gke-gurumee-gke-default-pool-d6d0240d-xvwr Ready 9d v1.20.8-gke.900 true
이제 다시 kubectl get pod -o wide 명령어를 입력하면, gpu=true 레이블을 준 Node 에 Pod 이 배치됨을 확인할 수 있다.
$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES scheduling-1 1/1 Running 0 5m41s 10.20.2.27 gke-gurumee-gke-default-pool-d6d0240d-sj3x scheduling-2 1/1 Running 0 3m24s 10.20.0.48 gke-gurumee-gke-default-pool-d6d0240d-xvwr
오토 스케일링
k8s 에서 오토 스케일링이 필요한 경우가 있다. 총 3가지 유형이 있다.
HPA: Pod 자체를 복체하여 처리할 수 있는 Pod의 개수를 늘림.
VPA: 리소스를 증가시켜 Pod의 사용 가능한 리소스를 늘림
CA: 클러스터를 자체를 늘림
이 중 HPA 만이 기본적으로 제공되는 오토 스케일링 방법이며 나머지 2개는 클라우드 프로바이더 별 제공할 수도 있고 안 할수도 있다. 여기서는 HPA 만을 다룬다. 이번 절은 GKE 에서 다룬다.
실습을 진행해보자. 먼저 다음과 같이 hpa.yaml 을 만든다.
src/ch12/k8s/hpa.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: php-apache spec: selector: matchLabels: run: php-apache replicas: 1 template: metadata: labels: run: php-apache spec: containers: - name: php-apache image: k8s.gcr.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
Deployment 와 Service 를 생성하며, php-apache 라는 웹 서비스를 구축하게 된다. 다음 명령어를 이용해 리소스를 생성해보자.
$ kubectl create -f hpa.yaml deployment.apps/php-apache created service/php-apache created
자 이제 HPA 를 생성하자.
$ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10 horizontalpodautoscaler.autoscaling/php-apache autoscaled $ kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache /50% 1 10 1 20s
보면 "TARGET"이 50%이고 "MIN"이 1개, "MAX"가 10개, 현재 "REPLICA"는 1개로 되있음을 확인할 수 있다. 이제 무한히 php-apache 서비스를 호출하는 Pod 을 만들어보자.
$ kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
그리고 HPA 와 Deployment 를 관찰해보자.
$ kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache /50% 1 10 1 72s php-apache Deployment/php-apache 250%/50% 1 10 1 79s php-apache Deployment/php-apache 250%/50% 1 10 4 80s php-apache Deployment/php-apache 250%/50% 1 10 5 96s $ kubectl get deployment php-apache NAME READY UP-TO-DATE AVAILABLE AGE php-apache 5/5 5 5 115s
"TARGET"이 250%가 되면서 "REPLICA" 개수가 계속 증가한다. 위는 내가 중간에 끊어서 명령어를 실행했기 때문에 5개밖에 안찍혔지만 실제로는 7개까지 Pod 이 늘어났다. 이제 호출하는 Pod 을 삭제해보자.
$ kubectl delete pod load-generator pod "load-generator" deletedkubectl delete pod load-generator pod "load-generator" deleted
이제 다시 HPA 와 Deployment 를 관찰한다.
$ kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 60%/50% 1 10 5 2m33s php-apache Deployment/php-apache 67%/50% 1 10 5 2m38s php-apache Deployment/php-apache 67%/50% 1 10 7 2m52s php-apache Deployment/php-apache 14%/50% 1 10 7 3m9s php-apache Deployment/php-apache 0%/50% 1 10 7 3m39s php-apache Deployment/php-apache 0%/50% 1 10 7 8m5s php-apache Deployment/php-apache 0%/50% 1 10 2 8m20s php-apache Deployment/php-apache 0%/50% 1 10 2 8m36s php-apache Deployment/php-apache 0%/50% 1 10 1 8m51s $ kubectl get deployment php-apache NAME READY UP-TO-DATE AVAILABLE AGE php-apache 1/1 1 1 9m13s
증가할 때는 진짜 빠르게 Pod 개수를 오토 스케일링했는데 내려갈 때는 매우 천천히 개수가 준다. 아무래도 실제 서비스에는 이런 저런 상황으로 부하가 왔다 갔다 할 수 있으니 그것까지 고려해서 개수를 조정하는 듯 하다.
HPA 말고 VPA , CA 를 하기 위해서는 각 클라우드 프로바이더에서 제공하는지 확인하고 해당 방법을 래퍼런스를 통해서 찾아야 한다. GKE 에서 VPA , CA 하는 방법은 아래 명령어들을 참고하라.
vpa
$ gcloud container clusters create CLUSTER_NAME \ --enable-vertical-pod-autoscaling --cluster-version=VERSION
ca
$ gcloud container clusters create example-cluster \ --num-nodes 2 \ --zone us-central1-a \ --node-locations us-central1-a,us-central1-b,us-central1-f \ --enable-autoscaling --min-nodes 1 --max-nodes 4
from http://gurumee92.tistory.com/283 by ccl(A) rewrite - 2021-08-20 21:00:47