95. Application Lifecycle Management - Section Introduction

  • 애플리케이션 배포, 업데이트, 롤백 전략
  • 환경 변수, ConfigMap, Secret 관리
  • Multi-container Pod, Init Container
  • Autoscaling (HPA, VPA) - 2025 업데이트

96. Rolling Updates and Rollbacks

Rolling Update란?

“다운타임 없이 앱을 점진적으로 교체하는 방식”

왜 필요한가?

  • 기존 방식: Pod 전부 끄고 → 새 버전 배포 → 사용자는 그 사이 에러 경험
  • Rolling Update: 기존 Pod 1개씩 새 버전으로 교체 → 사용자는 눈치 못 챔

동작 원리:

  • Deployment는 내부적으로 두 개의 ReplicaSet을 동시에 관리
  • 기존 RS는 줄이고 새 RS는 늘림 (Pod 총 개수를 일정하게 유지)
  • 이 “버전 전환 이력”이 저장되어 있어서 롤백도 한 줄로 가능

Rollout과 Versioning

  • Deployment 생성 → Rollout (revision 1)
  • 이미지 업데이트 → 새 Rollout (revision 2)
  • 또 업데이트 → 새 Rollout (revision 3)

이미지 변경마다 새 Rollout(revision)이 생성되어 히스토리로 남음

# 롤아웃 상태 확인
kubectl rollout status deployment/myapp-deployment
 
# 롤아웃 히스토리
kubectl rollout history deployment/myapp-deployment

Deployment Strategy

전략동작다운타임
Recreate모든 기존 Pod 종료 → 새 Pod 생성O (일시적 중단)
RollingUpdate (기본값)하나씩 교체X (무중단)

Recreate 전략 (다운타임 O)

  1. Old v1 | Old v1 | Old v1 (모두 종료)
  2. --- 다운타임 ---
  3. New v2 | New v2 | New v2 (새로 생성)

RollingUpdate 전략 (무중단)

  1. Old v1 | Old v1 | Old v1
  2. Old v1 | Old v1 | New v2 (1개 교체)
  3. Old v1 | New v2 | New v2 (1개 교체)
  4. New v2 | New v2 | New v2 (1개 교체)

업데이트 방법

# 방법 1: YAML 파일 수정 후 적용
kubectl apply -f deployment-definition.yml
 
# 방법 2: 이미지 직접 변경
kubectl set image deployment/myapp-deployment nginx-container=nginx:1.9.1

kubectl set image는 실행 중인 deployment만 변경하고 YAML 파일에는 반영되지 않음

롤백

# 이전 버전으로 롤백
kubectl rollout undo deployment/myapp-deployment
 
# ReplicaSet 상태 확인 (롤백 전후 비교)
kubectl get replicasets

롤링 업데이트 내부 동작

단계Old ReplicaSet (축소)New ReplicaSet (확장)
1Pod Pod Pod(비어있음)
2Pod PodPod
3PodPod Pod
4(비어있음)Pod Pod Pod

롤백 시: 위 과정의 역순 (New → Old)

주요 명령어 정리

명령어설명
kubectl create -f deploy.ymlDeployment 생성
kubectl get deployments목록 조회
kubectl apply -f deploy.ymlYAML로 업데이트
kubectl set image deployment/... img=v2이미지 변경
kubectl rollout status deployment/...롤아웃 상태
kubectl rollout history deployment/...히스토리
kubectl rollout undo deployment/...롤백

97-98. Labs - Rolling Updates and Rollbacks

# 현재 deployment의 strategy 확인
kubectl describe deployment <name> | grep -i strategy
 
# 롤아웃 히스토리에서 특정 revision 상세 보기
kubectl rollout history deployment/<name> --revision=2
 
# 특정 revision으로 롤백
kubectl rollout undo deployment/<name> --to-revision=1

99. Configure Applications

  • Pod에 애플리케이션 설정을 주입하는 방법 3가지:
    1. Command & Arguments (컨테이너 실행 명령 변경)
    2. Environment Variables (환경 변수 설정)
    3. ConfigMaps / Secrets (설정 데이터 외부화)

