StatefulSet 아키텍처: 상태를 가지는 애플리케이션의 식별자 유지 비결
쿠버네티스를 처음 접할 때 가장 널리 사용하고 친숙해지는 워크로드 리소스는 단연 Deployment입니다. 웹 서버나 API 서버와 같은 무상태(Stateless) 애플리케이션을 배포할 때, Deployment는 장애가 발생한 파드(Pod)를 무작위 이름의 새로운 파드로 즉시 교체하여 서비스 가용성을 완벽하게 보장합니다.
하지만 모든 애플리케이션이 무상태인 것은 아닙니다. MySQL, MongoDB, Redis 같은 데이터베이스나 Kafka, RabbitMQ 같은 메시지 브로커들은 기존의 데이터를 보존해야 하며, 클러스터 노드 간에 마스터(Master)와 슬레이브(Slave) 같은 엄격한 역할과 순서가 존재합니다. 이런 '상태를 가지는(Stateful)' 애플리케이션에 무작위로 생성되고 소멸하는 Deployment를 적용하면 데이터가 유실되거나 클러스터링이 붕괴하는 대참사가 발생합니다.
이러한 상태 유지 애플리케이션을 클라우드 네이티브 환경에서 안전하게 오케스트레이션하기 위해 탄생한 컨트롤러가 바로 StatefulSet입니다. 이 가이드에서는 StatefulSet이 어떻게 파드들에게 불변의 식별자를 부여하고 스토리지를 영구적으로 매핑하는지 그 아키텍처의 비밀을 해부합니다.

