[IT-방법] 스테이트풀셋 실전 예제 따라하기 – 배포부터 동작 검증까지 단계별 실습

스테이트풀셋 관련 쿠버네티스 구조를 설명하는 대표 이미지

스테이트풀셋이 필요한 진짜 이유

데이터베이스를 운영하던 데브옵스 엔지니어가 가장 당황하는 순간은 언제일까요? 아마도 잘 돌아가던 DB 포드가 재시작되었는데, 이전의 데이터가 사라졌거나 네트워크 식별자가 바뀌어 클러스터 구성원들이 서로를 찾지 못할 때일 거예요. Deployment를 사용해 데이터베이스를 배포했다면 이런 문제는 피하기 어렵습니다. Deployment는 포드의 교체를 기본 원칙으로 하기 때문에, 포드가 새로 생성될 때마다 이름도 바뀌고 연결된 스토리지도 초기화될 위험이 크기 때문이에요.

상태를 유지해야 하는 애플리케이션, 즉 데이터베이스나 메시지 큐 같은 시스템은 단순한 재시작만으로는 부족합니다. 포드가 어떤 이름으로 실행되었는지, 어떤 저장 공간을 사용하고 있었는지에 대한 고유한 정체성이 유지되어야 해요. 이것이 바로 쿠버네티스에서 스테이트풀셋(StatefulSet)을 사용하는 결정적인 이유입니다.

이 글을 읽고 나면 스테이트풀셋을 활용해 데이터가 보존되는 안정적인 시스템을 구축할 수 있어요. 단순히 이론을 배우는 것에 그치지 않고, 실제 실무에서 바로 사용할 수 있는 수준의 실습 과정을 경험하게 될 거예요. 구체적으로 다음과 같은 내용을 단계별로 다룹니다.

  • 스테이트풀셋과 디플로이먼트의 핵심 차이점 이해하기
  • 데이터 영속성을 위한 매니페스트 파일 작성법
  • 클러스터 배포 후 네트워크 식별자와 스토리지 검증하기
  • 실제 운영 환경에서 발생할 수 있는 오류 해결법
💡 알아두기
스테이트풀셋은 포드에 고유한 번호를 부여하고, 포드가 재시작되어도 동일한 네트워크 주소와 저장 공간을 다시 연결해 주는 기능을 수행해요.

실습 시작 전 꼭 알아야 할 핵심 개념

본격적인 스테이트풀셋 실전 예제를 시작하기 전에, 우리가 다루는 리소스들이 정확히 어떤 성격을 가졌는지 명확히 짚고 넘어가야 해요. 무턱대고 코드부터 복사해서 붙여넣으면, 왜 데이터가 저장되지 않는지 혹은 왜 네트워크 통신이 안 되는지 원인을 찾느라 시간을 허비하게 될 수 있습니다.

가장 먼저 이해해야 할 점은 스테이트풀셋이 단순히 포드를 관리하는 것을 넘어, 정체성(Identity)을 관리한다는 사실이에요. 일반적인 워크로드는 포드가 죽으면 똑같은 복제본을 새로 만들면 그만이지만, 스테이트풀셋은 ‘0번 포드’가 죽으면 반드시 ‘0번 포드’라는 이름과 그에 맞는 스토리지로 다시 살아나야 합니다.

디플로이먼트와 스테이트풀셋 비교

두 리소스의 차이를 명확히 알면 어떤 상황에 무엇을 써야 할지 판단할 수 있어요. 아래 표를 통해 핵심적인 차이점을 확인해 보세요.

구분 항목 디플로이먼트(Deployment) 스테이트풀셋(StatefulSet)
포드 이름 무작위 해시값 (예: web-abc12) 순차적 번호 (예: web-0, web-1)
스토리지 연결 모든 포드가 동일한 볼륨 공유 가능 포드마다 개별적인 볼륨 할당 (1:1)
네트워크 주소 서비스를 통해서만 접근 가능 각 포드별 고유한 DNS 주소 제공
배포 순서 동시 또는 무작위 배포 0번부터 순차적으로 생성 및 삭제

위 표에서 알 수 있듯이, 데이터의 일관성과 순서가 중요한 애플리케이션에는 반드시 스테이트풀셋을 선택해야 해요. 만약 분산 데이터베이스를 운영하면서 디플로이먼트를 사용한다면, 각 노드가 서로를 식별하지 못해 클러스터가 깨지는 대참사를 겪을 수 있습니다.

실습을 위한 필수 체크리스트