100. Commands and Arguments in Docker

컨테이너 프로세스 생명주기

  • 컨테이너는 하나의 프로세스를 실행하기 위해 설계됨
  • 프로세스가 종료되면 컨테이너도 종료
# Ubuntu 컨테이너 → 기본 CMD가 bash → 터미널 없으면 즉시 종료
docker run ubuntu
docker ps -a  # → Exited (0) 상태
 
# sleep 명령으로 오버라이드
docker run ubuntu sleep 5

CMD vs ENTRYPOINT

# CMD만 사용 - 런타임 인자가 CMD 전체를 대체
FROM ubuntu
CMD ["sleep", "5"]
 
# ENTRYPOINT 사용 - 런타임 인자가 ENTRYPOINT 뒤에 추가됨
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["5"]           # 기본값
# CMD만 있을 때
docker run ubuntu-sleeper          # → sleep 5
docker run ubuntu-sleeper 10       # → sleep 10 (CMD 대체)
 
# ENTRYPOINT + CMD일 때
docker run ubuntu-sleeper          # → sleep 5 (CMD가 기본 인자)
docker run ubuntu-sleeper 10       # → sleep 10 (CMD만 오버라이드)
 
# ENTRYPOINT 자체를 변경
docker run --entrypoint sleep2.0 ubuntu-sleeper 10  # → sleep2.0 10

ENTRYPOINT = 실행할 명령, CMD = 기본 인자값. 둘을 조합하면 유연한 컨테이너 구성 가능


101. Commands and Arguments in Kubernetes

Docker → Kubernetes 매핑

DockerfileKubernetes Pod Spec역할
ENTRYPOINTcommand실행할 명령어 (완전 대체)
CMDargs명령어에 전달할 인자 (기본값 대체)
# Docker: docker run --entrypoint sleep2.0 ubuntu-sleeper 10
# Kubernetes 동일 설정:
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper-pod
spec:
  containers:
  - name: ubuntu-sleeper
    image: ubuntu-sleeper
    command: ["sleep2.0"]   # ENTRYPOINT 대체
    args: ["10"]            # CMD 대체
# Dockerfile에 ENTRYPOINT ["sleep"], CMD ["5"]가 작성된 상태
# CMD만 오버라이드 (sleep 시간만 변경)
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-sleeper-pod
spec:
  containers:
  - name: ubuntu-sleeper
    image: ubuntu-sleeper
    args: ["10"]   # CMD "5" → "10"으로 변경

102-103. Labs - Commands and Arguments

# Pod의 command/args 확인
kubectl describe pod <name> | grep -A5 "Command\|Args"
 
# YAML로 확인
kubectl get pod <name> -o yaml | grep -A5 "command\|args"

104. Configure Environment Variables in Applications

# 방법 1: 직접 지정 (Plain Key-Value)
spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
    env:
    - name: APP_COLOR
      value: pink
 
# 방법 2: ConfigMap에서 가져오기
    env:
    - name: APP_COLOR
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: APP_COLOR
 
# 방법 3: Secret에서 가져오기
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: DB_PASSWORD

105. Configuring ConfigMaps in Applications

공식문서: ConfigMaps

ConfigMap 생성

# Imperative - literal
kubectl create configmap app-config \
  --from-literal=APP_COLOR=blue \
  --from-literal=APP_MODE=prod
 
# Imperative - 파일에서
kubectl create configmap app-config --from-file=app_config.properties
# Declarative
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_COLOR: blue
  APP_MODE: prod

ConfigMap을 Pod에 주입

# 전체 ConfigMap을 환경 변수로 주입
spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
    envFrom:
    - configMapRef:
        name: app-config
 
# 개별 키만 주입
    env:
    - name: APP_COLOR
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: APP_COLOR
 
# Volume으로 마운트
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config
# ConfigMap 조회
kubectl get configmaps
kubectl describe configmap app-config

