
운영 중인 서비스의 포드가 갑자기 사라진다면?
새벽 3시, 관제 시스템에서 긴급 알람이 울립니다. 트래픽을 처리해야 할 핵심 서비스 포드 세 개가 갑자기 종료되었어요. 노드에 문제가 생겼거나 예기치 못한 오류로 포드가 죽었는데, 누군가 수동으로 다시 띄우기 전까지 서비스는 먹통 상태로 남게 됩니다. 대규모 트래픽을 다루는 SRE(Site Reliability Engineer)에게 이런 상황은 매일 반복될 수 있는 공포예요.
이런 문제를 해결하기 위해 쿠버네티스는 선언적 명령(Declarative Command) 방식을 사용해요. “포드가 몇 개 떠 있어야 한다”라고 미리 정의해 두면, 쿠버네티스가 알아서 현재 상태를 유지하려고 노력하죠. 그 핵심 도구가 바로 레플리카셋(ReplicaSet)이에요.
단순히 포드를 여러 개 띄우는 것을 넘어, 설정 파일인 YAML을 어떻게 작성하느냐에 따라 서비스의 안정성이 결정돼요. 잘못된 셀렉터(Selector) 설정 하나로 포드가 통제 불능 상태에 빠지거나, 리소스 제한을 설정하지 않아 클러스터 전체가 마비될 수도 있습니다.
이번 글에서는 실무에서 즉시 활용 가능한 레플리카셋 YAML 설정 파일 작성법을 깊이 있게 다뤄요. 다음 내용을 통해 실무 역량을 높여보세요.
- 레플리카셋 매니페스트의 핵심 필드별 상세 해설
- 가장 기초적인 최소 구성 YAML 예제
- 리소스 제한과 상태 확인이 포함된 실무형 확장 예제
- 설정 오류를 잡아내는 검증 및 트러블슈팅 방법
작성 전 반드시 점검해야 할 핵심 개념
레플리카셋 YAML을 작성하기 전에, 우리가 만들고자 하는 것이 정확히 무엇인지 이해해야 해요. 레플리카셋은 단순히 포드를 복제하는 도구가 아니라, 현재 상태(Current State)를 사용자가 정의한 원하는 상태(Desired State)와 일치시키는 컨트롤러예요.
이 메커니즘을 이해하지 못하면 셀렉터와 라벨 사이의 관계를 놓치기 쉬워요. 레플리카셋은 특정 라벨을 가진 포드들을 감시하고, 그 개수가 설정값과 다르면 즉시 조치를 취합니다. 따라서 YAML 작성 시 가장 먼저 준비해야 할 것은 관리할 포드들에 부여할 명확한 라벨 전략이에요.
레플리카셋은 포드를 직접 관리하기보다, 라벨을 기준으로 포드를 찾아내어 관리한다는 점을 명심하세요. 라벨이 일치하지 않으면 레플리카셋은 자신이 관리해야 할 포드를 찾지 못해 계속해서 새로운 포드를 생성하는 무한 루프에 빠질 수 있어요.
또한, 실무에서는 레플리카셋을 직접 사용하기보다 디플로이먼트(Deployment)를 통해 관리하는 경우가 훨씬 많아요. 하지만 디플로이먼트의 내부 동작 원리를 이해하고, 하위 객체인 레플리카셋의 매니페스트를 완벽히 파악하는 것은 고급 엔지니어로 가는 필수 관문이에요.
객체별 비교 및 선택 기준
상황에 따라 어떤 객체를 사용할지 판단하는 기준을 표로 정리했어요. 이 표를 보고 현재 운영 환경에 가장 적합한 도구를 선택해 보세요.
| 객체 유형 | 주요 목적 | 주요 특징 | 추천 상황 |
|---|---|---|---|
| Pod | 최소 실행 단위 | 단일 컨테이너 또는 다중 컨테이너 실행 | 테스트용 또는 단일 작업 |
| ReplicaSet | 포드 개수 유지 | 라벨 기반의 포드 복제 및 관리 | 가용성 보장 필요 시 |
| Deployment | 애플리케이션 배포 | 롤링 업데이트 및 롤백 기능 포함 | 대부분의 운영 환경 |
결론적으로, 단순히 포드 개수를 유지하는 기능만 필요하다면 레플리카셋으로 충분하지만, 서비스 업데이트(Rolling Update)나 안정적인 버전 관리까지 고려한다면 디플로이먼트를 사용하는 것이 표준이에요. 하지만 레플리카셋의 spec.selector와 spec.template 관계를 모르면 디플로이먼트도 제대로 다룰 수 없어요.
레플리카셋 YAML 작성 6단계 가이드
이제 본격적으로 실무에서 사용하는 레플리카셋 설정 파일 작성 과정을 단계별로 살펴볼게요. 각 단계를 따라가며 문법과 논리 구조를 익혀보세요.
STEP 1. 최소 구성 매니페스트 작성하기
가장 먼저 해야 할 일은 군더더기 없는 최소한의 코드를 작성하는 거예요. 이 코드는 레플리카셋이 작동하기 위한 뼈대 역할을 해요. 아래는 가장 기본적인 형태의 YAML 예시입니다.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: my-web-app
labels:
app: web-server
spec:
replicas: 3
selector:
matchLabels:
app: web-server
template:
metadata:
labels:
app: web-server
spec:
containers:
- name: nginx
image: nginx:1.21
이 짧은 코드 안에는 레플리카셋의 생명 주기와 직결된 핵심 요소들이 모두 들어있어요. 여기서 중요한 점은 spec.selector.matchLabels의 내용과 spec.template.metadata.labels의 내용이 반드시 일치해야 한다는 사실이에요. 이 둘이 어긋나면 레플리카셋은 자신이 만든 포드를 스스로 찾지 못하는 심각한 오류를 범하게 됩니다.
STEP 2. 필수 필드 하나씩 뜯어보기
이제 각 필드가 어떤 역할을 하는지 상세히 해설해 드릴게요. SRE라면 각 필드의 의미를 명확히 알고 있어야 장애 대응 시 빠르게 판단할 수 있어요.
- apiVersion: apps/v1 – 이 객체가 속한 API 그룹을 지정해요. 레플리카셋은 apps 그룹의 v1 버전을 사용합니다.
- kind: ReplicaSet – 생성하려는 리소스의 종류를 정의해요.
- metadata – 리소스의 이름(name)과 관리용 라벨(labels)을 담는 공간이에요.
- spec.replicas – 유지하고 싶은 포드의 개수를 정해요. 숫자가 0이면 모든 포드를 삭제하고, 숫자를 늘리면 즉시 추가 생성해요.
- spec.selector – 어떤 포드를 관리할지 결정하는 기준이에요.
matchLabels를 통해 지정한 라벨을 가진 포드들이 관리 대상이 됩니다. - spec.template – 레플리카셋이 새로운 포드를 생성할 때 사용할 설계도예요. Pod의 형식을 그대로 따릅니다.
spec.selector는 한 번 생성된 레플리카셋의 설정을 변경할 수 없어요. 만약 셀렉터를 바꾸고 싶다면 기존 레플리카셋을 삭제하고 새로 만들어야 합니다.STEP 3. 리소스 제한(Resources) 설정으로 안정성 높이기
실무에서 가장 빈번하게 발생하는 장애 중 하나는 특정 포드가 노드의 모든 자원을 점유해 버리는 현상이에요. 이를 방지하기 위해 컨테이너에 리소스 제한을 반드시 걸어주어야 합니다.
resources 필드는 두 가지 핵심 하위 필드를 가집니다. requests는 포드가 보장받아야 할 최소 자원량이고, limits는 포드가 사용할 수 있는 최대 자원량이에요. 스케줄러는 requests 값을 기준으로 포드를 어느 노드에 배치할지 결정합니다.
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
만약 limits.memory를 초과하면 쿠버네티스는 해당 포드를 OOMKilled(Out Of Memory Killed) 상태로 만들고 재시작합니다. CPU의 경우에는 제한을 넘으면 포드가 죽는 대신 속도가 느려지는 스로틀링(Throttling) 현상이 발생해요. 서비스의 성격에 맞춰 이 수치를 정밀하게 설계해야 합니다.
STEP 4. 상태 확인(Probes) 기능 추가하기
포드가 떠 있다고 해서 반드시 서비스가 정상인 것은 아니에요. 애플리케이션이 실행 중이지만 내부 오류로 응답을 못 할 수도 있죠. 이때 사용하는 것이 헬스 체크(Health Check)입니다.
- livenessProbe: 포드가 살아있는지 확인해요. 이 검사에 실패하면 쿠버네티스는 포드를 강제로 재시작합니다.
- readinessProbe: 포드가 트래픽을 받을 준비가 되었는지 확인해요. 실패하면 해당 포드를 서비스 엔드포인트에서 제외하여 사용자에게 오류가 전달되지 않게 막아줍니다.
이 두 가지 프로브를 적절히 설정해야만 트래픽 급증 시에도 안정적인 서비스 운영이 가능해요.
STEP 5. 실무형 확장 예제 통합하기
지금까지 배운 내용을 모두 합친, 실제 운영 환경에 근접한 완성형 YAML 예제를 보여드릴게요. 이 코드를 복사해서 실습 환경에 적용해 보세요.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: production-api-rs
labels:
app: api-server
env: production
spec:
replicas: 4
selector:
matchLabels:
app: api-server
template:
metadata:
labels:
app: api-server
spec:
containers:
- name: api-container
image: my-api:v2.1.0
ports:
- containerPort: 8080
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
STEP 6. 설정 검증 및 적용하기
YAML 작성이 끝났다면 바로 kubectl apply를 하기 전에 검증 단계를 거쳐야 해요. 실수를 줄이는 가장 좋은 방법은 다음 명령어를 활용하는 것입니다.
- kubectl apply –dry-run=client -f filename.yaml: 실제 클러스터에 적용하지 않고 문법적 오류가 없는지만 확인해요.
- kubectl diff -f filename.yaml: 현재 클러스터에 적용된 설정과 내가 수정한 YAML의 차이점을 보여줘요. 실수로 의도치 않은 설정을 변경하는 것을 막아줍니다.
자주 하는 실수와 해결법
레플리카셋을 다루다 보면 누구나 한 번쯤 겪는 문제들이 있어요. 실제 사례를 통해 예방 방법을 익혀보세요.
- ❌ 셀렉터와 라벨 불일치 → 레플리카셋이 포드를 생성하지만, 생성하자마자 자신이 만든 포드를 인식하지 못해 무한 생성 루프가 발생해요. → ✅
spec.selector.matchLabels와spec.template.metadata.labels가 100% 일치하는지 확인하세요. - ❌ 리소스 Limit 미설정 → 한 포드가 메모리를 전부 점유하여 같은 노드의 다른 포드들까지 함께 죽는 연쇄 장애가 발생해요. → ✅ 반드시
resources.limits를 설정하여 개별 컨테이너의 영향력을 제한하세요. - ❌ 너무 짧은 initialDelaySeconds → 앱이 뜨기도 전에 헬스 체크를 시도하여 포드가 무한 재시작되는 현상이 생겨요. → ✅ 앱의 기동 시간을 고려하여 충분한 지연 시간을 설정하세요.
- ❌ 잘못된 이미지 태그 사용:
latest태그를 사용하면 어떤 버전이 배포되었는지 추적하기 어려워요. → ✅v1.2.3처럼 명확한 버전 태그를 사용하세요. - ❌ Selector 수정 시도 → 이미 생성된 레플리카셋의 셀렉터를 바꾸려고 하면 에러가 발생해요. → ✅ 기존 레플리카셋을 삭제하고 새 YAML로 다시 생성하세요.
자주 묻는 질문
Q. 레플리카셋과 디플로이먼트의 결정적인 차이가 무엇인가요?
레플리카셋은 포드 개수 유지에 집중하지만, 버전을 업데이트하거나 롤백하는 기능은 없어요. 디플로이먼트는 레플리카셋을 내부적으로 관리하면서, 서비스 중단 없이 버전을 교체하는 기능을 제공하므로 실무에서는 디플로이먼트를 주로 사용해요.
Q. 왜 제 레플리카셋은 포드를 생성하지 못하고 대기 상태인가요?
대부분 리소스 부족 문제예요. 노드에 가용 가능한 CPU나 메모리가 부족하면 스케줄러가 포드를 배치하지 못합니다. kubectl describe rs [이름] 명령어로 이벤트를 확인해 보세요.
Q. 포드 개수를 실시간으로 조절할 수 있나요?
네, 가능해요. kubectl scale rs [이름] --replicas=5 명령어를 사용하거나, YAML 파일을 수정 후 다시 적용하면 즉시 반영됩니다.
Q. 라벨을 잘못 지정해서 포드가 유령처럼 떠 있어요. 어떻게 하죠?
레플리카셋이 관리하지 않는 라벨을 가진 포드들이 남은 거예요. 이 경우 포드를 수동으로 삭제하거나, 올바른 라벨을 가진 레플리카셋이 다시 생성되도록 관리해야 합니다.
안정적인 운영을 위한 마지막 체크리스트
레플리카셋 YAML 작성은 단순히 문법을 채우는 작업이 아니라, 서비스의 생존 조건을 정의하는 과정이에요. 작성한 파일이 운영 환경에 나가기 전, 아래 항목들을 다시 한번 눈으로 훑어보세요.
selector와template.labels가 정확히 일치하는가?- 컨테이너별
requests와limits가 설정되었는가? - 앱의 상태를 확인할
liveness와readiness프로브가 있는가? - 이미지 태그가
latest가 아닌 특정 버전인가? - 실행 전
--dry-run으로 문법 검증을 마쳤는가?
오늘 배운 내용을 바탕으로 지금 바로 실습 환경에서 자신만의 템플릿을 만들어 보세요. 처음에는 복잡해 보이지만, 한 번 구조를 익히고 나면 클러스터의 안정성을 제어하는 강력한 무기가 될 거예요.
실습 중 설정값이 적용되지 않거나 예상치 못한 에러 메시지가 나타난다면, 주저하지 말고 댓글로 질문을 남겨 주세요. 함께 해결 방안을 찾아보겠습니다.
함께 읽으면 좋은 글:
– 쿠버네티스 레플리카셋 기본 개념 총정리
– 클러스터 구축 및 기초 환경 설정 가이드