7.4.2 스테이트풀셋의 특징과 기능
앞서 우리는 상태 유지 애플리케이션이 왜 특별한 관리를 필요로 하는지, 그리고 그들이 가지는 독특한 요구사항들(안정적인 고유 식별자, 안정적인 퍼시스턴트 스토리지, 순서 있는 배포 및 스케일링)에 대해 알아보았습니다. 일반적인 디플로이먼트 컨트롤러로는 이러한 까다로운 요구들을 모두 만족시키기 어렵습니다. 바로 이 지점에서 스테이트풀셋(StatefulSet)이 그 진가를 발휘합니다.
스테이트풀셋은 쿠버네티스에서 상태 유지 애플리케이션을 효과적으로 배포하고 관리하기 위해 특별히 설계된 워크로드 API 오브젝트입니다. 디플로이먼트가 주로 상태 없는 애플리케이션을 위한 것이라면, 스테이트풀셋은 각 파드가 고유한 정체성을 유지하고, 자신만의 데이터를 영구적으로 보존하며, 예측 가능한 방식으로 생성되고 관리되어야 하는 애플리케이션들을 위한 해결책입니다.
마치 디플로이먼트가 수많은 동일한 병사(파드)들을 지휘하는 장군이라면, 스테이트풀셋은 각기 다른 역할과 장비를 가진 정예 요원(파드)들을 개별적으로 관리하고 지휘하는 특수부대 지휘관과 같다고 비유할 수 있습니다. 이 지휘관은 각 요원의 고유 번호, 개인 장비, 그리고 작전 투입 및 철수 순서까지 세심하게 관리합니다.
이제 스테이트풀셋이 구체적으로 어떤 특징과 기능을 통해 상태 유지 애플리케이션의 요구사항을 충족시키는지 자세히 살펴보겠습니다.
7.4.2.1 안정적인 파드 이름 (e.g., web-0, web-1)
상태 유지 애플리케이션에서 각 파드는 고유하고 안정적인 네트워크 식별자를 가져야 한다고 말씀드렸습니다. 스테이트풀셋은 바로 이 요구사항을 충족시키기 위해 각 파드에게 예측 가능하고 안정적인 고유 이름을 부여합니다.
디플로이먼트에 의해 생성된 파드들은 보통 디플로이먼트 이름에 랜덤한 해시값과 또 다른 랜덤 문자열이 조합된 이름(예: my-app-deployment-7f9c6785d4-x2p4q)을 갖습니다. 이 이름은 파드가 재생성될 때마다 변경되므로, 특정 파드를 안정적으로 식별하기 어렵습니다.
하지만 스테이트풀셋은 다릅니다. 스테이트풀셋에 의해 생성되는 파드들은 다음과 같은 일관된 명명 규칙을 따릅니다.
<스테이트풀셋 이름>-<순서 색인 (Ordinal Index)>
여기서 <스테이트풀셋 이름>은 사용자가 정의한 스테이트풀셋의 이름이며, <순서 색인>은 0부터 시작하여 1씩 증가하는 정수입니다. 예를 들어, web이라는 이름의 스테이트풀셋이 3개의 복제본(replicas: 3)을 갖도록 설정되었다면, 생성되는 파드들의 이름은 다음과 같이 예측 가능하게 부여됩니다.
- web-0
- web-1
- web-2
이러한 파드 이름은 매우 안정적(sticky)입니다. 즉, web-0이라는 파드가 어떤 이유로 종료되고 스테이트풀셋에 의해 다시 생성되더라도, 새로 생성된 파드는 여전히 web-0이라는 이름을 갖게 됩니다. 심지어 파드가 다른 노드로 스케줄링되어도 이 이름은 유지됩니다. 이 안정성은 파드의 전체 생명주기 동안 지속됩니다.
이처럼 안정적이고 예측 가능한 파드 이름은 다음과 같은 중요한 이점을 제공합니다.
- 애플리케이션 내부에서의 파드 식별: 클러스터링된 데이터베이스나 분산 시스템에서 각 멤버는 다른 멤버를 이름으로 식별하고 통신할 수 있습니다. 예를 들어, web-1 파드는 항상 web-0 파드를 특정하여 데이터를 요청하거나 상태를 확인할 수 있습니다.
- 외부 시스템과의 연동: 외부 모니터링 시스템이나 관리 도구가 특정 파드를 지속적으로 추적하고 관리하기 용이합니다.
- 디버깅 및 로깅: 특정 파드에서 문제가 발생했을 때, 일관된 이름을 통해 로그를 추적하고 문제를 진단하기가 더 쉬워집니다.
이 안정적인 파드 이름은 뒤이어 설명할 안정적인 네트워크 ID(DNS 이름)와 안정적인 스토리지 할당의 기반이 됩니다. 마치 각 학생에게 고유한 학번을 부여하여 출석, 성적, 개인 사물함 등을 관리하는 것과 유사하다고 생각할 수 있습니다. 스테이트풀셋에게 이 순서 색인이 붙은 이름은 단순한 레이블이 아니라, 각 파드의 고유한 정체성을 나타내는 핵심 요소입니다.
7.4.2.2 안정적인 퍼시스턴트 볼륨 (파드별 PVC)
상태 유지 애플리케이션의 또 다른 핵심 요구사항은 각 파드가 자신만의 데이터를 영구적으로 보존할 수 있는 안정적인 퍼시스턴트 스토리지를 가져야 한다는 것입니다. 스테이트풀셋은 이 요구사항을 충족시키기 위해 각 파드에게 고유한 퍼시스턴트 볼륨 클레임(PersistentVolumeClaim, PVC)을 자동으로 생성하고 연결해주는 매우 강력한 기능을 제공합니다.
디플로이먼트의 경우, 모든 파드가 하나의 PVC를 공유하거나, 각 파드가 임시 스토리지를 사용하도록 설정할 수 있습니다. 하지만 이는 각 파드가 독립적인 데이터를 가져야 하는 상태 유지 애플리케이션에는 적합하지 않습니다.
스테이트풀셋은 spec 필드 내에 volumeClaimTemplates 라는 특별한 섹션을 정의할 수 있게 합니다. 이 템플릿은 스테이트풀셋에 의해 생성될 각 파드에 대해 PVC가 어떤 명세(예: 스토리지 크기, 접근 모드, 스토리지 클래스)를 가져야 하는지를 기술합니다.
스테이트풀셋이 web-0, web-1, web-2 와 같이 순서 색인이 붙은 파드를 생성할 때, volumeClaimTemplates에 정의된 내용을 바탕으로 각 파드에 대한 PVC도 자동으로 생성합니다. 이때 생성되는 PVC의 이름 또한 예측 가능한 패턴을 따릅니다.
<volumeClaimTemplate 이름>-<스테이트풀셋 이름>-<순서 색인>
예를 들어, 스테이트풀셋 web의 volumeClaimTemplates에 data라는 이름의 템플릿이 정의되어 있다면, 각 파드에 대해 다음과 같은 PVC가 생성됩니다.
- data-web-0 (이 PVC는 web-0 파드에 마운트됩니다.)
- data-web-1 (이 PVC는 web-1 파드에 마운트됩니다.)
- data-web-2 (이 PVC는 web-2 파드에 마운트됩니다.)
이렇게 생성된 각 PVC는 클러스터에 구성된 스토리지 클래스(StorageClass)에 따라 동적으로 퍼시스턴트 볼륨(PV)을 프로비저닝 받아 바인딩되거나, 미리 생성된 적절한 PV와 바인딩됩니다. 중요한 점은, 각 파드는 자신에게 할당된 고유한 PVC(그리고 그에 연결된 PV)를 독점적으로 사용한다는 것입니다.
이러한 파드별 고유 PVC는 다음과 같은 안정성을 보장합니다.
- 데이터 영속성: web-0 파드가 재시작되거나 다른 노드로 옮겨가더라도, 이 파드는 항상 이전에 사용했던 data-web-0 PVC에 다시 연결됩니다. 따라서 파드가 저장했던 데이터는 안전하게 유지됩니다.
- 데이터 격리: 각 파드는 자신만의 독립적인 스토리지 공간을 가지므로, 다른 파드의 데이터와 섞이거나 영향을 주지 않습니다. 이는 데이터베이스 샤드나 메시지 큐의 파티션과 같이 각 인스턴스가 독립적인 데이터를 관리해야 하는 경우에 필수적입니다.
- 스케일 다운 시 데이터 보존: 스테이트풀셋의 replicas 수를 줄여 파드를 삭제하더라도, 해당 파드와 연결되었던 PVC와 PV는 기본적으로 삭제되지 않고 남아있습니다. (PVC의 삭제 정책은 StatefulSetSpec.persistentVolumeClaimRetentionPolicy 필드를 통해 제어할 수 있습니다. 이전 버전에서는 PVC가 자동으로 삭제되지 않았으나, 최신 버전에서는 이 정책을 통해 스케일 다운 또는 스테이트풀셋 삭제 시 PVC를 자동으로 삭제할지 여부를 결정할 수 있게 되었습니다. 이 부분은 쿠버네티스 버전에 따라 동작이 다를 수 있으므로 주의가 필요합니다. 전통적으로는 PVC가 남아 데이터 복구 및 재활용의 기회를 제공했습니다.) 이는 실수로 파드를 삭제했거나, 나중에 동일한 순서 색인의 파드를 다시 생성할 때 기존 데이터를 그대로 사용할 수 있게 해주는 중요한 안전장치입니다.
이처럼 volumeClaimTemplates를 통한 파드별 안정적인 PVC 제공 기능은 스테이트풀셋이 상태 유지 애플리케이션의 데이터 관리 요구사항을 충족시키는 핵심 메커니즘입니다. 마치 각 정예 요원에게 개인 식별 번호가 새겨진 전용 장비 보관함을 제공하는 것과 같습니다.
7.4.2.3 Headless Service를 통한 파드 직접 접근
스테이트풀셋의 안정적인 파드 이름과 안정적인 스토리지는 매우 중요하지만, 이 파드들을 네트워크상에서 안정적으로 발견하고 직접 통신할 수 있는 방법이 없다면 그 유용성이 크게 떨어질 것입니다. 일반적인 쿠버네티스 서비스(Service)는 여러 파드들 앞에서 단일 가상 IP(ClusterIP)를 제공하고 요청을 라운드 로빈 방식으로 분배하는 로드 밸런서 역할을 합니다. 이는 상태 없는 애플리케이션에는 적합하지만, 특정 파드(예: 데이터베이스의 주 노드 또는 특정 샤드)에 직접 접근해야 하는 상태 유지 애플리케이션에는 맞지 않습니다.
이러한 문제를 해결하기 위해 스테이트풀셋은 종종 헤드리스 서비스(Headless Service)와 함께 사용됩니다. 헤드리스 서비스는 일반적인 서비스와 달리 ClusterIP를 가지지 않는 특별한 종류의 서비스입니다. spec.clusterIP 필드를 None으로 설정하여 생성합니다.
스테이트풀셋의 명세(spec.serviceName)에 이 헤드리스 서비스의 이름을 지정하면, 쿠버네티스는 다음과 같은 마법을 부립니다.
- 개별 파드에 대한 DNS 레코드 생성: 헤드리스 서비스는 자신의 셀렉터와 일치하는 각 파드에 대해 고유하고 안정적인 DNS A 레코드를 쿠버네티스 내부 DNS 시스템에 자동으로 생성합니다. 이 DNS 레코드의 형식은 다음과 같습니다.<파드 이름>.<헤드리스 서비스 이름>.<네임스페이스>.svc.<클러스터 도메인>
예를 들어, my-namespace 네임스페이스에 nginx-svc라는 이름의 헤드리스 서비스가 있고, 이 서비스를 governing service로 사용하는 web 스테이트풀셋이 web-0, web-1 파드를 생성했다면, 다음과 같은 DNS 이름으로 각 파드에 직접 접근할 수 있게 됩니다.
- web-0.nginx-svc.my-namespace.svc.cluster.local (이 DNS 이름은 web-0 파드의 현재 IP 주소로 해석됩니다.)
- web-1.nginx-svc.my-namespace.svc.cluster.local (이 DNS 이름은 web-1 파드의 현재 IP 주소로 해석됩니다.)
이 DNS 이름은 파드의 IP 주소가 변경되더라도 (예: 파드 재시작 시) 항상 해당 파드의 최신 IP 주소를 가리키도록 자동으로 업데이트됩니다. 따라서 클라이언트나 다른 파드들은 이 안정적인 DNS 이름을 사용하여 특정 스테이트풀셋 파드에 직접 연결할 수 있습니다.
- 서비스 자체에 대한 DNS 레코드 (SRV 레코드 활용 가능성): 헤드리스 서비스 자체의 DNS 이름(예: nginx-svc.my-namespace.svc.cluster.local)을 조회하면, 해당 서비스가 관리하는 모든 준비된(Ready) 파드들의 IP 주소 목록을 반환합니다. 이는 클라이언트가 직접 특정 파드를 선택하거나, 애플리케이션 레벨에서 자체적인 라우팅 또는 서비스 디스커버리 로직을 구현할 때 유용합니다. 또한, 헤드리스 서비스의 포트에 이름을 지정하면 SRV 레코드도 생성되어, 포트 번호까지 포함한 서비스 디스커버리가 가능해집니다.
이처럼 헤드리스 서비스를 사용하면 다음과 같은 장점이 있습니다.
- 안정적인 네트워크 식별자 제공: 각 파드는 <파드이름>.<서비스이름> 형태의 안정적인 DNS 이름을 갖게 되어, IP 주소가 변경되어도 일관된 방식으로 접근할 수 있습니다. 이는 “7.4.1.1 안정적인 고유 식별자 필요”에서 언급된 요구사항을 완벽하게 충족시킵니다.
- 직접 파드 접근: 로드 밸런서를 거치지 않고 특정 파드 인스턴스에 직접 네트워크 요청을 보낼 수 있습니다. 이는 데이터베이스의 주-복제 관계, 리더-팔로워 패턴, 또는 샤드 기반 아키텍처에서 필수적입니다.
- 애플리케이션 수준의 클러스터링 지원: 상태 유지 애플리케이션은 종종 자체적인 클러스터 멤버십 관리 및 서비스 디스커버리 메커니즘을 가집니다. 헤드리스 서비스는 이러한 애플리케이션들이 쿠버네티스 환경과 잘 통합되어 서로를 발견하고 통신할 수 있도록 지원합니다.
스테이트풀셋 명세에서 serviceName 필드에 헤드리스 서비스 이름을 지정하는 것은 매우 일반적인 패턴이며, 이를 통해 스테이트풀셋의 파드들은 진정한 의미의 ‘상태를 가진’ 개별적인 네트워크 엔드포인트로 동작할 수 있게 됩니다. 마치 각 정예 요원에게 고유한 호출 부호와 통신 채널을 부여하여, 지휘 본부나 다른 요원들이 특정 요원을 직접 호출하고 임무를 부여할 수 있도록 하는 것과 같습니다.
지금까지 살펴본 안정적인 파드 이름, 안정적인 파드별 퍼시스턴트 볼륨, 그리고 헤드리스 서비스를 통한 직접 파드 접근 기능은 스테이트풀셋이 상태 유지 애플리케이션을 위한 강력한 컨트롤러로 자리매김하게 하는 핵심 요소들입니다. 이러한 기능들이 유기적으로 결합되어, 복잡한 상태 관리 요구사항을 가진 애플리케이션도 쿠버네티스 위에서 안정적이고 효율적으로 운영될 수 있도록 지원합니다.