실습을 진행하기 전에 여러분의 환경이 준비되었는지 확인해 주세요. 준비가 미흡하면 배포 단계에서 많은 오류를 마주하게 됩니다.

  • 쿠버네티스 클러스터: 최소 3개 이상의 노드를 가진 클러스터가 권장됩니다.
  • kubectl 도구: 클러스터에 명령을 내릴 수 있는 최신 버전의 CLI가 설치되어 있어야 해요.
  • 스토리지 클래스(StorageClass): 동적 볼륨 프로비저닝을 지원하는 스토리지 클래스가 설정되어 있어야 실습이 수월합니다.
  • 권한: 클러스터의 리소스를 생성하고 삭제할 수 있는 관리자 권한이 필요합니다.
⚠️ 주의
실습 환경이 클라우드(EKS, GKE 등)라면 스토리지 클래스 이름이 기본 설정과 다를 수 있으니, 반드시 `kubectl get sc` 명령어로 먼저 확인해 주세요.

스테이트풀셋 실전 배포 단계별 가이드

이제 준비가 끝났다면 직접 스테이트풀셋 예제를 따라하며 시스템을 구축해 볼 차례예요. 이번 실습에서는 간단한 Nginx 서버를 활용하지만, 내부적으로는 데이터가 저장되는 볼륨과 고유한 네트워크 주소를 갖도록 구성할 겁니다. 이를 통해 실제 데이터베이스 배포와 유사한 환경을 만들어 볼게요.

STEP 1. 데이터 저장을 위한 스토리지 클래스 확인

스테이트풀셋의 핵심은 포드가 사라져도 데이터가 살아남는 것입니다. 이를 위해서는 포드가 생성될 때마다 자동으로 볼륨을 만들어주는 Dynamic Provisioning 기능이 필요해요. 먼저 현재 클러스터에서 사용할 수 있는 스토리지 클래스를 확인해 보세요.

`kubectl get sc` 명령어를 입력하면 사용 가능한 리스트가 나옵니다. 여기서 `standard`나 `gp2` 같은 이름을 기억해 두세요. 만약 아무것도 나오지 않는다면, 테스트를 위해 로컬 스토리지 프로비저너를 설치하거나 클라우드 환경의 기본 설정을 확인해야 합니다. 우리가 작성할 매니페스트 파일에서 이 이름을 지정해 줄 것이기 때문이에요.

STEP 2. 스테이트풀셋 매니페스트 파일 작성

이제 가장 중요한 단계인 YAML 파일을 작성할 시간입니다. 스테이트풀셋은 일반적인 디플로이먼트와 달리 Headless Service가 반드시 필요합니다. 이 서비스는 포드에 각각 고유한 DNS 이름을 부여하는 역할을 해요.

아래는 우리가 사용할 전체 매니페스트 구조입니다. 이 코드를 `statefulset-demo.yaml`이라는 이름으로 저장해 주세요.

💡 알아두기
Headless Service는 ClusterIP를 0으로 설정하여, 서비스 IP를 거치지 않고 포드의 개별 IP로 직접 통신할 수 있게 해줍니다.

매니페스트의 핵심 포인트는 세 가지입니다. 첫째, `serviceName` 필드가 서비스 이름과 일치해야 한다는 점이에요. 둘째, `volumeClaimTemplates`를 통해 각 포드가 자신만의 전용 디스크를 갖도록 정의합니다. 셋째, 포드의 순차적 생성을 보장합니다.

STEP 3. 클러스터에 리소스 배포하기

파일 작성을 마쳤다면 이제 클러스터에 명령을 내릴 차례예요. 작성한 파일을 적용하기 위해 다음 명령어를 사용합니다.

`kubectl apply -f statefulset-demo.yaml`

명령어를 입력하면 쿠버네티스 컨트롤러가 작동하기 시작합니다. 스테이트풀셋은 디플로이먼트와 다르게 포드를 하나씩 생성해요. 0번 포드가 완전히 실행(Running) 상태가 되고, 준비 완료(Ready) 상태가 될 때까지 기다린 후에 1번 포드를 만들기 시작합니다. 이는 데이터베이스 클러스터에서 마스터 노드가 먼저 준비되어야 슬레이브 노드가 붙을 수 있는 논리를 구현한 것이에요. `kubectl get pods -w` 명령어를 통해 포드가 순서대로 올라오는 모습을 실시간으로 관찰해 보세요.

STEP 4. 네트워크 식별자와 동작 검증하기

