이 글은 이번 세션에서 다룬 내용을 운영 관점으로 한 번에 꿰는 “총 정리본”입니다. 단순 기능 나열이 아니라, “왜 필요한가 / 어디서 실수하는가 / 실무에서 어떤 선택을 하는가”까지 한 흐름으로 정리합니다.
목차
- 클러스터 모니터링: Metrics Server의 역할과 한계
- 로깅 기초:
kubectl logs와 멀티 컨테이너 로그 - 배포(Deployment) 업데이트 & 롤백: 리비전과 전략
- 컨테이너 실행 모델: CMD/ENTRYPOINT ↔ Pod
command/args - 환경 변수와 구성 관리: Env → ConfigMap → Secret
- Secret은 왜 Base64인가? ConfigMap과 “같아 보이는” 이유와 진짜 차이
- etcd 저장 시(At-Rest) Secret 암호화: EncryptionConfiguration
- 멀티 컨테이너 파드: colocated / init / sidecar, 그리고 “먼저 실행” 문제
- 오토스케일링: HPA(수평)·VPA(수직)·In-place 리사이징, 그리고 선택 기준
1) 클러스터 모니터링: Metrics Server의 역할과 한계
쿠버네티스 운영에서 “뭘 모니터링할 것인가”는 크게 3단입니다.
- 노드 수준 메트릭: 노드 수, Ready 노드 수, 노드 CPU/메모리/디스크/네트워크 사용률
- 파드 수준 메트릭: 파드 수, 파드별 CPU/메모리 사용량
- 분석/장기 보관: 과거 추세, 이상 탐지, 대시보드, 알림
쿠버네티스는 “완전한 내장 모니터링”을 기본 제공하지 않습니다. 대신 선택지는 다음처럼 나뉩니다.
- Metrics Server: “지금 현재”에 가까운 리소스 사용량(짧은 window)을 제공
- Prometheus / Elastic / Datadog / Dynatrace: 저장·분석·대시보드·알림까지 포함(장기 보관 가능)
Metrics Server는 뭘 하는가?
- 각 노드의 kubelet이 노출하는 리소스 메트릭을 수집/집계
- 결과를 메모리(in-memory)에 보관
- 그래서
kubectl top node,kubectl top pod같은 즉시성 조회에 사용
핵심 한계: 디스크에 장기 보관하지 않으므로 “지난주 추세” 같은 건 Metrics Server만으로 불가능합니다.
빠른 확인 명령
kubectl top node
kubectl top pod -A
2) 로깅 기초: kubectl logs와 멀티 컨테이너 로그
컨테이너 로그의 기본은 “표준 출력(stdout/stderr)”입니다.
- Docker:
docker logs <container> [-f] - Kubernetes:
kubectl logs <pod> [-f]
단일 컨테이너 파드
kubectl logs pod/event-simulator -f
멀티 컨테이너 파드: 컨테이너 지정 필수
파드 안에 컨테이너가 여러 개면 어느 컨테이너 로그를 볼지 지정해야 합니다.
kubectl logs pod/my-pod -c event-simulator -f
kubectl logs pod/my-pod -c image-processor -f
운영 팁: 멀티 컨테이너 파드는 로그/메트릭/트러블슈팅이 복잡해지므로 “패턴 목적(사이드카/초기화 등)”이 분명할 때만 사용하세요.
3) 배포 업데이트 & 롤백: 리비전과 전략
Deployment는 변경을 “리비전(Revision)”으로 기록합니다.
- Deployment 생성 → 롤아웃 트리거 → ReplicaSet 생성(Revision 1)
- 이미지/설정 변경 → 새 롤아웃 → 새 ReplicaSet 생성(Revision 2 …)
- 덕분에 변경 추적과 롤백이 가능합니다.
상태/이력 확인
kubectl rollout status deploy/myapp
kubectl rollout history deploy/myapp
배포 전략 2가지
1) Recreate
- 기존 파드를 전부 내리고, 새 버전을 전부 올림
- 단점: 중간에 서비스 다운 가능
2) RollingUpdate (기본값)
- 기존 파드를 조금씩 내리면서 새 파드를 조금씩 올림
- 무중단에 유리
Deployment 이벤트/동작을 보고 싶으면:
kubectl describe deploy/myapp
kubectl get rs
업데이트 방법
선언형(권장)
매니페스트 수정 후 apply:
kubectl apply -f deploy.yaml
명령형(주의)
kubectl set image deploy/myapp app=myorg/app:2.0
주의: YAML과 실제 상태가 달라질 수 있어, 이후 운영/배포 자동화에서 혼란이 생기기 쉽습니다.
롤백
kubectl rollout undo deploy/myapp
4) 컨테이너 실행 모델: CMD/ENTRYPOINT ↔ Pod command/args
이 파트는 운영에서 자주 터지는 문제(“컨테이너가 바로 죽어요”, “명령이 왜 바뀌죠?”)의 근본 원인입니다.
Docker 기준
- ENTRYPOINT: “실행 파일/고정 커맨드”
- CMD: “기본 인자(default args)” 또는 “기본 커맨드”
- 런타임에 전달한 값이 CMD를 대체하거나 ENTRYPOINT에 추가되는지에 따라 동작이 달라짐
Kubernetes로 오면 매핑이 이렇게 됩니다
- Pod의
command: Docker의 ENTRYPOINT를 오버라이드 - Pod의
args: Docker의 CMD를 오버라이드(또는 인자 제공)
예시: ubuntu-sleeper 이미지(ENTRYPOINT=["sleep"], CMD=["5"])
- 기본 실행:
sleep 5 - 파드에서 args만 바꾸면:
sleep 10
containers:
- name: sleeper
image: ubuntu-sleeper
args: ["10"]
- ENTRYPOINT 자체를 바꾸면(예:
sleep2.0같은 다른 실행 파일로 교체):command사용
containers:
- name: sleeper
image: ubuntu-sleeper
command: ["sleep"]
args: ["10"]
5) 환경 변수와 구성 관리: Env → ConfigMap → Secret
(1) 단순 env 직접 주입
env:
- name: APP_COLOR
value: blue
단점: 파드/배포 YAML이 많아지면 관리 지옥이 됩니다.
(2) ConfigMap으로 구성 중앙 관리
ConfigMap은 “민감하지 않은 구성”을 키-값으로 관리합니다.
생성(명령형)
kubectl create configmap appconfig --from-literal=APP_COLOR=blue
생성(선언형)
apiVersion: v1
kind: ConfigMap
metadata:
name: appconfig
data:
APP_COLOR: "blue"
파드 주입(환경 변수)
env:
- name: APP_COLOR
valueFrom:
configMapKeyRef:
name: appconfig
key: APP_COLOR
또는 전체를 한 번에:
envFrom:
- configMapRef:
name: appconfig
6) Secret은 왜 Base64인가? ConfigMap과 “같아 보이는” 이유와 진짜 차이
결론부터
- 맞습니다. Secret의 Base64는 암호화가 아닙니다.
누구든지 값을 보면 디코딩해서 원문을 얻습니다. - 그래서 “그럼 ConfigMap이랑 뭐가 달라?”라는 질문이 정확히 나옵니다.
Secret과 ConfigMap의 “진짜 차이”
Secret은 형식이 아니라 취급(보안 경로/권한/연계 기능)이 다릅니다.
- API 오브젝트 타입이 다르고, RBAC로 접근 통제 대상이 됨
- Secret을 볼 수 있는 권한은 최소화해야 함
- etcd 저장 시 암호화(At-Rest Encryption) 적용 대상이 됨
- ConfigMap은 보통 암호화 대상에서 제외하는 경우가 많음(선택 가능)
- K8s/플랫폼 연동이 Secret 중심으로 설계된 경우가 많음
- 예: 이미지 Pull Secret, ServiceAccount 토큰 등
- 운영 관점에서 “민감정보는 Secret”이라는 표준화
- 도구/정책/감사 대응에서 큰 차이를 만듦
즉, Base64가 보안의 핵심이 아니라, 권한 제어 + 저장 시 암호화 + 운영 표준이 핵심입니다.
kubectl create secret generic에서 generic은?
Secret 타입 중 하나입니다.
generic: 일반적인 키-값 시크릿(opaque 성격)- 그 외 예:
docker-registry: 레지스트리 인증용tls: 인증서/키 쌍
예:
kubectl create secret generic app-secret \
--from-literal=DB_HOST=mysql \
--from-literal=DB_USER=admin \
--from-literal=DB_PASS='p@ssw0rd'
7) etcd 저장 시(At-Rest) Secret 암호화: EncryptionConfiguration
Secret이 Base64라면, “클러스터 내부 저장(etcd)은 어떻게 보호하지?”가 다음 질문입니다.
기본 상태
- Secret 오브젝트는 etcd에 암호화되지 않은 형태로 저장될 수 있습니다
- etcd 접근권이 있는 사람은 민감정보를 볼 위험이 있습니다
해결: Encryption at Rest 활성화
개념은 간단합니다.
- EncryptionConfiguration 파일 생성
- kube-apiserver에
--encryption-provider-config=...로 전달 - 해당 파일을 apiserver Pod에 볼륨 마운트
EncryptionConfiguration 예시(aescbc + identity)
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <BASE64_32BYTE_KEY>
- identity: {}
- providers 순서가 매우 중요합니다
첫 번째 provider가 “암호화에 사용”됩니다.identity가 맨 위면 암호화가 사실상 꺼진 것과 같습니다.
“기존 Secret도 자동으로 암호화되나?”
- 암호화 활성화 이후 새로 저장되는 것부터 암호화되는 동작을 자주 보게 됩니다.
- 기존 데이터는 “재저장(rewrite)” 작업을 통해 다시 암호화되도록 정리합니다.
8) 멀티 컨테이너 파드: colocated / init / sidecar, 그리고 “먼저 실행” 문제
멀티 컨테이너 파드는 “같은 생명주기(shared lifecycle)”가 필요한 경우에 씁니다.
- 같은 네트워크 네임스페이스(서로
localhost로 통신 가능) - 같은 볼륨 공유 가능
- Pod 단위로 함께 스케일/함께 종료
3가지 패턴
(1) Co-located(기본 멀티 컨테이너)
spec.containers배열에 컨테이너 여러 개- 시작 순서 보장 없음
- 둘 다 파드 생명주기 동안 함께 실행
containers:
- name: web
image: nginx
- name: app
image: myapp
(2) Init Container
- 메인 컨테이너 전에 반드시 먼저 실행되어 완료되어야 하는 작업
- DB 준비 대기, 초기 데이터 다운로드 같은 “선행 작업”에 적합
- 완료 후 종료됨
initContainers:
- name: wait-db
image: busybox
command: ["sh","-c","until nc -z db 3306; do sleep 1; done"]
containers:
- name: app
image: myapp
(3) Sidecar
용어로는 “보조 기능 컨테이너” 패턴입니다. 중요한 건 이겁니다.
- 기술적으로
containers에 두면 co-located와 동일한 구조입니다. - 차이는 “역할과 운영 의도”입니다.
예: 로그 수집(filebeat), 프록시(envoy), 인증서 갱신, 모니터링 에이전트
“filebeat가 먼저 실행될지 어떻게 알아?”
기본 containers 방식에서는 보장 못 합니다.
그래서 “먼저 실행”이 진짜 요구라면 다음 중 하나로 해결합니다.
방법 A) 메인 컨테이너가 사이드카 준비를 기다리게 설계(가장 범용)
volumes:
- name: shared
emptyDir: {}
containers:
- name: filebeat
image: elastic/filebeat:8.12.0
volumeMounts:
- name: shared
mountPath: /shared
command: ["sh","-c"]
args:
- |
touch /shared/filebeat.ready
exec filebeat -e -c /etc/filebeat/filebeat.yml
- name: app
image: myapp:1.0
volumeMounts:
- name: shared
mountPath: /shared
command: ["sh","-c"]
args:
- |
until [ -f /shared/filebeat.ready ]; do sleep 1; done
exec /app/start
방법 B) 네이티브 사이드카(지원 클러스터에서): initContainer + restartPolicy: Always
클러스터가 지원한다면 “먼저 시작”을 구조적으로 만족시키는 방식이 있습니다.
initContainers:
- name: filebeat
image: elastic/filebeat:8.12.0
restartPolicy: Always
args: ["-c","/etc/filebeat/filebeat.yml","-e"]
containers:
- name: app
image: myapp:1.0
9) 오토스케일링: HPA·VPA·In-place 리사이징, 그리고 선택 기준
스케일링은 대상이 2개(워크로드/클러스터), 방식이 2개(수평/수직)라서 4칸으로 정리하면 혼동이 사라집니다.
| 대상 | 수평(Horizontal) | 수직(Vertical) |
|---|---|---|
| 워크로드 | 파드 수 증감(HPA) | 파드 리소스 증감(VPA/수동) |
| 클러스터 | 노드 수 증감(Cluster Autoscaler) | 노드 스펙 변경(덜 일반적) |
9-1) HPA: 파드 수를 자동으로 늘리고 줄인다
운영자가 하던 일을 HPA가 자동화합니다.
kubectl top pod로 보던 메트릭을 기반으로- Deployment/StatefulSet/ReplicaSet의 replicas를 자동 조절
전제조건
kubectl top/ HPA는 보통 Metrics Server가 필요합니다.
명령형 생성
kubectl autoscale deployment myapp --min=1 --max=10 --cpu-percent=50
kubectl get hpa
선언형(HPA v2 예시)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
“이 퍼센트는 파드별이야, 디플로이 총이야?”
HPA의 CPU utilization은 보통 파드(컨테이너)의 실제 사용량을 해당 파드의 requests.cpu로 나눈 비율 기반이며, 이를 평균 내서 판단합니다.
즉 디플로이먼트 총합이 아니라 파드(컨테이너) 단위가 기본입니다.
9-2) 파드 리소스 변경은 기본적으로 “재생성”이다
Deployment에서 resources.requests/limits를 바꾸면 기본 동작은:
- 기존 파드 종료
- 새 리소스 정의를 가진 새 파드 생성
상태 저장 워크로드에서는 이 동작이 부담이 될 수 있습니다.
9-3) In-place Pod Resource Resize(제자리 파드 리사이징)
이를 개선하기 위한 기능이 “in-place 리사이징”입니다.
- CPU/메모리 리소스에 대해 “재시작 없이 조정” 같은 정책을 가능하게 하는 방향
- 다만 기능 게이트, 알파/베타/스테이블 여부, 제약 등이 있어 실무 적용은 환경에 따라 다릅니다.
9-4) VPA: 파드 수가 아니라 “파드 리소스(requests/limits)”를 조정한다
여기서 가장 많이 헷갈리는 부분을 단정적으로 정리합니다.
VPA는 “min/max를 바꾸는 도구”가 아니다
minAllowed/maxAllowed는 VPA가 추천·적용할 수 있는 범위를 제한하는 가드레일입니다.- VPA가 실제로 추천/적용하는 것은 CPU/메모리 requests(주로) 입니다.
- 적용 모드에서는 파드가 재생성될 때 그 값이 들어가도록(Admission Controller) 동작합니다.
즉,
- 바뀌는 것: 파드(컨테이너)의
resources.requests(때로 limits) - 바뀌지 않는 것:
minAllowed/maxAllowed(사람이 정하는 제한선)
VPA 구성 요소
- Recommender: 사용량 수집/분석 → 추천 생성
- Updater: 필요 시 파드 퇴출/재생성 유도
- Admission Controller: 파드 생성 시 추천값 주입
VPA 모드(개념 정리)
- Off: 추천만
- Initial: 생성 시점에만 적용
- Recreate / Auto: 상황에 따라 파드 재생성(현 시점 구현/기능 지원에 따라 in-place로 진화 가능)
9-5) 실무에서 VPA를 “많이 안 쓰는 느낌”이 드는 이유
그 직감은 매우 현실적입니다. 대표 이유는:
- 파드 재생성/eviction 부담(가용성·지연·운영 예측성)
- HPA와 함께 쓰기 까다로움(HPA는 requests를 분모로 보기 때문에 VPA가 requests를 바꾸면 스케일링 감각이 흔들릴 수 있음)
- 대부분 서비스는 정적 튜닝 + HPA로도 충분히 운영 가능
- 추천값 신뢰/검증/예외 케이스 처리 비용
그래서 실무에서 VPA는 보통:
- Off 모드로 추천만 보고 사람이 반영하거나
- Initial로만 적용해서 “새로 뜨는 파드”에 한정하는 식으로 보수적으로 도입하는 경우가 많습니다.
최종 결론: 운영 관점에서 한 줄 요약
- Metrics Server는 “지금 리소스(top)”를 위해 필수에 가깝지만, 장기 분석은 Prometheus/상용 APM이 필요
- kubectl logs는 stdout/stderr 기반이며, 멀티 컨테이너면
-c가 필수 - Deployment는 리비전/롤링 업데이트/롤백이 핵심 운영 기능
- Docker CMD/ENTRYPOINT 개념이 Pod의
args/command로 그대로 이어진다 - 구성은 env → ConfigMap → Secret, Secret의 Base64는 암호화가 아니다
- 진짜 보안은 RBAC + etcd at-rest encryption + 운영 표준화
- 멀티 컨테이너는 패턴을 명확히(코로케이트/init/사이드카) 하고, “먼저 실행”은 기본적으로 보장되지 않는다
- 오토스케일링은
- HPA = 파드 수
- VPA = 파드 리소스(requests)
- in-place 리사이징은 “재생성 없이”를 향한 진화
헷갈리는 내용 정리
- RollingUpdate 파라미터
- maxSurge: 업데이트 중 desired replicas(Deployment의 spec.replicas)보다 추가로 더(+) 띄울 수 있는 Pod 수/비율. 결과적으로 새 ReplicaSet을 증가시키는 여유를 줌.
- maxUnavailable: 업데이트 중 unavailable(Ready 아님)이어도 되는 Pod 수/비율. “몇 개를 지워도 된다”라기보다 최소 Ready 보장 수를 정하는 개념이며, 결과적으로 기존 ReplicaSet을 감소시키는 여유를 줌.
- 구(이전) ReplicaSet은 언제까지 남나
- 업데이트가 끝나면 구 RS는 보통 replicas=0으로 내려간 채로 남겨둠(롤백/히스토리 목적).
- 무한정 남기는 게 아니라 spec.revisionHistoryLimit 만큼만 보관하고, 초과하면 오래된 RS부터 삭제됨(예: 0이면 거의 남기지 않음).
- “이미지도 남겨두나?”
- RS가 남는다고 해서 쿠버네티스가 이미지를 “보관”하는 건 아님.
- 남는 건 **RS/Pod 템플릿 스펙(이미지 참조 문자열 포함)**이고, 실제 이미지 레이어는 레지스트리와 **노드의 런타임 캐시(containerd 등)**에 존재.
- Pod에서 쓰던 이미지는 보통 지우나
- 보통 바로 삭제하지 않고 노드에 캐시로 남김.
- 디스크 압박/임계치에 따라 kubelet이 Image GC로 자동 정리함(항상 남아있다는 보장 없음). 롤백 안정성은 노드 캐시가 아니라 레지스트리에 이미지가 유지되는지에 달림.
- ConfigMap을 volume으로 마운트하는 방식
- ConfigMap의 각 key가 파일명, value가 파일 내용이 되어 mountPath 아래에 생성됨.
- 파일 기반 설정(예: application.yaml, nginx.conf)에 유리.
- items로 특정 키만 마운트, defaultMode로 권한 설정 가능.
- subPath는 “파일 1개만 원하는 위치에”에 유용하지만 변경 자동 반영 이슈가 있을 수 있음.
- VPA는 노드 스펙을 바꾸나?
- VPA는 노드 스펙 변경이 아니라 Pod의 requests/limits를 조정함.
- 일반적으로 “Deployment 스펙을 직접 수정”하기보다,
- 추천 계산(Recommender) → Pod 생성 시 Mutating(Admission Controller) → 필요 시 eviction(Updater)로 Pod를 다시 만들어 적용하는 흐름이 흔함.
- 노드 증설/축소는 VPA가 아니라 Cluster Autoscaler 같은 별도 구성요소 역할.
'CKA' 카테고리의 다른 글
| Cluster Maintenance - 쿠버네티스 릴리즈 버전 이해 및 버전 업그레이드 방법 (0) | 2025.12.31 |
|---|---|
| Cluster Maintenance - Cordon/Drain/Uncordon (1) | 2025.12.31 |
| Application Lifecycle Management - VPA (1) | 2025.12.30 |
| Application Lifecycle Management - 오토스케일링과 HPA (0) | 2025.12.30 |
| Application Lifecycle Management - 멀티 컨테이터 파드 (1) | 2025.12.30 |