[IT-정보] 디플로이먼트 FAQ 실무 핵심 정리 – 테크리드를 위한 쿠버네티스 배포 설정과 오류 해결 가이드

디플로이먼트 관련 쿠버네티스 구조를 설명하는 대표 이미지

배포 중 멈춰버린 파드, 당황스러운 순간을 마주하고 계신가요?

금요일 오후, 마지막 배포를 승인했습니다. 모든 테스트는 완벽했고 CI/CD 파이프라인도 초록불을 띄웠어요. 그런데 갑자기 모니터링 알람이 울리기 시작합니다. 새로운 버전의 파드가 생성되다가 멈췄거나, 기존 파드가 죽으면서 서비스 전체에 장애가 발생한 상황이에요. 테크리드로서 가장 식은땀이 나는 순간이죠.

쿠버네티스에서 디플로이먼트(Deployment)는 단순히 컨테이너를 띄우는 도구가 아니에요. 무중단 배포를 보장하고, 애플리케이션의 상태를 유지하며, 문제가 생겼을 때 이전 상태로 되돌리는 운영의 핵심 엔진입니다. 하지만 설정 하나, 전략 하나를 잘못 선택하면 서비스 전체를 마비시키는 독이 될 수도 있어요.

단순히 공식 문서를 읽는 것만으로는 부족해요. 실무에서는 왜 배포가 느려지는지, 왜 롤백이 작동하지 않는지, 그리고 왜 특정 파드만 계속해서 재시작되는지에 대한 구체적인 답변이 필요합니다. 이번 글에서는 실무자들이 가장 많이 겪는 혼란을 중심으로 디플로이먼트 FAQ를 정리했어요.

이 글을 읽고 나면 다음 내용들을 확실히 내 것으로 만들 수 있어요.

  • 디플로이먼트와 리플리카셋의 근본적인 차이점
  • 서비스 중단을 막는 최적의 업데이트 전략 선택법
  • 실패한 배포를 즉시 복구하는 롤백 기술
  • 장애를 미연에 방지하는 프로브(Probe) 설정 노하우

배포 전략을 세우기 전, 반드시 점검해야 할 기준

무턱대고 YAML 파일을 작성하기 전에 우리가 관리할 애플리케이션의 성격부터 파악해야 해요. 모든 애플리케이션에 동일한 배포 방식을 적용하는 것은 위험합니다. 데이터베이스처럼 상태를 유지해야 하는 서비스와 Stateless한 웹 서버는 접근 방식이 완전히 달라야 하거든요.

가장 먼저 결정해야 할 것은 워크로드의 유형입니다. 쿠버네티스는 목적에 따라 다양한 컨트롤러를 제공하며, 디플로이먼트는 그중 가장 범용적이지만 만능은 아니에요. 자신의 서비스가 어떤 범주에 속하는지 아래 표를 통해 먼저 판단해 보세요.

컨트롤러 유형 주요 특징 적합한 서비스 사례
Deployment 무상태(Stateless) 애플리케이션 관리, 롤링 업데이트 지원 웹 서버, API 서버, 마이크로서비스
StatefulSet 상태 유지(Stateful) 관리, 고유 식별자 및 안정적 네트워크 제공 데이터베이스(MySQL, MongoDB), 메시지 큐
DaemonSet 모든(또는 특정) 노드에 파드 하나씩 배치 로그 수집기(Fluentd), 모니터링 에이전트

표를 확인했다면 이제 리소스 설계 기준을 세워야 해요. 디플로이먼트를 설정할 때 가장 많이 놓치는 부분이 바로 리소스의 한계치(Limits)와 요청량(Requests)입니다. 이를 명확히 하지 않으면, 배포 중에 노드의 메모리가 부족해져서 기존 파드까지 함께 죽어버리는 Cascading Failure를 경험할 수 있어요.

💡 알아두기
디플로이먼트를 구성하기 전, 반드시 애플리케이션이 중단되었을 때의 허용 시간(RTO)과 데이터 손실 허용 범위(RPO)를 팀 내에서 합의해야 합니다. 이에 따라 무중단 배포 전략의 복잡도가 결정되기 때문이에요.

마지막으로 체크리스트를 준비하세요. 사용할 이미지 태그가 고정되어 있는지(latest 사용 금지), 서비스가 외부에서 접속 가능한 형태인지, 그리고 롤백 시나리오가 검증되었는지를 확인하는 과정이 필요합니다. 준비가 되었다면 이제 본격적인 구현 단계로 넘어가겠습니다.