106-107. Labs - Env Variables

# Pod의 환경 변수 확인
kubectl describe pod <name> | grep -A10 "Environment"
 
# ConfigMap 내용 확인
kubectl get configmap <name> -o yaml
 
# pod env 강제 적용
kubectl edit pod <name>
 
# 변경 후 임시 파일 id 출력됨
# 해당 id를 이용해 replace
kubectl replace --force -f /tmp/kubectl-edit-<id>yaml

108. Secrets

공식문서: Secrets

ConfigMap vs Secret

구분ConfigMapSecret
용도일반 설정 데이터민감한 데이터 (비밀번호, 키 등)
저장 형태평문Base64 인코딩 (보안을 위해서가 아니라 단순히 직렬화 하기 위해서)
etcd 저장평문기본 Base64 (암호화 별도 설정 필요)

Secret 생성

# Imperative
kubectl create secret generic app-secret \
  --from-literal=DB_Host=mysql \
  --from-literal=DB_User=root \
  --from-literal=DB_Password=paswrd
 
# 파일에서 생성
kubectl create secret generic app-secret --from-file=app_secret.properties 
# Declarative (값은 Base64로 인코딩해야 함)
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
data:
  DB_Host: bXlzcWw=        # echo -n 'mysql' | base64
  DB_User: cm9vdA==        # echo -n 'root' | base64
  DB_Password: cGFzd3Jk    # echo -n 'paswrd' | base64

Base64 인코딩/디코딩

# 인코딩
echo -n 'mysql' | base64     # → bXlzcWw=
echo -n 'root' | base64      # → cm9vdA==
 
# 디코딩
echo -n 'bXlzcWw=' | base64 --decode  # → mysql

Secret을 Pod에 주입

# 환경 변수로 주입
spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
    envFrom:
    - secretRef:
        name: app-secret
 
# Volume으로 마운트 (각 키가 파일로 생성됨)
    volumeMounts:
    - name: secret-volume
      mountPath: /opt/app-secret-volumes
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: app-secret
# 마운트 후 파일 확인
ls /opt/app-secret-volumes/    # → DB_Host  DB_Password  DB_User
cat /opt/app-secret-volumes/DB_Password  # → paswrd

Secret 조회

kubectl get secrets
kubectl describe secret app-secret       # 값 숨김
kubectl get secret app-secret -o yaml    # Base64 인코딩 값 표시

Secret은 Base64 인코딩일 뿐 암호화가 아님. etcd에 접근 가능하면 디코딩 가능


109-111. Labs - Secrets

# Secret 개수 확인
kubectl get secrets
 
# Secret의 키 확인
kubectl describe secret <name>
 
# Secret 값 디코딩
kubectl get secret <name> -o jsonpath='{.data.password}' | base64 --decode

112. Demo: Encrypting Secret Data at Rest

문제: etcd에 Secret이 평문(Base64) 저장

# etcd에서 Secret 직접 조회 → 평문 노출
ETCDCTL_API=3 etcdctl \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  get /registry/secrets/default/my-secret | hexdump -C

해결: Encryption at Rest 활성화

# 1. 암호화 키 생성
head -c 32 /dev/urandom | base64
# 2. EncryptionConfiguration 파일 작성 (enc.yaml)
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <생성된_base64_키>
  - identity: {}
# 3. kube-apiserver에 설정 추가
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
  containers:
  - command:
    - kube-apiserver
    - --encryption-provider-config=/etc/kubernetes/enc/enc.yaml
    volumeMounts:
    - name: enc
      mountPath: /etc/kubernetes/enc
      readOnly: true
  volumes:
  - name: enc
    hostPath:
      path: /etc/kubernetes/enc
      type: DirectoryOrCreate
# 4. 기존 Secret도 재암호화
kubectl get secret --all-namespaces -o json | kubectl replace -f -

암호화 활성화 이전에 만든 Secret은 자동 암호화되지 않음 → kubectl replace로 재저장 필요


113. A Note on Secrets

