
레플리카셋 선택이 운영의 성패를 가르는 이유
새벽 3시에 갑작스러운 서비스 장애 알람을 받고 클러스터에 접속했을 때, 가장 먼저 마주하는 당혹스러운 상황이 있어요. Pod의 개수는 유지되고 있는데, 정작 새로운 업데이트 버전이 반영되지 않거나 서비스가 계속 구버전에서 멈춰 있는 경우예요. 인프라 운영자라면 한 번쯤 겪어봤을 이 문제는 단순히 설정 오류가 아니라, 처음부터 워크로드의 특성에 맞지 않는 컨트롤러를 선택했기 때문에 발생하곤 해요.
단순히 Pod 개수를 맞추는 것만 생각하고 레플리카셋(ReplicaSet)만 사용했다가는 배포 전략을 세우거나 롤백을 수행할 때 큰 어려움을 겪게 돼요. 서비스가 중단 없이 업데이트되어야 하는 웹 애플리케이션인지, 아니면 데이터의 연속성이 생명인 데이터베이스인지에 따라 우리가 선택해야 할 도구는 완전히 달라지거든요.
지금 이 글을 읽고 계신 분들은 아마 온프레미스 환경에서 서버 자원을 효율적으로 관리하며, 서비스 안정성을 극대화해야 하는 막중한 임무를 맡고 계실 거예요. 어떤 컨트롤러를 써야 운영 리소스를 줄이면서도 장애에 강한 시스템을 만들 수 있을지 고민하고 계실 텐데요. 이 글을 통해 각 컨트롤러의 실무적 차이점을 명확히 이해하고, 상황에 맞는 최적의 선택 기준을 세울 수 있어요.
오늘 살펴볼 주요 내용은 다음과 같아요.
- 레플리카셋과 대안 기술들의 핵심 개념 정리
- 운영 목적에 따른 컨트롤러별 기능 및 성능 비교
- 실무에서 바로 써먹는 상황별 추천 조합 시나리오
- 자주 발생하는 운영 실수와 해결 방법
컨트롤러 선택 전 반드시 확인해야 할 기준
쿠버네티스 환경에서 워크로드를 생성하기 전에 가장 먼저 스스로에게 던져야 할 질문이 있어요. “이 서비스는 상태를 유지해야 하는가, 아니면 언제든 버려도 상관없는가?”라는 질문이에요. 이 질문에 대한 답이 모든 선택의 시작점이 돼요.
단순히 ‘Pod를 띄운다’는 행위 자체에 매몰되면 안 돼요. 운영 관점에서는 업데이트가 일어날 때 서비스 중단이 허용되는지, Pod가 재시작될 때 이름이나 데이터가 바뀌어도 괜찮은지를 반드시 따져봐야 해요. 만약 이 기준을 놓치면 배포할 때마다 수동으로 Pod를 지우고 다시 만드는 불필요한 작업에 시간을 허비하게 돼요.
쿠버네티스 컨트롤러는 ‘선언적 명령’을 수행해요. 운영자가 “Pod 3개를 유지해”라고 선언하면, 컨트롤러는 끊임없이 현재 상태를 감시하며 선언된 상태로 되돌리는 루프를 수행해요.
의사결정을 돕기 위해 주요 컨트롤러들의 특성을 표로 정리해 두었어요. 이 표를 기준으로 현재 관리 중인 서비스의 성격을 대입해 보세요.
| 컨트롤러 종류 | 핵심 목적 | 업데이트 방식 | 상태 유지 여부 |
|---|---|---|---|
| 레플리카셋 | Pod 개수 유지 | 수동 관리 필요 | 없음 (Stateless) |
| 디플로이먼트 | 배포 및 버전 관리 | 롤링 업데이트 지원 | 없음 (Stateless) |
| 스테이트풀셋 | 안정적 식별자/데이터 | 순차적 업데이트 | 있음 (Stateful) |
| 데몬셋 | 모든 노드에 실행 | 노드 추가 시 자동 실행 | 용도에 따라 다름 |
위 표에서 알 수 있듯이, 우리가 흔히 사용하는 웹 서버나 API 서버는 대부분 디플로이먼트(Deployment)를 사용하는 것이 정석이에요. 레플리카셋은 디플로이먼트의 하위 개념으로 동작하기 때문에, 실무에서 레플리카셋을 직접 관리하는 일은 거의 없어야 해요. 반면 데이터베이스나 메시지 큐처럼 각 Pod가 고유한 이름과 데이터를 가져야 한다면 고민 없이 스테이트풀셋으로 가야 하죠.
상황별 최적의 컨트롤러 적용 가이드
이제 구체적인 실무 시나리오를 바탕으로 어떤 기술을 적용해야 할지 단계별로 살펴볼게요. 단순히 이론적인 차이를 넘어, 실제 운영 환경에서 마주할 문제들을 중심으로 설명해 드릴게요.
STEP 1. 단순 개수 유지를 넘어선 버전 관리가 필요할 때
만약 여러분이 관리하는 서비스가 수시로 업데이트되고, 업데이트 중에 서비스가 끊기면 안 된다면 반드시 디플로이먼트를 선택해야 해요. 레플리카셋은 단순히 “Pod를 3개 유지해”라는 명령에는 충실하지만, “Pod를 구버전에서 신버전으로 부드럽게 교체해”라는 명령은 수행할 수 없어요.
디플로이먼트는 내부적으로 레플리카셋을 생성하고 관리해요. 새로운 버전을 배포하면 기존 레플리카셋의 Pod 개수를 줄이면서 동시에 새로운 레플리카셋의 Pod 개수를 늘리는 롤링 업데이트(Rolling Update)를 자동으로 수행하죠. 이 과정에서 `maxSurge`와 `maxUnavailable` 설정을 통해 업데이트 중 일시적으로 늘어날 수 있는 Pod 수와, 서비스 중단 없이 유지되어야 하는 최소 Pod 수를 정밀하게 제어할 수 있어요.
STEP 2. 데이터의 영속성과 고유 식별자가 중요할 때
데이터베이스(MySQL, PostgreSQL 등)나 분산 저장소(Kafka, Elasticsearch)를 운영한다면 이야기가 완전히 달라져요. 이런 워크로드는 Pod가 재시작되어도 “내가 누구인지(Identity)“와 “내 데이터가 어디에 있는지(Storage)“를 정확히 알아야 해요. 이때 사용하는 것이 바로 스테이트풀셋(StatefulSet)이에요.
스테이트풀셋은 Pod에 0번부터 시작하는 순차적인 번호(Ordinal Index)를 부여해요. 예를 들어 `web-0`, `web-1`, `web-2`와 같이 이름이 고정되죠. 이 고유한 이름 덕분에 클러스터 내부의 다른 서비스들이 특정 Pod를 항상 같은 이름으로 찾아갈 수 있어요. 또한, 각 Pod에 전용 볼륨(Persistent Volume)을 1:1로 매핑하여, Pod가 죽었다 살아나도 이전의 데이터를 그대로 물고 올라올 수 있게 설계되어 있어요.
스테이트풀셋은 업데이트 시 Pod를 순차적으로 하나씩 처리해요. 따라서 업데이트 속도가 디플로이먼트에 비해 느릴 수밖에 없으며, 잘못된 설정으로 인한 데이터 손실 위험이 있으니 반드시 테스트 환경에서 검증을 마쳐야 해요.
STEP 3. 모든 노드에 공통 인프라를 설치해야 할 때
클러스터의 모든 노드에 로그 수집기(Fluentd), 모니터링 에이전트(Prometheus Node Exporter), 또는 네트워크 보안 도구를 설치해야 한다면 데몬셋(DaemonSet)이 정답이에요. 노드가 10개든 100개든 상관없이, 데몬셋은 각 노드마다 정확히 하나의 Pod를 생성하도록 보장해요.
새로운 노드가 클러스터에 추가되면 데몬셋은 이를 즉시 감지하고 해당 노드에 필요한 Pod를 자동으로 띄워요. 운영자가 일일이 새 노드에 접속해서 설치 스크립트를 돌릴 필요가 없는 거죠. 이는 온프레미스 환경에서 노드를 증설할 때 인프라 자동화의 핵심적인 역할을 수행해요.
STEP 4. 실무 시나리오: 웹 서비스와 데이터베이스의 조합
이해를 돕기 위해 실제 기업의 표준 아키텍처를 예로 들어볼게요. 보통 하나의 서비스는 다음과 같은 조합으로 구성돼요.
- Front-end & API 서버: 디플로이먼트(Deployment) 사용. 빠른 배포와 무중단 업데이트가 우선이에요.
- 데이터베이스 레이어: 스테이트풀셋(StatefulSet) 사용. 데이터 정합성과 고유 식별자가 우선이에요.
- 로그 및 모니터링: 데몬셋(DaemonSet) 사용. 모든 물리 서버의 자원을 감시해야 하기 때문이에요.
이처럼 각 컨트롤러의 역할을 명확히 구분하여 배치하면, 운영 리소스를 최소화하면서도 장애 발생 시 복구 가능한 견고한 시스템을 구축할 수 있어요. 단순히 기능이 많다고 좋은 것이 아니라, 서비스의 성격에 맞는 도구를 쓰는 것이 진짜 실력이에요.
자주 하는 실수와 해결법
현장에서 운영자들이 가장 흔하게 범하는 실수들을 모았습니다. 비슷한 상황을 겪고 있다면 아래 내용을 즉시 확인해 보세요.
- ❌ 실수: 레플리카셋을 직접 수정하여 버전을 업데이트함
왜 발생하는가: 디플로이먼트 아래에 있는 레플리카셋을 직접 건드리면, 디플로이먼트의 선언된 상태와 충돌이 발생하여 설정이 다시 덮어씌워지거나 배포가 꼬이게 돼요.
✅ 해결법: 반드시 디플로이먼트(Deployment) 리소스를 수정하세요. 그러면 디플로이먼트가 알아서 새 레플리카셋을 만들고 교체 작업을 진행해요. - ❌ 실수: 스테이트풀셋에서 Pod 이름 규칙을 무시함
왜 발생하는가: Pod의 고유한 식별자를 활용하지 않고 외부에서 임의의 이름을 부여하려고 하면 스테이트풀셋의 이점을 전혀 누릴 수 없어요.
✅ 해결법: 스테이트풀셋이 부여하는 0, 1, 2 번호 체계를 그대로 받아들이고, 서비스(Service) 설정을 통해 해당 이름을 호출하도록 구성하세요. - ❌ 실수: 데몬셋 Pod가 특정 노드에서 실행되지 않음
왜 발생하는가: 노드의 Taint(테인트) 설정이나 Selector 불일치로 인해 데몬셋이 실행될 권한이 없는 경우가 많아요.
✅ 해결법: 노드의 Taint 설정을 확인하고, 필요하다면 데몬셋 설정에 `tolerations`를 추가하여 해당 노드에서도 실행될 수 있도록 허용해 주세요. - ❌ 실수: 디플로이먼트 업데이트 중 Pod가 계속 생성/삭제를 반복함
왜 발생하는가: `maxSurge`와 `maxUnavailable` 설정값이 클러스터의 가용 자원(CPU/Memory)보다 높게 설정되어 자원이 부족해지는 현상이에요.
✅ 해결법: 노드의 남은 자원량을 계산하여 업데이트 시점에 사용할 수 있는 여유 자원 범위 내로 설정값을 조정하세요.
자주 묻는 질문
Q. 디플로이먼트와 레플리카셋의 차이점은 무엇인가요?
디플로이먼트는 레플리카셋을 관리하는 ‘상위 컨트롤러’예요. 레플리카셋은 단순히 개수만 유지하지만, 디플로이먼트는 배포 전략, 롤백, 버전 기록 관리 기능을 추가로 제공해요. 따라서 실무에서는 디플로이먼트를 쓰는 것이 기본이에요.
Q. 스테이트풀셋은 언제 사용하는 것이 가장 좋나요?
데이터베이스, 캐시 서버(Redis 등), 메시지 브로커처럼 각 인스턴스가 고유한 ID를 가져야 하거나, 재시작 시 반드시 이전에 연결되었던 저장소(Volume)를 다시 연결해야 하는 서비스에 사용하세요.
Q. 데몬셋은 모든 노드에 무조건 Pod를 띄우나요?
기본적으로는 그렇지만, `nodeSelector`나 `affinity` 설정을 통해 특정 레이블을 가진 노드에만 실행되도록 제한할 수도 있어요. 예를 들어 GPU가 있는 노드에만 AI 모델 추론 엔진을 띄울 때 유용해요.
Q. 레플리카셋만 사용해도 서비스 운영에 문제가 없나요?
단순한 테스트용이 아니라면 권장하지 않아요. 업데이트를 할 때마다 사람이 수동으로 Pod를 하나씩 지우고 새로 만들어야 하므로, 운영 실수(Human Error)가 발생할 확률이 매우 높고 장애 대응도 늦어져요.