
지난 포스팅에서는 네임스페이스로 환경을 분리하고, create 대신 apply를 써야 하는 이유, 그리고 쿠버네티스의 비동기 처리 방식을 알아봤습니다.
명령을 내리는 방법과 기본 뼈대를 이해했다면, 이제는 실제 운영 환경에서 파드의 생명주기를 어떻게 제어하고, 수많은 매니페스트 파일을 어떻게 관리할 것인지 고민해야 할 차례입니다.
이번 포스팅에서는 무중단 배포를 위한 롤링 업데이트, 동적 이름 할당, 비동기 환경에서의 대기 처리, 그리고 실무 필수 매니페스트 관리 기법을 정리해 보겠습니다. 🚀
운영 중인 서비스의 이미지 버전이나 환경 변수를 바꿔야 할 때, 기존 파드를 한 번에 종료하고 새 파드를 띄우면 서비스 접속 장애가 발생합니다.
쿠버네티스는 이를 방지하기 위해 롤링 업데이트를 지원합니다. 새 버전의 파드를 먼저 띄워서 정상 동작을 확인한 후, 기존 파드를 순차적으로 종료하는 방식이죠.
# Deployment가 관리하는 모든 파드 순차 재시작
kubectl rollout restart deployment sample-deployment
💡 단독 파드는 롤링 업데이트가 불가능합니다
rollout restart는Deployment나ReplicaSet같은 컨트롤러에만 사용할 수 있습니다. 단독 파드는 이 기능을 쓸 수 없으므로, 실무에서는 가급적 단독 파드 배포를 지양합니다.
롤링 업데이트 중에는 진행 상황을 실시간으로 모니터링할 수 있고, 문제가 생기면 즉시 이전 상태로 되돌릴 수 있습니다.
# 업데이트 진행 상태 확인
kubectl rollout status deployment sample-deployment
# 이전 버전으로 긴급 롤백
kubectl rollout undo deployment sample-deployment
generateName 🎲롤링 업데이트나 스케일 아웃 과정에서는 여러 개의 파드가 새롭게 생성됩니다. 이때 파드 이름을 sample-pod처럼 하드코딩하면 이름 충돌로 생성이 실패합니다.
generateName을 사용하면 지정한 접두사 뒤에 쿠버네티스가 무작위 난수를 붙여 고유한 이름을 자동 생성합니다.
# sample-generatename.yaml
apiVersion: v1
kind: Pod
metadata:
generateName: sample-generatename- # 하이픈(-)으로 끝나는 게 관례
spec:
containers:
- name: nginx-container
image: nginx
⚠️ 주의:
generateName은create로 실행합니다이 기능은 예외적으로
apply가 아닌create를 사용해야 합니다.apply는 정확한 이름을 기준으로 상태를 비교하는데, 이름이 동적으로 변하면 비교 대상을 찾을 수 없기 때문입니다.kubectl create -f sample-generatename.yaml kubectl get pods # 결과: sample-generatename-x8f2a 형태로 생성됨
💡 참고: Deployment로 파드를 생성할 때 이름 뒤에 무작위 해시값(예: sample-app-7b5c...)이 붙는 것도 내부적으로 이 generateName 원리를 사용하기 때문입니다.
wait ⏳지난 포스팅에서 배웠듯이 쿠버네티스는 비동기적으로 동작합니다. kubectl이 "완료"라고 응답해도 실제 노드에서는 여전히 작업이 진행 중일 수 있죠.
CI/CD 파이프라인이나 자동화 스크립트에서는 특정 리소스가 완전히 준비될 때까지 명시적으로 기다리는 제어가 필요합니다. 이때 사용하는 명령어가 wait입니다.
# 파드가 노드에 스케줄링될 때까지 대기
kubectl wait --for=condition=PodScheduled pod --all
# 리소스가 트래픽을 받을 수 있는 Ready 상태까지 대기
kubectl wait --for=condition=Ready -f sample-pod.yaml
# 파드 삭제가 완전히 끝날 때까지 대기
kubectl delete pod --all --wait=false # 삭제 비동기 요청 후 바로 반환
kubectl wait --for=delete pod --all # 실제 삭제 완료를 기다림
--timeout (실무 필수)만약 이미지 다운로드 에러(ImagePullBackOff) 등으로 파드가 영원히 Ready 상태가 되지 못하면, 스크립트는 무한정 멈춥니다. 실무에서는 반드시 타임아웃을 명시해야 합니다.
kubectl wait --for=condition=Ready pod/sample-pod --timeout=60s
실제 서비스는 하나의 파드만 띄우는 게 아닙니다. Deployment, Service, ConfigMap 등 수많은 리소스가 함께 맞물려 동작하죠. 이 복잡한 매니페스트들을 어떻게 관리해야 할까요?
---)Deployment와 Service처럼 결합도가 높고 항상 같이 배포되는 리소스는 구분자(---)를 이용해 하나의 YAML 파일에 작성하는 게 유리합니다.
# sample-multi-resource.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order1-deployment
# ... (Deployment 스펙 생략) ...
---
apiVersion: v1
kind: Service
metadata:
name: order2-service
# ... (Service 스펙 생략) ...
⚠️ 주의: 단일 파일 배포 중 중간에 문법 오류가 발생하면, 오류 이후의 리소스들은 생성되지 않습니다.
-R)시스템 규모가 커지면 용도별로 파일을 나누고 디렉토리 단위로 묶어서 관리합니다.
# 특정 디렉토리 안의 모든 YAML 파일 일괄 적용 (하위 폴더 제외)
kubectl apply -f dir/
# 하위 디렉토리까지 모두 포함하여 적용
kubectl apply -f dir/ -R
💡 배포 순서 제어 팁: 디렉토리 단위 실행 시 파일명의 알파벳 순서대로 배포됩니다. 의존성에 맞춰 배포해야 한다면 파일명 앞에 연번을 붙이세요. (예:
01-config.yaml,02-deployment.yaml)
수많은 리소스를 관리하려면 각 리소스가 어떤 서비스에 속하는지 식별할 수 있는 '명찰'이 필요합니다.
| 구분 | 레이블 (Label) | 어노테이션 (Annotation) |
|---|---|---|
| 목적 | 리소스 분류, 선택, 그룹화 | 추가 설명 및 부가 정보 기록 |
| 검색 지원 | 지원됨 (Label Selector) | 지원 안 됨 |
| Value 길이 | 63자 이하 | 262,144자 이하 |
| 주요 용도 | 식별자, 배포 타겟팅 | 릴리스 노트, 빌드 정보, Ingress 설정 |
레이블을 이용한 검색 예시
# 특정 레이블이 붙은 파드만 검색
kubectl get pods -l app=sample-app
--prune (GitOps의 핵심)최근 실무에서는 Git 저장소에 매니페스트를 저장하고, 그 상태를 클러스터와 동기화하는 GitOps 방식을 많이 씁니다.
Git에서 파일을 지웠다면, 클러스터에 배포된 실제 리소스도 삭제되어야 맞겠죠? --prune 옵션을 사용하면 삭제된 매니페스트를 클러스터에 자동 반영할 수 있습니다.
실습: 삭제된 리소스 자동 반영하기
# 1. 파일이 삭제된 로컬 폴더를 다시 배포 (prune 없음)
kubectl apply -f ./dir
# 💡 결과: 로컬에서는 파일이 지워졌지만, 클러스터에는 파드가 여전히 남아있음
# 2. --prune 옵션 사용 (동기화)
kubectl apply -f ./dir --prune -l system=a
# 💡 결과: 디렉토리에 없는 파일의 리소스가 자동으로 삭제됨!
🔥 치명적 주의사항:
--prune사용 시 반드시 레이블 셀렉터(-l)를 함께 지정하세요! 레이블을 지정하지 않으면 해당 디렉토리에 정의되지 않은 클러스터 내 모든 리소스가 삭제될 수 있습니다.
kubectl set 🛠️지금까지 매니페스트를 통한 '선언형 관리'의 중요성을 강조했지만, 운영하다 보면 긴급하게 롤백하거나 빠르게 테스트해야 할 상황이 생깁니다. 이때 YAML 파일을 열지 않고도 설정을 즉시 변경할 수 있는 명령어가 kubectl set입니다.
주요 설정 항목:
image: 컨테이너 이미지 버전 (가장 많이 씀)env: 환경 변수resources: CPU/메모리 할당량# 실행 중인 파드의 Nginx 이미지를 1.17 버전으로 즉시 변경
kubectl set image pod sample-pod nginx-container=nginx:1.17
# 로컬 YAML과 현재 클러스터 상태의 차이 비교
kubectl diff -f sample-pod.yaml

💡 설정 드리프트(Configuration Drift) 주의
set명령어를 쓰면 클러스터 상태는 변하지만, 로컬(또는 Git)의 YAML 파일은 과거 상태 그대로입니다. 이 불일치를 '설정 드리프트'라고 부릅니다.따라서
set은 긴급 조치용으로만 사용하고, 조치 후에는 반드시diff로 변경사항을 확인한 뒤 원본 YAML 파일을 업데이트하여 배포 파이프라인을 유지하는 게 중요합니다.
오늘은 무중단 롤링 업데이트부터 이름 충돌 방지, wait 제어, --prune을 활용한 동기화, 그리고 복잡한 매니페스트 설계 방법까지 다뤘습니다.
결국 쿠버네티스 운영의 핵심은 "코드(매니페스트)에 정의된 상태와 실제 클러스터 상태를 어떻게 안전하고 일관되게 동기화할 것인가?" 입니다.
다음 포스팅에서는 배포된 리소스에 문제가 생겼을 때 원인을 파헤치는 방법, 즉 로그 확인(logs), 컨테이너 접속(exec), 트래픽 포워딩(port-forward) 등 트러블슈팅 필수 명령어들을 정리해 보겠습니다! 🚀