Secret 보안 Best Practice

  1. Secret 정의 YAML을 공개 리포지토리에 올리지 않기
  2. RBAC 으로 Secret 접근 권한 제한
  3. Encryption at Rest 활성화
  4. 3rd party 솔루션 고려: AWS Secrets Manager, Azure Key Vault, HashiCorp Vault

114. Scale Applications

  • 수동 스케일링: kubectl scale deployment <name> --replicas=N
  • 자동 스케일링: HPA, VPA (이후 섹션에서 다룸)

114-A. Jobs and CronJobs (CKA 필수)

공식문서: Jobs / CronJob

Job vs CronJob

구분JobCronJob
역할일회성 배치 작업 (완료까지만 실행)스케줄 기반 반복 Job 생성
비유한 번 실행 스크립트cron + 스크립트
예시DB 마이그레이션, 영상 인코딩매시간 백업, 매일 리포트

Job imperative 치트

# ── 기본 생성 ──────────────────────────────────────────────
kubectl create job one-time --image=busybox -- echo hello
 
# 명령어가 길면 -- 뒤에 인자 나열
kubectl create job backup --image=busybox -- /bin/sh -c "tar -czf /backup/data.tgz /data"
 
# ── YAML로 뽑아서 세부 수정 ────────────────────────────────
kubectl create job my-job --image=busybox $do -- echo hi > job.yaml
# → completions, parallelism, backoffLimit, activeDeadlineSeconds 등 추가 수정

Job YAML 주요 필드

apiVersion: batch/v1
kind: Job
metadata:
  name: my-job
spec:
  completions: 3          # 몇 번 성공해야 완료로 볼지 (기본 1)
  parallelism: 2          # 동시에 몇 개 Pod 실행 (기본 1)
  backoffLimit: 4         # 실패 재시도 횟수 (기본 6)
  activeDeadlineSeconds: 300   # 최대 실행 시간
  template:
    spec:
      restartPolicy: Never   # Job은 Never 또는 OnFailure만 가능
      containers:
      - name: worker
        image: busybox
        command: ["echo", "hello"]

CronJob imperative 치트

# ── 기본 생성 (cron 문법 주의) ────────────────────────────
kubectl create cronjob hourly \
  --image=busybox \
  --schedule="0 * * * *" \
  -- /bin/sh -c "date; echo hello"
 
# ── 5분마다 ────────────────────────────────────────────────
kubectl create cronjob every-5m --image=busybox --schedule="*/5 * * * *" -- date
 
# ── 매일 자정 ──────────────────────────────────────────────
kubectl create cronjob daily --image=busybox --schedule="0 0 * * *" -- date
 
# ── 기존 CronJob에서 즉시 Job 실행 (시험 빈출!) ─────────────
kubectl create job --from=cronjob/hourly manual-run-1
 
# ── YAML로 뽑기 ────────────────────────────────────────────
kubectl create cronjob test --image=busybox --schedule="* * * * *" $do -- date > cj.yaml

cron 표현식 빠른 참조

 ┌── 분 (0-59)
 │  ┌── 시 (0-23)
 │  │  ┌── 일 (1-31)
 │  │  │  ┌── 월 (1-12)
 │  │  │  │  ┌── 요일 (0-6, 0=일요일)
 │  │  │  │  │
 *  *  *  *  *

# 자주 쓰는 예시
*/5 * * * *    → 5분마다
0 * * * *      → 매시 정각
0 0 * * *      → 매일 자정
0 9 * * 1-5    → 평일 오전 9시

Job / CronJob 상태 확인

# Job 상태
kubectl get jobs
kubectl describe job my-job
kubectl logs job/my-job     # Job의 로그
 
# CronJob 상태
kubectl get cronjobs
kubectl get cj              # 약어
kubectl describe cj hourly
 
# CronJob이 생성한 Job 이력
kubectl get jobs --selector=job-name
 
# 실행 중단
kubectl patch cronjob hourly -p '{"spec":{"suspend":true}}'
kubectl patch cronjob hourly -p '{"spec":{"suspend":false}}'

