콘텐츠로 이동
Study NoteCKA

실전 과제 — 워크로드와 스케줄링

결론부터
  • HPA의 축소 안정화 창은 명령 옵션이 없다. kubectl autoscale로 뼈대를 뽑고 behavior를 YAML에 직접 넣는다.
  • 로그 사이드카는 두 컨테이너가 같은 볼륨을 같은 경로에 마운트해야 파일을 본다.
  • 새 PriorityClass 값은 system-으로 시작하지 않는 클래스의 최댓값을 기준으로 정한다.
  • Pod별 requests는 노드 Allocatable에서 다른 Pod의 requests와 여유분을 뺀 뒤 나눈다.

개념 페이지가 “무엇이 일어나는가”를 설명한다면, 이 페이지는 지문을 받았을 때 무엇부터 치는가를 연습한다. 과제는 연습용으로 만든 시나리오이고 이름과 값은 예시다. 과제마다 조건 → 풀이 → 확인 → 함정 순서로 읽고, 원리는 링크한 개념 페이지에서 확인한다. 호스트 접속과 네임스페이스 확인은 문제마다 반복하는 3단계를 따른다.

준비 명령은 연습 클러스터에 같은 상황을 만들 때만 쓴다. 끝나면 만든 네임스페이스를 지우면 된다.

과제

  • 네임스페이스 scale-lab의 Deployment web-api를 대상으로 같은 이름의 HPA를 만든다.
  • Pod당 평균 CPU 사용률 60%를 목표로 하고, Pod 수는 최소 2개·최대 6개다.
  • 축소 안정화 창을 60초로 둔다.

준비

터미널 창
kubectl create namespace scale-lab
kubectl create deployment web-api -n scale-lab --image=nginx:1.28
kubectl set resources deployment web-api -n scale-lab --requests=cpu=100m

풀이

  1. 뼈대를 명령으로 뽑는다. 대상·최소·최대·목표 사용률은 옵션으로 채워진다.

    터미널 창
    kubectl autoscale deployment web-api -n scale-lab \
    --min=2 --max=6 --cpu=60% --dry-run=client -o yaml > hpa.yaml
  2. behavior를 spec 아래에 더한다. 안정화 창은 명령 옵션이 없다.

    spec:
    behavior:
    scaleDown:
    stabilizationWindowSeconds: 60
  3. 적용하고 값이 들어갔는지 본다.

    터미널 창
    kubectl apply -f hpa.yaml
    kubectl get hpa web-api -n scale-lab
    kubectl get hpa web-api -n scale-lab \
    -o jsonpath='{.spec.behavior.scaleDown.stabilizationWindowSeconds}{"\n"}'
    # 60

안정화 창의 뜻과 기본값은 behavior — 확장·축소 속도 제어에 있다.

기존 Deployment에 로그 사이드카 추가하기

섹션 제목: “기존 Deployment에 로그 사이드카 추가하기”

과제

  • 네임스페이스 reports의 Deployment report-writer는 /var/log/report.log에 로그를 쓴다.
  • 같은 Pod에 busybox:stable 이미지의 컨테이너 log-tail을 추가한다.
  • log-tail은 /bin/sh -c "tail -n+1 -f /var/log/report.log"를 실행한다.
  • 두 컨테이너가 /var/log에 마운트한 볼륨으로 로그 파일을 공유한다.

준비

터미널 창
kubectl create namespace reports
kubectl create deployment report-writer -n reports --image=busybox:stable \
-- /bin/sh -c 'while true; do date >> /var/log/report.log; sleep 5; done'

풀이

  1. Pod 템플릿을 연다.

    터미널 창
    kubectl edit deployment report-writer -n reports
  2. 세 곳을 고친다. 볼륨 정의, 기존 컨테이너의 마운트, 새 컨테이너다. 아래는 고친 부분만 보인 발췌다.

    spec:
    template:
    spec:
    containers:
    - name: busybox # 기존 컨테이너
    volumeMounts: # 추가
    - name: logs
    mountPath: /var/log
    - name: log-tail # 추가
    image: busybox:stable
    command: ["/bin/sh", "-c", "tail -n+1 -f /var/log/report.log"]
    volumeMounts:
    - name: logs
    mountPath: /var/log
    volumes: # 추가
    - name: logs
    emptyDir: {}
  3. 새 Pod이 뜨고 사이드카가 로그를 읽는지 본다.

    터미널 창
    kubectl rollout status deployment report-writer -n reports
    kubectl get pods -n reports # 새 Pod이 READY 2/2
    kubectl logs <새-Pod-이름> -n reports -c log-tail --tail=3

볼륨이 Pod 안에서 공유되는 방식은 emptyDir에서 다룬다.

기존 값에 맞춰 PriorityClass 만들기

섹션 제목: “기존 값에 맞춰 PriorityClass 만들기”