포드가 모두 생성되었다면, 우리가 의도한 대로 고유한 네트워크 주소를 가지고 있는지 확인해야 합니다. 스테이트풀셋은 `<포드이름>.<서비스이름>.<네임스페이스>.svc.cluster.local` 형태의 DNS 이름을 자동으로 생성합니다.

임시 포드를 하나 띄워서 내부에서 DNS 쿼리를 날려볼 수 있어요.
`kubectl run -it –rm –image=busybox:1.28 dns-test — restart=Never — nslookup web-0.nginx-service`
위 명령어를 실행했을 때 `web-0.nginx-service`에 대한 IP 주소가 응답으로 온다면, 네트워크 식별자 설정이 완벽하게 성공한 것입니다. 이것이 가능하다는 것은 나중에 데이터베이스 노드 간 통신을 할 때 매우 안정적인 연결을 보장한다는 뜻이에요.

STEP 5. 데이터 영속성 테스트 (가장 중요)

마지막으로, 포드가 삭제되어도 데이터가 사라지지 않는지 직접 테스트해 봅시다. 이 과정이 실패한다면 여러분의 스테이트풀셋 설정은 실무에서 사용할 수 없는 상태입니다.

  1. 먼저 0번 포드에 접속하여 특정 파일을 생성합니다:
    `kubectl exec web-0 — sh -c “echo ‘Hello Kubernetes’ > /data/test.txt”`
  2. 그다음, 0번 포드를 강제로 삭제합니다:
    `kubectl delete pod web-0`
  3. 잠시 기다리면 스테이트풀셋 컨트롤러가 0번 포드를 다시 생성합니다.
  4. 새로 생성된 0번 포드에 다시 접속하여 파일이 남아있는지 확인합니다:
    `kubectl exec web-0 — cat /data/test.txt`

만약 `Hello Kubernetes`라는 문구가 그대로 출력된다면, 데이터 영속성 테스트에 성공한 것입니다! 포드는 이름도 같고, 연결된 PVC(PersistentVolumeClaim)도 그대로 유지되었기 때문에 이전 데이터를 그대로 읽어올 수 있는 것이죠.

💡 알아두기
실제 운영 환경에서는 포드를 삭제해도 PVC는 자동으로 삭제되지 않습니다. 데이터를 완전히 지우려면 사용자가 직접 PVC를 삭제해야 하니 주의가 필요해요.

자주 하는 실수와 해결법

실전에서 스테이트풀셋을 다루다 보면 예상치 못한 벽에 부딪히곤 합니다. 가장 흔하게 발생하는 문제들을 정리했으니, 문제가 생겼을 때 빠르게 대조해 보세요.

  • 포드가 Pending 상태에서 멈춰있어요
    원인: 대부분 스토리지 클래스가 잘못 지정되었거나, 해당 클래스로 볼륨을 생성할 권한이 없는 경우입니다.
    → ✅ 해결법: `kubectl describe pod [포드이름]`을 실행하여 `Events` 섹션을 확인하세요. 스토리지 프로비저너가 볼륨 생성에 실패했다는 메시지가 있다면 스토리지 클래스 이름을 다시 확인해야 합니다.
  • 포드 이름 뒤에 숫자가 붙지 않아요
    원인: 스테이트풀셋이 아닌 디플로이먼트를 사용 중일 가능성이 높습니다.
    → ✅ 해결법: 매니페스트의 `kind` 필드가 `StatefulSet`으로 정확히 명시되어 있는지 확인하세요.
  • 네트워크 통신이 안 돼요 (DNS 오류)
    원인: Headless Service가 설정되지 않았거나, 매니페스트의 `serviceName` 필드가 서비스 이름과 다를 때 발생합니다.
    → ✅ 해결법: 서비스의 `metadata.name`과 스테이트풀셋의 `spec.serviceName`이 토씨 하나 안 틀리고 일치하는지 확인하세요.
  • 포드를 삭제했는데 데이터가 사라졌어요
    원인: `volumeClaimTemplates`를 사용하지 않고 포드 안에 직접 볼륨을 마운트했기 때문입니다.
    → ✅ 해결법: 반드시 스테이트풀셋의 `volumeClaimTemplates` 섹션을 사용하여 포드마다 개별 PVC가 생성되도록 구성해야 합니다.
  • 포드 생성 순서가 뒤섞여요
    원인: Readiness Probe(준비 상태 검사)가 설정되지 않아 포드가 준비되기도 전에 다음 포드가 생성될 수 있습니다.
    → ✅ 해결법: 각 컨테이너에 적절한 `readinessProbe`를 설정하여, 서비스가 준비될 때까지 쿠버네티스가 기다리도록 만드세요.