CronJob 히스토리 관리

spec:
  successfulJobsHistoryLimit: 3    # 성공한 Job 보관 개수
  failedJobsHistoryLimit: 1        # 실패한 Job 보관 개수
  concurrencyPolicy: Forbid         # Allow / Forbid / Replace
  startingDeadlineSeconds: 60       # 지연 허용 시간
concurrencyPolicy의미
Allow (기본)동시 실행 허용
Forbid이전 Job 실행 중이면 건너뜀
Replace이전 Job 중단하고 새 Job 실행

115. Multi Container Pods

  • 하나의 Pod에 여러 컨테이너가 같은 생명주기를 공유
  • 동일한 네트워크 (localhost 통신), 동일한 볼륨 접근

Pod 안의 컨테이너들은 함께 생성/종료

  • Web AppLog Agent — localhost 통신
  • 두 컨테이너가 Shared Volume 공유
apiVersion: v1
kind: Pod
metadata:
  name: simple-webapp
spec:
  containers:
  - name: simple-webapp
    image: simple-webapp
    ports:
    - containerPort: 8080
  - name: log-agent
    image: log-agent

116. Multi Container Pods Design Pattern

패턴역할예시
Sidecar메인 컨테이너의 기능을 보강로그 수집기, 프록시
Ambassador외부 통신을 대리DB 프록시, API gateway
Adapter출력 데이터를 변환/표준화로그 포맷 변환, 모니터링 데이터 변환
  • Sidecar: App ↔ Log Collector
  • Ambassador: App → Proxy → DB (Dev/Staging/Prod)
  • Adapter: App → Adapter → Monitoring System

117. Labs - Multi Container Pods

공식문서: Sidecar Containers (Native Sidecar 관련)

# Pod 내 컨테이너 수 확인
kubectl describe pod <name> | grep -c "Container ID"
 
# 특정 컨테이너 로그 확인
kubectl logs <pod-name> -c <container-name>
 
# 특정 컨테이너에 접속
kubectl exec -it <pod-name> -c <container-name> -- /bin/sh

(2025) Native Sidecar Container (v1.28+)

v1.28부터 InitContainer에 restartPolicy: Always 를 지정하면 Native Sidecar로 동작함.

기존 SidecarNative Sidecar
메인 컨테이너와 동시 시작/종료메인보다 먼저 시작, 나중에 종료
Job에서 문제 발생 (Job이 메인 종료해도 사이드카 살아있음)Job 친화적
Probe 지원 미흡Liveness/Readiness 지원
apiVersion: v1
kind: Pod
metadata:
  name: app-with-native-sidecar
spec:
  initContainers:
  - name: log-shipper
    image: fluentd:latest
    restartPolicy: Always    # ★ 이 줄이 핵심: Native Sidecar
    volumeMounts:
    - name: logs
      mountPath: /var/log
  containers:
  - name: main-app
    image: my-app
    volumeMounts:
    - name: logs
      mountPath: /var/log
  volumes:
  - name: logs
    emptyDir: {}

v1.29에서 Beta, v1.33에서 GA 예정. CKA 시험에도 반영 시작.


118. InitContainers

공식문서: Init Containers

Init Container란?

“메인 컨테이너가 시작되기 전에 ‘먼저 해둬야 할 일’을 처리하는 전용 컨테이너”

왜 필요한가? (메인 컨테이너에서 하면 안 되나?)

  • 메인 앱 이미지는 앱 실행만 하도록 작게 유지하고 싶음
  • 초기화 스크립트/도구를 앱 이미지에 넣으면 이미지가 커지고 보안 공격면 증가
  • 의존 서비스(DB 등)가 준비될 때까지 기다리는 로직을 메인 코드에 넣으면 앱이 지저분해짐

Init Container가 해결하는 전형적 시나리오:

  • “DB가 켜질 때까지 대기 후 앱 시작”
  • “Git에서 설정 파일 clone 후 앱 시작”
  • “DB 스키마 마이그레이션 후 앱 시작”