실무 밀착형 디플로이먼트 핵심 운영 가이드

단순히 YAML을 복사해서 붙여넣는 단계는 지났습니다. 실제 운영 환경에서 서비스의 안정성을 책임지는 테크리드라면, 배포의 메커니즘을 깊이 있게 이해하고 제어할 수 있어야 해요. 단계별로 핵심적인 설계 포인트를 짚어보겠습니다.

STEP 1. 업데이트 전략의 정밀한 제어

디플로이먼트의 꽃은 RollingUpdate 전략입니다. 하지만 단순히 이 옵션만 켜둔다고 해서 무중단이 보장되지는 않아요. 핵심은 maxSurgemaxUnavailable 파라미터를 어떻게 설정하느냐에 달려 있습니다.

예를 들어, 현재 실행 중인 파드가 10개인 클러스터가 있다고 가정해 봅시다. 만약 maxSurge를 25%로 설정하면, 배포 중에 총 13개(10 + 2.5의 올림)의 파드가 일시적으로 존재할 수 있어요. 반대로 maxUnavailable을 25%로 설정하면, 배포 중에도 최소 7개의 파드는 항상 살아있어야 한다는 뜻입니다. 만약 인프라 자원이 부족한 상황에서 maxSurge를 너무 높게 잡으면, 새로운 파드가 생성되려다 리소스 부족으로 Pending 상태에 빠지며 배포가 멈춰버릴 수 있어요.

💡 알아두기
자원 여유가 거의 없는 클러스터라면 maxSurge를 0으로 설정하고, maxUnavailable을 단계적으로 조절하는 방식을 고려해야 합니다.

STEP 2. 실패를 방지하는 프로브(Probe) 설계

많은 운영자가 가장 흔하게 하는 실수가 바로 LivenessProbe와 ReadinessProbe를 구분하지 않는 것입니다. 이 둘을 혼동하면 배포 중에 서비스가 끊기거나, 죽어야 할 파드가 살아있는 것처럼 보이는 기현상이 발생해요.

먼저 ReadinessProbe는 “이 파드가 트래픽을 받을 준비가 되었는가?”를 묻습니다. 애플리케이션이 실행은 되었지만, 아직 DB 커넥션 풀을 채우지 못했거나 초기 캐시를 로딩 중이라면 트래픽을 보내면 안 되겠죠. 이 프로브가 성공하기 전까지 쿠버네티스는 해당 파드를 서비스 엔드포인트에 추가하지 않습니다. 이것이 무중단 배포의 핵심입니다.

반면 LivenessProbe는 “이 파드가 살아있는가?”를 체크합니다. 만약 애플리케이션이 데드락(Deadlock) 상태에 빠져 응답을 못 한다면, 이 프로브가 실패를 감지하고 파드를 강제로 재시작합니다. 주의할 점은, ReadinessProbe 설정이 잘못되어 초기화가 오래 걸리는데 LivenessProbe가 너무 공격적으로 설정되어 있으면, 파드가 준비되기도 전에 계속 재시작되는 무한 루프에 빠질 수 있다는 점이에요.

STEP 3. 히스토리 관리와 안전한 롤백

배포가 잘못되었다는 것을 인지한 순간, 가장 먼저 해야 할 일은 kubectl rollout undo 명령어를 사용하는 것입니다. 하지만 이를 위해서는 디플로이먼트 설정에 revisionHistoryLimit이 적절히 설정되어 있어야 해요. 기본값은 보통 10이지만, 운영 환경에 따라 이 값을 조절해야 합니다.

히스토리 제한이 너무 낮으면 이전 버전의 정보를 찾을 수 없어 롤백이 불가능해지고, 너무 높으면 클러스터의 etcd에 불필요한 메타데이터가 쌓여 성능에 영향을 줄 수 있습니다. 실무적으로는 최근 5~10개 정도의 리비전을 유지하는 것이 적당합니다. 롤백을 실행하기 전에는 반드시 현재 상태의 ReplicaSet 목록을 확인하여, 어떤 버전으로 돌아갈 것인지 명확히 판단하는 습관을 가져야 합니다.

STEP 4. 리소스 요청 및 제한(Requests & Limits) 최적화

