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-deploymentDeployment Strategy
| 전략 | 동작 | 다운타임 |
|---|---|---|
| Recreate | 모든 기존 Pod 종료 → 새 Pod 생성 | O (일시적 중단) |
| RollingUpdate (기본값) | 하나씩 교체 | X (무중단) |
Recreate 전략 (다운타임 O)
Old v1 | Old v1 | Old v1(모두 종료)--- 다운타임 ---New v2 | New v2 | New v2(새로 생성)
RollingUpdate 전략 (무중단)
Old v1 | Old v1 | Old v1Old v1 | Old v1 | New v2(1개 교체)Old v1 | New v2 | New v2(1개 교체)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 (확장) |
|---|---|---|
| 1 | Pod Pod Pod | (비어있음) |
| 2 | Pod Pod | Pod |
| 3 | Pod | Pod Pod |
| 4 | (비어있음) | Pod Pod Pod |
롤백 시: 위 과정의 역순 (New → Old)
주요 명령어 정리
| 명령어 | 설명 |
|---|---|
kubectl create -f deploy.yml | Deployment 생성 |
kubectl get deployments | 목록 조회 |
kubectl apply -f deploy.yml | YAML로 업데이트 |
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=199. Configure Applications
- Pod에 애플리케이션 설정을 주입하는 방법 3가지:
- Command & Arguments (컨테이너 실행 명령 변경)
- Environment Variables (환경 변수 설정)
- ConfigMaps / Secrets (설정 데이터 외부화)
100. Commands and Arguments in Docker
컨테이너 프로세스 생명주기
- 컨테이너는 하나의 프로세스를 실행하기 위해 설계됨
- 프로세스가 종료되면 컨테이너도 종료
# Ubuntu 컨테이너 → 기본 CMD가 bash → 터미널 없으면 즉시 종료
docker run ubuntu
docker ps -a # → Exited (0) 상태
# sleep 명령으로 오버라이드
docker run ubuntu sleep 5CMD 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 10ENTRYPOINT = 실행할 명령, CMD = 기본 인자값. 둘을 조합하면 유연한 컨테이너 구성 가능
101. Commands and Arguments in Kubernetes
Docker → Kubernetes 매핑
| Dockerfile | Kubernetes Pod Spec | 역할 |
|---|---|---|
ENTRYPOINT | command | 실행할 명령어 (완전 대체) |
CMD | args | 명령어에 전달할 인자 (기본값 대체) |
# 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_PASSWORD105. 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: prodConfigMap을 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-config106-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>yaml108. Secrets
공식문서: Secrets
ConfigMap vs Secret
| 구분 | ConfigMap | Secret |
|---|---|---|
| 용도 | 일반 설정 데이터 | 민감한 데이터 (비밀번호, 키 등) |
| 저장 형태 | 평문 | 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' | base64Base64 인코딩/디코딩
# 인코딩
echo -n 'mysql' | base64 # → bXlzcWw=
echo -n 'root' | base64 # → cm9vdA==
# 디코딩
echo -n 'bXlzcWw=' | base64 --decode # → mysqlSecret을 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 # → paswrdSecret 조회
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 --decode112. 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
- Secret 정의 YAML을 공개 리포지토리에 올리지 않기
- RBAC 으로 Secret 접근 권한 제한
- Encryption at Rest 활성화
- 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 필수)
Job vs CronJob
| 구분 | Job | CronJob |
|---|---|---|
| 역할 | 일회성 배치 작업 (완료까지만 실행) | 스케줄 기반 반복 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.yamlcron 표현식 빠른 참조
┌── 분 (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 App ↔ Log 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-agent116. 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로 동작함.
| 기존 Sidecar | Native 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: myappInitContainer 실행 순서:
init-myservice실행 → 완료init-mydb실행 → 완료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 스케일링
| 구분 | Horizontal | Vertical |
|---|---|---|
| 클러스터 인프라 | 노드 추가 | 노드 리소스 증가 |
| 워크로드 | Pod 수 증가 | Pod 리소스(CPU/Mem) 증가 |
수동 vs 자동
| 스케일링 대상 | 수동 | 자동 |
|---|---|---|
| 클러스터 인프라 | kubeadm join | Cluster Autoscaler |
| 워크로드 (수평) | kubectl scale --replicas=N | HPA |
| 워크로드 (수직) | kubectl edit | VPA |
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: 50HPA 동작 흐름:
- Metrics Server가 CPU/메모리 사용률 수집
- HPA Controller가 임계값과 비교
- 임계값 초과 → Pod 수 증가
- 정상 범위 → 현재 유지 (또는 축소)
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 |
| Initial | Pod 생성 시에만 적용 |
| Recreate | Pod를 재생성하여 적용 |
| 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-vpaVPA와 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 명령어 매핑
| Docker | Kubernetes | 설명 |
|---|---|---|
ENTRYPOINT | command | 실행 명령어 |
CMD | args | 기본 인자 |
docker run -e KEY=VAL | env / envFrom | 환경 변수 |
--entrypoint | command (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=newuserrollout 명령어 전체
# 상태 확인
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는 자동 갱신 안됨)