특징:

  • 여러 개 순차 실행 (하나씩 완료되어야 다음으로)

  • 모두 성공해야 메인 컨테이너 시작

  • 실패하면 restartPolicy에 따라 전체 Pod 재시작

  • Pod의 메인 컨테이너 실행 전에 한 번만 실행되는 초기화 컨테이너

  • 순서대로 실행되며, 하나가 실패하면 Pod 재시작

사용 사례

  • DB 마이그레이션, 설정 파일 다운로드, 의존 서비스 대기
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting; sleep 2; done']
  - name: init-mydb
    image: busybox
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting; sleep 2; done']
  containers:
  - name: myapp-container
    image: myapp

InitContainer 실행 순서:

  1. init-myservice 실행 → 완료
  2. init-mydb 실행 → 완료
  3. myapp-container 시작

InitContainer가 실패하면 Kubernetes가 Pod를 재시작 (restartPolicy에 따라)


119-120. Labs - Init Containers

# InitContainer 상태 확인
kubectl describe pod <name> | grep -A10 "Init Containers"
 
# InitContainer 로그 확인
kubectl logs <pod-name> -c <init-container-name>

121. Self Healing Applications

  • Kubernetes는 ReplicaSet/Deployment를 통해 자동 복구
  • Pod 실패 시 자동으로 새 Pod 생성

Probe 3종 비교

Probe역할실패 시 동작사용 시점
Liveness컨테이너 살아있나?재시작애플리케이션 데드락 감지
Readiness트래픽 받을 준비?Service Endpoint 제외앱 시작 지연 / 일시 과부하
Startup (v1.18+)시작 완료됐나?재시작 (완료 전까지 다른 Probe 억제)느린 시작 앱 (Java 등)

Probe 3가지 진단 방식

방식예시
HTTP GET/healthz 경로 200 OK 응답 확인
TCP Socket특정 포트 연결 가능 여부
Exec컨테이너 내 명령 실행 후 exit 0 확인

Probe YAML 예시

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: my-app
    ports:
    - containerPort: 8080
 
    # 1) Startup Probe: 첫 기동까지 최대 5*30=150초 허용
    startupProbe:
      httpGet:
        path: /healthz
        port: 8080
      failureThreshold: 30
      periodSeconds: 5
 
    # 2) Liveness Probe: 30초마다 체크, 3번 실패하면 재시작
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 30
      failureThreshold: 3
 
    # 3) Readiness Probe: TCP로 8080 포트 열렸는지
    readinessProbe:
      tcpSocket:
        port: 8080
      periodSeconds: 5
 
    # Exec 방식 예시
    # livenessProbe:
    #   exec:
    #     command: ["cat", "/tmp/healthy"]

Probe 주요 옵션

옵션의미기본값
initialDelaySeconds첫 체크 전 대기0
periodSeconds체크 간격10
timeoutSeconds응답 대기 시간1
successThreshold성공 판정 횟수1
failureThreshold실패 판정 횟수3

시험 문제에서 "Pod가 CrashLoopBackOff" → livenessProbe 설정 확인. "Service가 Endpoint 안 잡힘" → readinessProbe 확인.


122. (2025) Introduction to Autoscaling

Autoscaling이란?

“트래픽에 따라 Pod 수 또는 리소스를 자동으로 늘리고 줄이는 것”

왜 필요한가?

  • 밤엔 사용자 적고 → 자원 낭비
  • 낮에 트래픽 몰리면 → Pod 부족으로 느려짐
  • 사람이 매번 kubectl scale 치기는 불가능

2가지 방향:

  • HPA (Horizontal): Pod 개수를 늘림 — 상태 없는 웹 앱에 적합
  • VPA (Vertical): Pod 하나의 리소스(CPU/Mem) 를 늘림 — 상태 있는 앱 / 단일 인스턴스 앱

전통적 스케일링 vs Kubernetes 스케일링