디플로이먼트의 안정성은 결국 노드의 자원 관리에서 결정됩니다. 파드가 사용할 최소한의 자원인 requests와 최대 허용치인 limits를 설정하지 않으면, 특정 파드가 노드의 모든 자원을 점유하는 Noisy Neighbor 문제가 발생합니다.

특히 CPU는 압축 가능한(Compressible) 자원이지만, 메모리는 압축 불가능한(Incompressible) 자원이라는 점을 명심하세요. CPU 사용량이 높으면 파드가 느려질 뿐이지만, 메모리 사용량이 Limit을 넘어서면 커널은 즉시 OOM(Out Of Memory) Killer를 호출해 해당 파드를 즉사시킵니다. 따라서 메모리 설정은 실제 애플리케이션의 Peak 사용량을 면밀히 모니터링한 뒤 보수적으로 잡아야 합니다.

STEP 5. 실무 시나리오: 무중단 배포 워크플로우 예시

이론을 실제 상황에 대입해 보겠습니다. 새로운 버전 v2를 배포하는 상황입니다.

  1. 사전 검증: v2 이미지의 ReadinessProbe 경로가 정상인지, DB 마이그레이션이 완료되었는지 확인합니다.
  2. 배포 실행: kubectl apply로 디플로이먼트를 업데이트합니다.
  3. 상태 모니터링: kubectl rollout status 명령어로 배포 진행 상황을 실시간으로 관찰합니다.
  4. 장애 감지: 새로운 파드가 ReadinessProbe를 통과하지 못하고 계속 실패한다면, 즉시 중단합니다.
  5. 긴급 조치: kubectl rollout undo deployment/[이름]으로 이전 v1 상태로 복구합니다.

이 과정을 자동화하는 것이 데브옵스의 역할이지만, 각 단계의 메커니즘을 모르면 자동화된 도구가 에러를 뱉었을 때 손을 쓸 방법이 없습니다.

자주 하는 실수와 해결법

운영 현장에서 테크리드들이 가장 자주 마주치는 실수들을 정리했습니다. 반복되는 실수를 줄이는 것만으로도 장애 대응 시간의 절반을 줄일 수 있어요.

  • 실수: Deployment의 Selector와 Pod의 Label이 일치하지 않음
    👉 왜 발생하는가: YAML 수정 과정에서 오타가 나거나, 기존 리소스의 라벨을 임의로 변경했을 때 발생합니다.
    해결법: Selector는 한 번 설정하면 변경하기 매우 어렵습니다. 배포 전 반드시 kubectl get pods --show-labels로 라벨 관계를 검증하세요.
  • 실수: ReadinessProbe가 너무 늦게 응답함
    👉 왜 발생하는가: 애플리케이션 초기화 시간이 Probe의 initialDelaySeconds보다 길 때 발생합니다.
    해결법: 애플리케이션의 실제 부팅 시간을 측정하여 초기 지연 시간을 넉넉하게 설정하세요.
  • 실수: CPU/Memory Limit을 너무 낮게 설정함
    👉 왜 발생하는가: 개발 환경의 낮은 트래픽을 기준으로 운영 환경 설정을 결정할 때 발생합니다.
    해결법: 반드시 프로덕션 환경의 부하 테스트 데이터를 기반으로 Limit을 결정하세요.
  • 실수를: RollingUpdate 중 노드 자원 부족
    👉 왜 발생하는가: maxSurge로 인해 새로운 파드가 생성될 때 노드에 남은 공간이 없기 때문입니다.
    해결법: 클러스터의 가용 자원을 확인하거나 maxSurge를 0으로 낮추어 기존 파드를 먼저 삭제한 뒤 새 파드를 띄우게 하세요.
  • 실수: 이미지 태그를 ‘latest’로 사용함
    👉 왜 발생하는가: 편리함 때문에 사용하지만, 어떤 버전이 실행 중인지 추적할 수 없게 만듭니다.
    해결법: 항상 고유한 버전 태그(예: v1.2.3, git hash)를 사용하세요.

자주 묻는 질문

Q. Deployment와 ReplicaSet의 차이가 정확히 무엇인가요?

ReplicaSet은 단순히 지정된 수의 파드를 유지하는 기능에 집중합니다. 반면 Deployment는 ReplicaSet을 관리하는 상위 개념으로, 배포 전략(RollingUpdate, Recreate)을 실행하고 이전 버전으로의 롤백을 가능하게 하는 ‘관리 기능’을 포함하고 있습니다. 실무에서는 ReplicaSet을 직접 다루기보다 Deployment를 통해 관리하는 것이 표준입니다.