과제

  • 사용자 워크로드용 PriorityClass batch-high를 만든다. 값은 기존 사용자 정의 클래스의 최댓값보다 1 작게 한다.
  • 네임스페이스 tiered의 Deployment log-shipper가 이 클래스를 쓰게 하고, 롤아웃이 끝났는지 확인한다.

준비

터미널 창
kubectl create priorityclass team-low --value=1000
kubectl create priorityclass team-top --value=500000
kubectl create namespace tiered
kubectl create deployment log-shipper -n tiered --image=busybox:stable -- sleep 3600

풀이

  1. 기존 클래스를 값 순서로 본다. system-으로 시작하는 두 개는 내장 클래스라 기준에서 뺀다.

    터미널 창
    kubectl get priorityclass --sort-by=.value
    # NAME VALUE GLOBAL-DEFAULT AGE PREEMPTIONPOLICY
    # team-low 1000 false 1m PreemptLowerPriority
    # team-top 500000 false 1m PreemptLowerPriority
    # system-cluster-critical 2000000000 false 9d PreemptLowerPriority
    # system-node-critical 2000001000 false 9d PreemptLowerPriority
  2. 최댓값에서 1을 뺀 값으로 만든다.

    터미널 창
    kubectl create priorityclass batch-high --value=499999 \
    --description="user workloads"
  3. Deployment의 Pod 템플릿에 클래스 이름을 넣는다.

    터미널 창
    kubectl patch deployment log-shipper -n tiered \
    -p '{"spec":{"template":{"spec":{"priorityClassName":"batch-high"}}}}'
  4. 롤아웃과 실제 우선순위를 확인한다.

    터미널 창
    kubectl rollout status deployment log-shipper -n tiered
    kubectl get pods -n tiered \
    -o custom-columns='NAME:.metadata.name,CLASS:.spec.priorityClassName,PRIORITY:.spec.priority'

선점이 일어나는 순서는 PriorityClass와 선점에서 본다.

노드 자원을 Pod에 고르게 나누기

섹션 제목: “노드 자원을 Pod에 고르게 나누기”

과제

  • 네임스페이스 blog의 Deployment blog는 replicas가 3인데 일부 Pod이 Pending이다.
  • Pod마다 init 컨테이너 하나와 앱 컨테이너 하나가 있고, 워커 노드는 하나다.
  • 세 Pod이 노드 자원을 고르게 나눠 쓰도록 requests를 고친다. 노드가 안정적으로 돌 여유를 남긴다.
  • init 컨테이너와 앱 컨테이너의 requests는 같은 값으로 한다.
  • 고치는 동안에는 replicas를 0으로 두고, 끝나면 3개가 모두 Running·Ready여야 한다.

이 과제는 노드 크기에 따라 값이 달라져 준비 명령을 두지 않는다. 연습할 때는 requests를 노드 Allocatable의 절반쯤으로 준 replicas 3짜리 Deployment를 만들면 같은 상황이 된다.

풀이

  1. 왜 Pending인지 확인한다. Insufficient cpu나 Insufficient memory가 보이면 requests 문제다.

    터미널 창
    kubectl get pods -n blog -o wide
    kubectl describe pod <Pending인-Pod> -n blog | grep -A5 Events
  2. replicas를 0으로 줄인다. 이 Deployment의 requests가 노드 집계에서 빠진다.

    터미널 창
    kubectl scale deployment blog -n blog --replicas=0
  3. 노드에서 나눌 수 있는 양을 읽는다.

    터미널 창
    kubectl get node <워커노드> \
    -o jsonpath='{.status.allocatable.cpu}{" "}{.status.allocatable.memory}{"\n"}'
    kubectl describe node <워커노드> | grep -A8 'Allocated resources'
  4. Pod 하나의 몫을 계산한다. 아래는 예시 수치다.

    CPU메모리
    Allocatable2000m3800Mi
    다른 Pod의 requests 합350m300Mi
    나눌 수 있는 양1650m3500Mi
    여유 15%를 남기고 3으로 나눈 값467m991Mi
    내림해서 쓸 값450m950Mi
  5. init 컨테이너와 앱 컨테이너에 같은 값을 넣는다. kubectl set resources는 컨테이너를 지정하지 않으면 init 컨테이너까지 전부 바꾼다. 두 쪽에 들어갔는지 바로 확인한다.

    터미널 창
    kubectl set resources deployment blog -n blog --requests=cpu=450m,memory=950Mi
    kubectl get deployment blog -n blog -o jsonpath='{.spec.template.spec.initContainers[*].resources.requests}{"\n"}{.spec.template.spec.containers[*].resources.requests}{"\n"}'
  6. 다시 3개로 늘리고 확인한다.

    터미널 창
    kubectl scale deployment blog -n blog --replicas=3
    kubectl rollout status deployment blog -n blog
    kubectl get pods -n blog # 3개 모두 Running, READY 1/1

계산의 근거는 노드 용량에서 requests 정하기에 있다.