구분HorizontalVertical
클러스터 인프라노드 추가노드 리소스 증가
워크로드Pod 수 증가Pod 리소스(CPU/Mem) 증가

수동 vs 자동

스케일링 대상수동자동
클러스터 인프라kubeadm joinCluster Autoscaler
워크로드 (수평)kubectl scale --replicas=NHPA
워크로드 (수직)kubectl editVPA

123. (2025) Horizontal Pod Autoscaler (HPA)

  • Pod 수를 자동으로 조절 (CPU/Memory 사용량 기반)
  • Metrics Server 필수
# Imperative 방식으로 HPA 생성
kubectl autoscale deployment my-app --cpu-percent=50 --min=1 --max=10
 
# HPA 상태 확인
kubectl get hpa
 
# HPA 삭제
kubectl delete hpa my-app
# Declarative 방식
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

HPA 동작 흐름:

  1. Metrics Server가 CPU/메모리 사용률 수집
  2. HPA Controller가 임계값과 비교
  3. 임계값 초과 → Pod 수 증가
  4. 정상 범위 → 현재 유지 (또는 축소)

HPA는 Pod spec에 resources.requests가 정의되어 있어야 정상 동작


124-125. Labs - Manual Scaling & HPA

# 수동 스케일링
kubectl scale deployment my-app --replicas=5
 
# HPA 생성 후 모니터링
kubectl get hpa -w  # watch 모드

126. (2025) In-Place Resize of Pods

  • Kubernetes v1.27+ (alpha feature)
  • Pod를 재시작하지 않고 CPU/Memory 리소스 변경 가능
  • spec.containers[].resizePolicy 필드 사용
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx
    resources:
      requests:
        cpu: "250m"
        memory: "128Mi"
      limits:
        cpu: "500m"
        memory: "256Mi"
    resizePolicy:
    - resourceName: cpu
      restartPolicy: NotRequired    # 재시작 없이 변경
    - resourceName: memory
      restartPolicy: RestartContainer  # 메모리는 재시작 필요
# Pod 리소스 변경 (kubectl patch)
kubectl patch pod my-pod --subresource resize --patch \
  '{"spec":{"containers":[{"name":"my-container","resources":{"requests":{"cpu":"500m"},"limits":{"cpu":"1"}}}]}}'

Feature Gate InPlacePodVerticalScaling=true 활성화 필요


127. (2025) Vertical Pod Autoscaling (VPA)

공식문서: Vertical Pod Autoscaler (GitHub) — VPA는 별도 컴포넌트라 메인 docs에 없음

  • 개별 Pod의 리소스(CPU/Memory)를 자동 조절
  • HPA가 Pod 수를 조절하는 것과 달리, VPA는 각 Pod의 리소스 할당을 최적화

VPA 구성 요소

컴포넌트역할
Recommender리소스 사용량 분석 → 적절한 값 추천
Updater추천값과 현재값 비교 → 변경 필요 시 Pod 재시작
Admission Controller새 Pod 생성 시 추천 리소스 값 적용
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Auto"    # Off, Initial, Recreate, Auto
  resourcePolicy:
    containerPolicies:
    - containerName: my-container
      minAllowed:
        cpu: "100m"
        memory: "50Mi"
      maxAllowed:
        cpu: "2"
        memory: "2Gi"

VPA updateMode

Mode동작
Off추천만 제공, 변경 X
InitialPod 생성 시에만 적용
RecreatePod를 재생성하여 적용
Auto가능하면 In-place, 아니면 재생성
# VPA 설치
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
./hack/vpa-up.sh
 
# VPA 상태 확인
kubectl get vpa
kubectl describe vpa my-app-vpa

VPA와 HPA를 같은 메트릭(CPU/Memory)으로 동시 사용하면 충돌. 서로 다른 메트릭 기반이면 공존 가능


128-129. Labs - VPA

# VPA 설치 확인
kubectl get pods -n kube-system | grep vpa
 
# VPA 추천값 확인
kubectl describe vpa <name>
# → Recommendation 섹션에서 Target, Lower Bound, Upper Bound 확인
 
