
스테이트풀셋 전환, 왜 신중해야 할까요
금요일 오후, 서비스 업데이트를 위해 디플로이먼트(Deployment)를 수정하던 중 갑작스러운 데이터 유실 사고가 발생했다면 어떨까요? 데이터베이스나 메시지 큐처럼 상태를 유지해야 하는 애플리케이션을 운영하는 데브옵스 엔지니어라면 누구나 한 번쯤 겪어봤을 법한 끔찍한 상상이에요. 단순히 포드(Pod)가 새로 뜨는 문제가 아니라, 그동안 쌓아온 소중한 데이터가 연결되지 않거나 파편화되는 순간 서비스 전체가 마비될 수 있어요.
많은 팀이 운영 편의성을 위해 처음에는 디플로이먼트로 시작하지만, 서비스 규모가 커지고 데이터의 영속성이 중요해지면서 결국 스테이트풀셋(StatefulSet)으로의 전환을 고민하게 됩니다. 하지만 스테이트풀셋은 일반적인 배포 방식과 네트워크 식별 방식, 그리고 스토리지 관리 메커니즘이 완전히 달라요. 준비 없이 접근했다가는 기존의 퍼시스턴트 볼륨 클레임(PVC)이 꼬이거나, 포드 이름이 바뀌면서 애플리케이션 내부 로직이 깨지는 대참사가 벌어질 수 있습니다.
이 글은 단순히 이론적인 개념을 나열하는 데 그치지 않아요. 실제 운영 환경에서 어떻게 기존 데이터를 안전하게 옮기고, 어떻게 하면 사용자에게 영향을 주지 않으면서 무중단으로 전환할 수 있는지 그 구체적인 로드맵을 제시합니다. 마이그레이션 도중 예상치 못한 오류가 발생했을 때 즉시 이전 상태로 되돌릴 수 있는 롤백 계획까지 모두 담았습니다.
이 글을 끝까지 읽으시면 다음과 같은 핵심 역량을 갖추게 될 거예요.
- 현행 디플로이먼트 구성과 스테이트풀셋 간의 구조적 차이점 완벽 이해
- 데이터 유실을 방지하는 단계별 마이그레이션 실행 절차 습득
- 무중단 전환을 위한 블루-그린(Blue-Green) 및 카나리(Canary) 전략 적용법
- 실제 장애 상황에 대비한 검증 및 롤백 시나리오 설계 능력
사전 준비 — 성공적인 전환을 위한 체크리스트
무턱대고 매니페스트를 수정하고 적용하는 것은 가장 위험한 행동이에요. 스테이트풀셋 전환은 인프라의 근간을 바꾸는 작업이기에, 현재 우리 클러스터가 어떤 상태인지, 그리고 우리가 사용할 스토리지가 스테이트풀셋의 요구사항을 충족하는지 면밀히 검토해야 합니다.
전환 전 반드시 확인해야 할 핵심 요소
가장 먼저 확인해야 할 것은 스토리지 클래스(StorageClass)와 볼륨의 결합 방식이에요. 디플로이먼트는 여러 포드가 하나의 PVC를 공유하는 방식이 흔하지만, 스테이트풀셋은 각 포드가 자신만의 고유한 PVC를 가져야 합니다. 만약 현재 사용 중인 스토리지 프로비저너가 개별 PVC 생성을 지원하지 않거나, 동적 할당(Dynamic Provisioning) 설정이 제대로 되어 있지 않다면 전환 과정에서 포드가 계속해서 Pending 상태에 머물게 될 거예요.
또한, 애플리케이션이 네트워크 식별자를 어떻게 사용하는지도 중요해요. 스테이트풀셋은 포드마다 고유한 호스트명을 부여하기 때문에, 애플리케이션 설정 파일에 기존 디플로이먼트 기반의 서비스 주소가 하드코딩되어 있다면 이를 수정할 준비를 마쳐야 합니다. 헤드리스 서비스(Headless Service)를 통해 각 포드에 개별 DNS 레코드가 생성될 것임을 인지하고 있어야 하죠.
스테이트풀셋은 포드가 재시작되어도 이름과 저장 공간이 유지되는 것을 보장합니다. 하지만 이는 쿠버네티스가 보장하는 것이지, 애플리케이션 내부의 데이터 정합성까지 책임지는 것은 아니라는 점을 기억하세요.
디플로이먼트 vs 스테이트풀셋 비교 분석
전환 전략을 세우기 위해 두 오브젝트의 차이점을 명확히 알고 있어야 합니다. 아래 표를 통해 결정적인 차이점들을 비교해 보세요.
| 구분 항목 | 디플로이먼트(Deployment) | 스테이트풀셋(StatefulSet) |
|---|---|---|
| 포드 식별자 | 무작위 해시값 (예: web-abc12) | 순차적 인덱스 (예: db-0, db-1) |
| 스토리지 관계 | 여러 포드가 하나의 PVC 공유 가능 | 포드당 1:1 매칭된 고유 PVC 사용 |
| 네트워크 정체성 | 서비스를 통한 로드밸런싱 위주 | 헤드리스 서비스를 통한 개별 접근 |
| 배포 순서 | 동시 혹은 무작위 생성/삭제 | 0번부터 순차적 생성 및 역순 삭제 |
이 비교를 통해 알 수 있듯이, 스테이트풀셋은 데이터의 정체성과 순서가 핵심입니다. 따라서 준비 단계에서는 단순히 매니페스트를 만드는 것을 넘어, 기존 데이터가 어떻게 새로운 포드의 고유한 PVC로 옮겨갈 수 있을지를 결정하는 것이 가장 큰 숙제입니다.
핵심 실행 단계 — 무중단 마이그레이션 가이드
이제 본격적인 전환 절차에 들어갑니다. 이 과정은 크게 5개의 단계로 나뉩니다. 각 단계는 이전 단계가 완벽하게 검증된 후에 다음으로 넘어가야 하며, 중간에 하나라도 어긋나면 즉시 중단하고 롤백 시나리오를 가동해야 합니다.
STEP 1. 현행 리소스 및 데이터 볼륨 분석
가장 먼저 해야 할 일은 현재 디플로이먼트가 사용하는 PVC와 실제 스토리지의 상태를 스캔하는 것입니다. 기존에 사용하던 볼륨이 ReadWriteOnce(RWO)인지, ReadWriteMany(RWX)인지 확인하세요. 대부분의 데이터베이스는 RWO를 사용하며, 이는 한 번에 하나의 노드에만 마운트될 수 있음을 의미합니다. 이 점은 나중에 포드를 옮길 때 볼륨 마운트 지연(Mount Delay)을 유발할 수 있는 중요한 변수가 됩니다.
또한, 기존 데이터의 용량과 백업 상태를 점검해야 해요. 마이그레이션 도중 디스크 용량이 가득 차면 데이터 오염이 발생할 수 있으므로, 최소한 현재 사용량의 1.5배 이상의 여유 공간이 있는 스토리지를 준비하는 것이 좋습니다. 데이터의 무결성을 위해 반드시 스냅샷(Snapshot) 기능을 지원하는 스토리지 클래스를 사용하는지 확인하세요.
STEP 2. 스테이트풀셋 매니페스트 설계
스테이트풀셋은 디플로이먼트와 설계 방식이 완전히 다릅니다. 특히 volumeClaimTemplates 항목이 가장 핵심적인 차이점입니다. 디플로이먼트에서는 PVC를 별도로 생성하여 포드에 연결하지만, 스테이트풀셋은 매니페스트 내부에 볼륨 템플릿을 정의하여 포드가 생성될 때마다 자동으로 PVC를 생성하도록 만듭니다.
설계 시 다음 요소들을 반드시 포함해야 합니다.
- 헤드리스 서비스(Headless Service): 클러스터 내부 DNS가 각 포드에 직접 접근할 수 있도록 `clusterIP: None`으로 설정된 서비스를 반드시 생성해야 합니다.
- 포드 관리 정책(Pod Management Policy): 배포 속도를 높이고 싶다면 `Parallel`을 사용할 수 있지만, 안정적인 데이터 동기화가 우선이라면 기본값인 `OrderedReady`를 사용하여 순차적으로 배포되도록 하세요.
- 리소스 제한(Resource Limits): 데이터 동기화 작업은 CPU와 메모리를 일시적으로 많이 소모할 수 있으므로, 평소보다 조금 더 넉넉하게 설정하는 것이 안전합니다.
스테이트풀셋의 포드 이름은 `이름-인덱스` 형식을 따릅니다. 예를 들어 스테이트풀셋 이름이 `mysql`이라면 포드 이름은 `mysql-0`, `mysql-1`이 됩니다. 기존 디플로이먼트의 포드 이름과 완전히 다르다는 점을 애플리케이션 로직이 인지하고 있어야 합니다.
STEP 3. 데이터 동기화 및 검증 환경 구축
데이터를 옮기는 방법은 크게 두 가지가 있습니다. 첫 번째는 스토리지 레벨의 복제이고, 두 번째는 애플리케이션 레벨의 복제입니다. 인프라 관리 권한이 있다면 스토리지 스냅샷을 활용하는 것이 가장 빠르고 안전합니다. 하지만 클라우드 환경의 제약이 있다면 애플리케이션 자체의 복제 기능(예: MySQL의 Master-Slave 복제)을 활용하는 것이 더 현실적입니다.
가장 권장하는 시나리오는 다음과 같습니다.
- 새로운 스테이트풀셋을 별도의 네임스페이스나 테스트 환경에 먼저 배포합니다.
- 기존 디플로이먼트의 데이터를 스냅샷을 통해 새로운 스테이트풀셋의 PVC로 복제합니다.
- 새로운 스테이트풀셋의 포드가 정상적으로 뜨는지, 데이터가 깨지지 않고 읽히는지 검증합니다.
이 과정에서 데이터 정합성 체크를 위해 간단한 쿼리를 날려보거나, 로그를 통해 파일 시스템 오류가 없는지 꼼꼼히 살펴봐야 합니다.
STEP 4. 무중단 전환 실행 (Canary/Blue-Green)
실제 운영 환경으로 전환할 때는 한 번에 모든 것을 바꾸지 마세요. 카나리(Canary) 방식을 추천합니다. 우선 스테이트풀셋의 0번 포드만 먼저 띄워서 일부 트래픽만 흘려보내며 상태를 관찰하는 방식입니다. 만약 서비스가 안정적이라면 점진적으로 포드 개수를 늘려갑니다.
더 확실한 방법은 블루-그린 전략입니다. 기존 디플로이먼트(Blue)를 그대로 둔 채, 모든 데이터가 동기화된 완벽한 스테이트풀셋(Green)을 구축합니다. 이후 로드밸런서나 인그레스(Ingress)의 타겟을 블루에서 그린으로 교체합니다. 이 방식은 전환 즉시 문제가 발견될 경우, 서비스 엔드포인트만 다시 블루로 돌리면 되기 때문에 가장 안전한 전환 방식으로 통합니다.
STEP 5. 최종 검증 및 기존 리소스 정리
전환이 완료되었다면 일정 시간 동안 모니터링 대시보드를 주시해야 합니다. 포드의 재시작 횟수, 디스크 I/O 수치, 그리고 네트워크 지연 시간을 체크하세요. 모든 것이 정상이라면, 비로소 기존의 디플로이먼트와 사용하지 않는 이전 PVC를 삭제합니다. 이때 주의할 점은 PVC 삭제는 반드시 모든 데이터가 완벽히 이전되었음을 확신한 후에 진행해야 한다는 것입니다. 한 번 삭제된 PVC는 복구가 매우 어렵습니다.
전환 직후에는 기존 디플로이먼트를 즉시 삭제하지 마세요. 최소 24시간에서 48시간 정도는 ‘Standby’ 상태로 유지하며, 언제든 즉시 트래픽을 되돌릴 수 있는 상태를 유지하는 것이 운영의 정석입니다.
자주 하는 실수와 해결법
마이그레이션 과정에서 엔지니어들이 가장 흔하게 겪는 시행착오들을 정리했습니다. 문제가 발생했을 때 당황하지 말고 이 리스트를 먼저 확인해 보세요.
- ❌ 실수: 스테이트풀셋 포드가 계속 Pending 상태에 머물러요.
→ 왜 발생하는가: 스테이트풀셋이 요구하는 새로운 PVC를 생성할 수 있는 스토리지 클래스가 없거나, 기존 볼륨이 다른 노드에 마운트되어 있어 이동할 수 없기 때문이에요.
→ ✅ 해결법: `kubectl describe pod` 명령어로 이벤트 로그를 확인하여 스토리지 클래스 설정과 볼륨 바인딩 상태를 체크하세요. - ❌ 실수: 포드가 뜨긴 했는데 데이터가 보이지 않아요.
→ 왜 발생하는가: 디플로이먼트의 PVC와 스테이트풀셋의 `volumeClaimTemplates`가 서로 다른 볼륨을 바라보고 있기 때문이에요.
→ ✅ 해결법: 기존 PVC의 `volumeName`을 확인하고, 스테이트풀셋 전환 시 해당 볼륨이 정확히 매핑되도록 수동으로 PVC를 생성하거나 이름을 일치시켜야 합니다. - ❌ 실수: 애플리케이션이 데이터베이스를 찾지 못해요.
→ 왜 발생하는가: 서비스 주소가 기존 디플로이먼트 기반의 서비스 이름으로 설정되어 있어, 스테이트풀셋의 개별 포드 주소를 찾지 못하는 것이에요.
→ ✅ 해결법: 헤드리스 서비스 주소를 기반으로 애플리케이션의 엔드포인트 설정을 업데이트하세요. - ❌ 실수: 전환 후 서비스 속도가 갑자기 느려졌어요.
→ 왜 발생하는가: 데이터 복제 과정에서 디스크 I/O 부하가 발생했거나, 네트워크 식별자 변경으로 인해 잘못된 경로로 트래픽이 흐르고 있을 수 있어요.
→ ✅ 해결법: 모니터링 도구로 스토리지의 IOPS와 네트워크 지연 시간을 확인하고, 포드 간 통신이 헤드리스 서비스를 통해 정상적으로 이루어지는지 테스트하세요. - ❌ 실수: 롤백을 시도했는데 이전 데이터로 돌아가지 않아요.
→ 왜 발생하는가: 전환 과정에서 기존 데이터가 이미 수정되었거나, 백업본이 최신 상태가 아니기 때문이에요.
→ ✅ 해결법: 마이그레이션 시작 전 반드시 스냅샷을 찍어두고, 롤백 시에는 스냅샷을 기반으로 볼륨을 복구하는 절차를 밟아야 합니다.
자주 묻는 질문
Q. 디플로이먼트에서 사용하던 PVC를 스테이트풀셋에 그대로 붙여 쓸 수 있나요?
네, 가능합니다. 하지만 스테이트풀셋은 기본적으로 `volumeClaimTemplates`를 통해 새로운 PVC를 만들려고 하기 때문에, 기존 PVC를 강제로 연결하려면 스테이트풀셋이 생성될 포드의 인덱스(예: `data-db-0`)와 동일한 이름의 PVC를 미리 수동으로 생성해 두어야 합니다.
Q. 무중단 전환이 정말로 가능한가요?
완벽한 의미의 제로 다운타임은 애플리케이션의 특성에 따라 다릅니다. 데이터베이스처럼 쓰기 작업이 빈번한 경우, 쓰기 권한을 잠시 차단(Read-only 모드)해야 하는 순간이 올 수 있어요. 하지만 블루-그린 전략을 잘 사용하면 사용자 체감 시간을 초 단위로 줄일 수 있습니다.
Q. 스테이트풀셋을 쓰면 관리가 더 힘들어지나요?
네, 맞습니다. 디플로이먼트처럼 포드가 죽었다고 해서 아무 데나 새로 뜨는 게 아니라, 특정 이름과 특정 볼륨을 찾아가는 과정이 필요하므로 관리 복잡도는 올라갑니다. 하지만 데이터 안정성을 생각한다면 반드시 감수해야 할 부분이에요.
Q. 롤백 계획을 세울 때 가장 중요한 것은 무엇인가요?
가장 중요한 것은 ‘데이터의 최신성’입니다. 전환 중 발생한 변경 사항을 어떻게 버릴 것인지, 혹은 어떻게 다시 가져올 것인지에 대한 결정이 미리 되어 있어야 합니다.