자주 묻는 질문

Q. 스테이트풀셋은 무조건 디플로이먼트보다 느린가요?

포드를 하나씩 순차적으로 생성하기 때문에 전체 배포 시간은 디플로이먼트보다 길 수 있습니다. 하지만 데이터의 일관성과 안정성을 위해 이 정도의 시간은 감수해야 하는 부분이에요.

Q. 스테이트풀셋을 삭제하면 데이터(PVC)도 같이 삭제되나요?
쿠버네티스의 설계 철학상, 스테이트풀셋을 삭제해도 연결된 PVC는 보호를 위해 자동으로 삭제되지 않습니다. 데이터 유실을 막기 위한 안전장치이니, 정말 필요하다면 직접 PVC를 삭제해 주어야 해요.

Q. 어떤 애플리케이션에 스테이트풀셋을 쓰는 게 가장 좋나요?
MySQL, PostgreSQL, MongoDB, Redis, Kafka, ZooKeeper처럼 각 노드가 고유한 ID를 가져야 하거나 데이터 저장소가 핵심인 애플리케이션에 가장 적합합니다.

Q. 헬름(Helm) 차트로 설치할 때도 스테이트풀셋을 쓰나요?
네, 많은 데이터베이스용 헬름 차트들이 내부적으로 스테이트풀셋을 사용하도록 설계되어 있습니다. 차트의 `values.yaml` 설정을 통해 스테이트풀셋의 동작을 세밀하게 조정할 수 있어요.

Q. 포드 개수를 늘리면 기존 데이터에 영향을 주나요?
아니요, 스테이트풀셋은 포드 개수를 늘릴 때마다 새로운 번호를 부여하고 그에 맞는 새로운 볼륨을 생성합니다. 기존 포드들이 가진 데이터에는 전혀 영향을 주지 않으니 안심하세요.

실습 마무리와 다음 단계

오늘 우리는 단순한 컨테이너 배포를 넘어, 데이터의 영속성과 네트워크 정체성을 보장하는 스테이트풀셋 실전 예제를 직접 수행해 보았습니다. 스테이트풀셋은 복잡해 보이지만, 원리만 이해하면 클러스터 위에서 데이터베이스를 운영하는 가장 강력한 도구가 됩니다.

✅ 핵심 요약

  • 데이터베이스 같은 상태 저장 앱에는 반드시 스테이트풀셋을 사용하세요.
  • Headless Service는 포드의 고유 DNS 주소를 위해 필수입니다.
  • `volumeClaimTemplates`를 통해 포드마다 개별적인 디스크를 할당하세요.
  • 포드는 순차적으로 생성되며, 이는 시스템 안정성을 위한 설계입니다.
  • 포드를 삭제해도 PVC는 남으므로 데이터 유실 걱정은 덜 수 있습니다.
  • 배포 후에는 반드시 DNS와 스토리지 영속성을 검증하세요.

이번 실습을 통해 기초를 다졌다면, 이제 더 높은 단계로 올라갈 준비가 되었습니다. 무작정 많은 리소스를 띄우기보다, 하나를 띄우더라도 왜 이 설정이 필요한지 고민하며 학습하는 것이 중요해요.

앞으로의 학습 로드맵

  • 오늘 할 일: 실습한 YAML 파일을 다시 작성해 보고, 포드 삭제 및 재생성 테스트를 3회 이상 반복하세요.
  • 이번 주 할 일: Helm을 사용하여 실제 오픈소스 데이터베이스(예: MariaDB)를 스테이트풀셋 기반으로 배포해 보세요.
  • 실행 직전 할 일: 클러스터의 스토리지 클래스(StorageClass) 설정이 어떻게 되어 있는지 깊게 파헤쳐 보세요.

실습 과정에서 막히는 부분이나 예상치 못한 오류 메시지를 만났다면, 주저하지 말고 아래 댓글로 질문을 남겨 주세요. 여러분의 시행착오가 더 좋은 콘텐츠를 만듭니다. 직접 적용해 보고 느낀 점도 환영해요!

더 깊이 있는 쿠버네티스 지식을 쌓고 싶다면, 쿠버네티스 스테이트풀셋 기본 개념 글클러스터 구축 입문 글을 함께 읽어보시는 것을 추천합니다.

댓글 남기기