# VPA 리소스 정책 확인
kubectl get vpa <name> -o yaml

핵심 개념 요약

Application Lifecycle 전체 흐름

flowchart TD
    D["1.<br/>배포<br/>(Deployment)"] --> U["2.<br/>업데이트<br/>(Rolling Update)"]
    U --> R[3.<br/>문제 발생 → Rollback]
    D --> C["4.<br/>설정<br/>관리<br/>(ConfigMap/Secret)"]
    D --> M["5.<br/>멀티<br/>컨테이너<br/>(Sidecar/Ambassador/Adapter)"]
    D --> I["6.<br/>초기화<br/>(InitContainer)"]
    D --> A["7.<br/>자동 스케일링<br/>(HPA/VPA)"]

Docker → Kubernetes 명령어 매핑

DockerKubernetes설명
ENTRYPOINTcommand실행 명령어
CMDargs기본 인자
docker run -e KEY=VALenv / envFrom환경 변수
--entrypointcommand (override)명령어 변경

kubectl set 통합 치트

kubectl set기존 리소스의 자주 바꾸는 필드만 빠르게 수정하는 명령. 시험장에서 가장 많이 쓰이는 명령 중 하나.

# ── 이미지 변경 (rolling update 트리거) ────────────────────
kubectl set image deploy/web web=nginx:1.21
kubectl set image pod/mypod mycontainer=nginx:1.21
# 여러 컨테이너 동시 변경
kubectl set image deploy/web web=nginx:1.21 sidecar=fluentd:1.16
 
# ── 환경 변수 관리 ────────────────────────────────────────
kubectl set env deploy/web DB_HOST=mysql
kubectl set env deploy/web DB_PORT=3306 DB_USER=admin     # 여러 개
kubectl set env deploy/web DB_HOST-                        # 삭제 (끝에 - 붙임)
kubectl set env deploy/web --from=configmap/app-cfg        # ConfigMap 전체 주입
kubectl set env deploy/web --from=secret/app-sec           # Secret 전체 주입
 
# ── ServiceAccount 변경 ───────────────────────────────────
kubectl set serviceaccount deploy/web my-sa
 
# ── 리소스 요청/제한 변경 ─────────────────────────────────
kubectl set resources deploy/web --requests=cpu=100m,memory=256Mi
kubectl set resources deploy/web --limits=cpu=500m,memory=512Mi
kubectl set resources deploy/web --requests=cpu=100m --limits=cpu=500m
 
# ── 이미지 풀 정책 ────────────────────────────────────────
kubectl set image-pull-policy deploy/web Always   # 구형 문법
# 최신: patch 또는 edit 사용
kubectl patch deploy web -p \
  '{"spec":{"template":{"spec":{"containers":[{"name":"web","imagePullPolicy":"Always"}]}}}}'
 
# ── Selector 변경 (드물지만 필요) ──────────────────────────
kubectl set selector svc web 'app=web,tier=front'
 
# ── 구독자(subject) 변경 - RBAC ────────────────────────────
kubectl set subject rolebinding rb --user=newuser

rollout 명령어 전체

# 상태 확인
kubectl rollout status deploy/web
 
# 히스토리
kubectl rollout history deploy/web
kubectl rollout history deploy/web --revision=2   # 특정 revision 상세
 
# 일시 정지 / 재개 (카나리 배포용)
kubectl rollout pause deploy/web
kubectl set image deploy/web web=nginx:1.22       # 멈춘 상태에서 여러 수정
kubectl set resources deploy/web --limits=cpu=1
kubectl rollout resume deploy/web                  # 일괄 반영
 
# 재시작 (Pod 강제 재생성)
kubectl rollout restart deploy/web
 
# 롤백
kubectl rollout undo deploy/web
kubectl rollout undo deploy/web --to-revision=2

kubectl rollout restart 는 시크릿/ConfigMap 변경 후 반영할 때 자주 씀 (Pod는 자동 갱신 안됨)