Q. 배포 중에 파드가 계속해서 CrashLoopBackOff 상태에 빠져요. 어떻게 해야 하나요?

이것은 파드가 실행되자마자 종료된다는 뜻입니다. 가장 먼저 kubectl logs [파드명]으로 애플리케이션 내부 에러 로그를 확인하세요. 설정 파일의 경로 오류, 환경 변수 누락, 혹은 DB 연결 실패가 가장 흔한 원인입니다. 로그 확인이 어렵다면 kubectl describe pod [파드명]을 통해 이벤트 로그에서 OOMKilled나 컨테이너 종료 원인을 찾아야 합니다.

Q. 무중단 배포를 하고 싶은데 서비스 끊김이 발생합니다. 무엇을 점검해야 하죠?

가장 유력한 원인은 ReadinessProbe 설정 미비입니다. 파드가 뜨자마자 트래픽을 받기 시작하는데, 아직 애플리케이션이 요청을 처리할 준비가 안 된 상태라면 연결 에러가 발생합니다. ReadinessProbe가 성공할 때까지 트래픽이 유입되지 않도록 설정을 재검토하세요.

Q. 롤백을 했는데 이전 버전으로 완벽히 돌아가지 않아요.

Deployment는 Pod의 상태를 관리할 뿐, 데이터베이스 스키마 같은 외부 상태는 관리하지 않습니다. 만약 v2 배포 시 DB 스키마를 변경했다면, v1으로 롤백하더라도 DB는 이미 v2 상태이므로 애플리케이션이 에러를 낼 수 있습니다. 데이터베이스 마이그레이션은 항상 하위 호환성을 유지하도록 설계해야 합니다.

Q. Deployment의 히스토리를 관리하는 가장 좋은 방법은 무엇인가요?

revisionHistoryLimit 값을 명시적으로 설정하는 것이 좋습니다. 너무 많으면 관리가 어렵고, 너무 적으면 과거로의 회귀가 불가능합니다. 보통 5에서 10 사이의 값을 권장하며, CI/CD 도구(ArgoCD, Flux 등)를 사용한다면 해당 도구의 히스토리 관리 기능과 연동하여 사용하는 것이 좋습니다.

안정적인 운영을 위한 마지막 체크리스트

디플로이먼트 운영은 한 번의 설정으로 끝나는 것이 아니라, 지속적인 관찰과 미세 조정의 과정입니다. 오늘 배운 내용을 바탕으로 현재 운영 중인 클러스터를 점검해 보세요.

✅ 핵심 요약

  • 무중단 배포를 위해 maxSurgemaxUnavailable을 자원 상황에 맞게 최적화하세요.
  • ReadinessProbe는 트래픽 유입 시점을, LivenessProbe는 파드 재시작 시점을 결정합니다.
  • 리소스 설정 시 Memory Limit은 반드시 실제 사용량을 기반으로 보수적으로 잡아야 합니다.
  • 롤백을 대비해 revisionHistoryLimit을 적절히 설정하세요.
  • 애플리케이션 배포 시 이미지 태그는 항상 고유한 값을 사용하세요.
  • 데이터베이스 스키마 변경 시 반드시 하위 호환성을 고려해야 합니다.

지금 바로 실행할 수 있는 단계입니다. 오늘 퇴근 전, 현재 운영 중인 주요 서비스의 Deployment YAML 파일을 열어 프로브(Probe) 설정이 제대로 되어 있는지, 그리고 리소스 제한(Limits)이 너무 타이트하지 않은지 딱 하나만 확인해 보세요. 이 작은 습관이 대형 장애를 막는 시작점이 됩니다.

실습 환경에서 직접 설정값을 바꿔가며 배포를 진행해 보세요. 만약 설정 과정에서 예상치 못한 오류가 발생하거나, 특정 상황에서의 전략이 고민된다면 아래 댓글로 질문을 남겨 주세요. 함께 해결 방안을 찾아보겠습니다.

더 깊이 있는 쿠버네티스 운영 노하우가 궁금하다면, 쿠버네티스 디플로이먼트 기본 개념 글클러스터 구축 입문 글을 함께 읽어보시는 것을 추천해요.

댓글 남기기