1. 예측 가능하고 영구적인 식별자 (Sticky Identity)
Deployment가 생성하는 파드들의 이름은 web-7b5467984-x9f2a처럼 의미 없는 해시(Hash) 값의 난수로 구성됩니다. 파드가 재시작되면 이 이름과 IP는 완전히 다른 값으로 바뀝니다. 파드는 언제든 대체 가능한 '가축(Cattle)'으로 취급되기 때문입니다.
반면, StatefulSet은 파드를 대체 불가능한 '애완동물(Pet)'처럼 다룹니다. StatefulSet이 생성하는 파드는 해시값 대신, 0부터 시작하는 고정된 순서의 정수 인덱스(Ordinal Index)를 부여받습니다.
예를 들어 mysql이라는 이름의 StatefulSet을 3개(Replicas=3) 배포하면, 파드의 이름은 반드시 다음과 같이 고정됩니다.
mysql-0mysql-1mysql-2
만약 워커 노드에 장애가 발생하여 mysql-1 파드가 죽는다면, 쿠버네티스는 다른 노드에 파드를 다시 살려낼 때도 반드시 mysql-1이라는 정확히 똑같은 이름을 부여합니다. 이 불변의 이름표 덕분에 데이터베이스 클러스터 내의 노드들은 재시작 후에도 서로가 누구인지 명확히 인식하고 기존의 동기화 작업을 이어갈 수 있습니다.
2. 네트워크 신원의 보장: Headless Service의 마법
이름이 고정되었다고 해서 네트워크 통신이 저절로 보장되는 것은 아닙니다. 파드의 IP 주소는 재시작될 때마다 여전히 변경되기 때문입니다. StatefulSet은 변하는 IP 주소 대신 불변의 도메인(DNS) 이름을 제공하기 위해 Headless Service(헤드리스 서비스)와 강하게 결합하여 동작합니다.
일반적인 쿠버네티스 Service는 자신만의 가상 IP(ClusterIP)를 가지고 트래픽을 여러 파드에 로드밸런싱합니다. 하지만 Headless Service는 명세서에 clusterIP: None으로 설정되어, 로드밸런싱 IP를 가지지 않습니다.
대신, 쿠버네티스의 내부 DNS 서버(CoreDNS)는 Headless Service에 묶인 StatefulSet 파드 각각에 대해 개별적인 DNS 레코드를 자동으로 생성해 줍니다. DNS 규칙은 다음과 같습니다.
[파드-이름].[서비스-이름].[네임스페이스].svc.cluster.local
- 예시:
mysql-0.mysql-h-svc.default.svc.cluster.local
이 고유한 DNS 주소는 파드가 삭제되고 다른 IP로 다시 태어나더라도 절대 변하지 않습니다. 클러스터 내부의 다른 파드들은 로드밸런서를 거치지 않고 이 DNS 주소를 통해 mysql-0(마스터 노드) 또는 mysql-1(읽기 전용 노드)과 같이 원하는 특정 파드에 정확하게 1:1로 직접 연결(Direct Connection)을 맺을 수 있습니다.
3. 스토리지 신원의 보장: VolumeClaimTemplates
데이터베이스 워크로드에서 가장 중요한 것은 데이터의 영속성(Persistence)입니다. mysql-1 파드가 재시작되었을 때, 완전히 엉뚱한 빈 디스크가 연결된다면 고정된 이름과 DNS는 아무런 의미가 없습니다. 파드는 죽고 다시 태어나더라도 자신이 이전에 쓰던 바로 그 디스크(Volume)를 다시 찾아 물고 올라와야 합니다.
Deployment는 모든 파드가 동일한 하나의 Persistent Volume Claim (PVC)을 공유하거나, 임시 볼륨을 사용합니다. 반면 StatefulSet은 VolumeClaimTemplates(볼륨 클레임 템플릿)이라는 독창적인 매커니즘을 사용합니다.
- StatefulSet이
mysql-0파드를 생성할 때,VolumeClaimTemplates명세에 따라 해당 파드만을 위한 전용 PVC(예:data-mysql-0)를 동적으로 생성하고 디스크를 할당(Provisioning)받아 마운트합니다. - 이어서
mysql-1파드를 띄울 때도,data-mysql-1이라는 고유한 PVC를 자동으로 만들어 독립된 디스크를 마운트해 줍니다. - 치유 메커니즘: 만약 노드 장애로
mysql-1파드가 삭제되더라도, 쿠버네티스는 디스크에 저장된 실제 데이터를 보호하기 위해 PVC와 PV(Persistent Volume)를 절대 지우지 않고 그대로 보존합니다. 이후 Kubelet이 새로운 노드에mysql-1파드를 다시 띄울 때, 파드 이름과 일치하는 기존의data-mysql-1PVC를 찾아내어 자동으로 다시 연결(Re-attach)합니다.
이 완벽한 스토리지 바인딩 기술 덕분에, 관리자는 데이터 유실 걱정 없이 상태를 가지는 애플리케이션의 컨테이너 이미지를 업그레이드하거나 노드를 옮길 수 있습니다.
4. 질서 정연한 생명주기: 엄격한 순서 보장 (Ordered Deployment)
무상태(Stateless) 앱들은 파드 3개를 띄우라고 하면 순서 없이 동시에 3개를 마구잡이로 실행시킵니다. 하지만 StatefulSet은 클러스터링을 구성하는 데이터베이스의 특성을 반영하여 파드의 생성과 삭제에 엄격한 '순서(Order)'를 강제합니다.
4.1. 파드 생성 및 스케일 아웃 (Scale Up)
StatefulSet은 0번 인덱스부터 순차적으로 파드를 생성합니다.mysql-0 파드가 생성되고 완벽하게 Ready 상태가 될 때까지 기다립니다. 0번 파드가 정상 궤도에 오르면 비로소 mysql-1 파드를 띄우고, 1번이 정상화되면 mysql-2를 띄웁니다.
- 이유: 대부분의 분산 시스템은 첫 번째 노드(
0번)를 메인 시드(Seed) 또는 마스터 노드로 삼고, 이후에 올라오는 노드들이 마스터에 접속하여 초기 동기화를 수행하기 때문입니다. 동시 생성으로 인한 데이터베이스 클러스터의 혼돈(Split-brain 등)을 원천 차단합니다.
4.2. 파드 축소 및 삭제 (Scale Down)
반대로 파드의 개수를 줄이거나 StatefulSet을 삭제할 때는 가장 높은 인덱스부터 역순으로 삭제합니다. (2 -> 1 -> 0)
- 이유: 가장 늦게 합류한 말단 노드부터 안전하게 클러스터에서 제외시키고 데이터를 정리(Drain)할 시간을 주어야 마스터 노드와 스토리지 쿼럼(Quorum)의 안정성이 훼손되지 않기 때문입니다.
5. 결론: 분산 데이터 시스템의 든든한 뼈대
StatefulSet은 단순히 Deployment의 변형이 아닙니다. 애플리케이션이 요구하는 까다로운 물리적 서버의 특성(고정 IP, 영구 독립 디스크, 순차적 부팅)을 유연한 컨테이너 생태계 위에 추상화하여 구현해 낸 매우 정교한 상태 머신입니다.
Elasticsearch, Cassandra, Zookeeper 등 복잡한 데이터 파이프라인을 쿠버네티스 위로 이관하려 한다면, StatefulSet의 이 고유한 식별자 유지 메커니즘을 명확히 이해하고 활용하는 것이 엔터프라이즈급 데이터 안정성을 확보하는 진정한 비결이 될 것입니다.
'1. K8s Core & Architecture > 1.3. 파드(Pod)와 워크로드 아키텍처' 카테고리의 다른 글
| Job과 CronJob 컨트롤러 아키텍처: 배치 프로세싱의 정석 (0) | 2026.04.10 |
|---|---|
| DaemonSet 동작 원리: 모든 노드에 파드를 보장하는 스케줄링 메커니즘 (0) | 2026.04.09 |
| 롤링 업데이트(Rolling Update) 전략과 MaxSurge, MaxUnavailable 이해 (0) | 2026.04.09 |
| Deployment 리소스의 내부 동작: ReplicaSet을 어떻게 관리하는가? (0) | 2026.04.09 |
| Ephemeral Containers: 실행 중인 파드 디버깅을 위한 혁신 (0) | 2026.04.08 |