study/devops

쿠버네티스 (Kubernetes, k8s) 스테이트풀셋

FYE 2023. 2. 15. 21:07

 

Stateless 파드

파드는 일시적이며, 언제나 삭제될 수 있음을 감안해야 한다. 파드 그 자체는 Stateless하다. 파드의 교체와 배치를 담당하는 것이 디플로이먼트입니다. 디플로이먼트는 레플리카셋을 통해 파드를 scale out하며, 이 때 만들어지는 파드들은 상호 대체 가능하다.

 

 

 

 

만약 파드가 사라져도, 데이터를 남기고 싶다면

파드 그 자체에 데이터를 남겨야만 하는 Stateful 애플리케이션으로는 MySQL, mongoDB, redis와 같은 데이터베이스가 있을 수 있다.

데이터베이스 애플리케이션이 담긴 파드가 사라질 때, 데이터가 함께 사라지도록 둬선 안된다.

 

그래서 쿠버네티스에도 영속적인 데이터(프로그램의 실행이 종료되어도 사라지지 않는 데이터)를 저장하기 위해 볼륨(Volume)을 연결할 수 있다. 여타 클라우드 서비스에서 볼륨을 따로 분리해 놓는 것과 같다.

 

파드에 볼륨을 연결하면, 데이터를 영속적으로 저장하는 것이 가능하다.

 


퍼시스턴트 볼륨 서브시스템은 사용자 및 관리자에게 스토리지 사용 방법에서부터 스토리지가 제공되는 방법에 대한 세부 사항을 추상화하는 API를 제공한다. 이를 위해 퍼시스턴스볼륨 및 퍼시스턴스볼륨클레임이라는 두 가지 새로운 API 리소스를 소개한다.

퍼시스턴스볼륨(PV)은 관리자가 프로비저닝하거나 스토리지 클래스를 사용하여 동적으로 프로비저닝한 클러스터의 스토리지이다.
노드가 클러스터 리소스인 것처럼 PV는 클러스터 리소스이다. PV는 Volumes와 같은 볼륨 플러그인이지만 PV를 사용하는 개별 파드와는 별개의 라이프사이클을 가진다. API 오브젝트는 NFS, iSCSI 또는 클라우드 공급자별 스토리지 시스템 등 스토리지 구현에 대한 세부 정보를 담아낸다.

 

 

Q. 볼륨과 퍼시스턴스 볼륨은 어떤 차이가 있나요? AWS EC2에도 비슷한 개념이 있습니다. EBS와 인스턴스 스토어 볼륨의 차이점과 연결지어서 설명해주세요.

볼륨은 컨테이너에서 사용하는 파일 시스템을 캡슐화하여 컨테이너와 별개로 관리되지만, 컨테이너가 삭제되면 함께 삭제된다.
이와달리 퍼시스턴트 볼륨은 컨테이너와 별개로 생성되고 관리되며 컨테이너가 삭제돼도 데이터가 지속된다.
퍼시스턴트 볼륨은 여러 컨테이너에서 공유할 수 있으며 볼륨과 달리 수동으로 삭제해야 한다.

AWS EC2에서도 비슷한 개념이 있는데 EBS(Elastic Block Store)는 EC2 인스턴스에 연결할 수 있는 지속적인 블록 스토리지이다. EBS 볼륨은 EC2 인스턴스에서 사용하는 파일 시스템을 캡슐화하여 인스턴스와 별개로 관리되며, EC2 인스턴스가 삭제돼도 데이터가 지속된다. 이와달리 인스턴스 스토어 볼륨은 EC2 인스턴스 내부에 있는 물리적인 디스크로, EC2 인스턴스와 함께 생성되며 인스턴스가 삭제되면 함께 삭제된다.

따라서 쿠버네티스에서 퍼시스턴스 볼륨과 AWS EC2에서 EBS는 비슷한 개념으로 볼 수 있다. 둘 다 컨테이너 또는 인스턴스가 삭제되더라도 데이터를 유지하며 여러 컨테이너 또는 인스턴스에서 공유할 수 있습니다. 인스턴스 스토어 볼륨은 EC2 인스턴스와 함께 생성되지만 쿠버네티스에서는 퍼시스턴스 볼륨을 따로 생성하여 사용합니다.

 

 

 


Stateful한 애플리케이션을 관리하려면

파드 명세에 퍼시스턴스 볼륨을 직접 정의해서 연결하는 것은 일반적으로 권장되지 않는 방법이다. 이 방법은 파드가 특정 노드에 스케줄링될 때 해당 노드에 있는 퍼시스턴스 볼륨과만 연결되므로, 파드가 다른 노드로 이동할 때 문제가 발생할 수 있다. 예를 들어, 파드가 노드 간 이동하면 퍼시스턴스 볼륨이 더 이상 해당 노드에 없거나 액세스할 수 없는 상태가 될 수 있습니다.

 

이러한 이유로 일반적으로는 파드와 퍼시스턴스 볼륨을 연결하는 대신, 스토리지 클래스를 사용하고 PersistentVolumeClaun(PVC)을 생성하는 것이 권장됩니다. PVC를 사용하면 파드는 볼륨에 대한 액세스를 요청하면 쿠버네티스가 해당 볼륨과 PVC를 연결하고, 이러한 PVC를 사용하여 파드가 언제든지 적절한 노드로 스케줄링될 때 해당 볼륨에 연결할 수 있다.

 

또한 스토리지 클래스는 스토리지 관리를 단순화하고, 스토리지 클래스가 다양한 백엔드를 지원할 수 있으므로 보다 큰 유연성을 제공한다.

따라서 PVC를 사용하여 스토리지 볼륨을 연결하는 것이 보다 유연하고 안전한 방법이다.

 

 

 

 

*PVC(Persistent Volume Claim)

쿠버네티스에서 사용되는 스토리지 볼륨을 동적으로 할당하고 관리하는 추상화된 리소스이다.
PVC를 사용하면 파드에서 필요로 하는 스토리지 볼륨을 요청할 수 있다.
PVC를 생성하면 쿠버네티스는 해당 PVC와 일치하는 볼륨을 동적으로 할당하거나 이미 존재하는볼륨을 찾아서 할당한다.
이렇게 할당된 볼륨은 해당 PVC에 바인딩되어 파드에서 사용할 수 있게 된다.

PVC는 스토리지 클래스와 함께 사용되며 스토리지 클래스는 어떤 종류의 스토리지를 사용할지, 어떤 프로토콜을 사용할지 등을 정한다. PVC는 이러한 스토리지 클래스를 참조하여 요청한 스토리지의 종류를 지정한다.

 

 

 

의존도를 줄이기 위해, 퍼시스턴스 볼륨클레임 (PVC)을 이용하여 PV와 연결한다. PVC는 파드가 볼륨의 세부 사항을 몰라도 볼륨을 사용할 수 있게 도와준다.

  • PV는 실제로 데이터가 저장되는 공간이다.
  • PVC는 PV를 선택, 연결해주는 요청 그 자체이다.

 

 

Q. PVC는 어떻게 작동되나요?
쿠버네티스에서 동적 스토리지 프로비저닝을 구현하는 데 사용된다. PVC를 상생허만 쿠버네티스는 PVC와 일치하는 PV(PersistentVolume)을 찾거나 새로 할당하여 요청한 스토리지 볼륨을 제공한다.

[PVC 생성]
사용자가 PVC를 생성하여 요청한 스토리지 클래스, 스토리지 요청량등을 지정한다.

[PV 할당]
쿠베네티스는 PVC에 대한 PV를 찾거나 새로 생성하여 해당 PVC에 바인딩한다. 이때 PV는 PVC의 요청 사항에 따라 용량, 엑세스 모드 등이 일치해야하며 만약 새로운 PV가 생성된다면, 스토리지 클래스에 지정된 프로비저너를 사용하여 동적으로 생성된다.

[파드에 마운트]
PVC는 이제 파드에서 마운트 될 수 있다. 파드는 PVC를 볼륨으로 사용하고, 쿠버네티스는 해당 볼륨을 PV에 연결합니다.

[PV 재사용]
PVC가 삭제되면 해당 PV는 다시 사용될 수 있다. 이때 쿠버네티스는 PV에서 데이터를 삭제하여 새로운 PVC에서 사용할 수 있도록 준비한다.

 

 

*프로비저닝

사용자의 요구에 맞게 시스템 자원을 할당, 배치, 배포해 두었다가 필요 시 시스템을 즉시 사용할 수 있는 상태로 두는 것을 말한다.

 


Stateful한 애플리케이션이 수평 확장한다면

파드를 정의할 때 PVC를 통해 볼륨에 연결할 수 있다. 그런데 그냥 이러한 파드를 디플로이먼트로 배포해도 PVC를 통해 연결되는 봄률은 하나이기 때문에 결국 같은 스토리지를 사용하는 모양이 나온다.

 

 

 

파드마다 별도의 데이터를 저장할 수 있게 만드려면, 수평확장되는 파드에 서로 다른 PV가 연결돼야한다. 파드가 PV를 동적으로 요청해서 그때그때 볼륨이 생성되게 하면 어떨까? 스토리지 클래스(StorageClass)리소스는 사용자가 요청할 때, 자동으로 PV를 프로비저닝 할 수 있게 돕는다.

 

 

 

 

 


스테이트풀셋

스테이트풀셋은 애플리케이션 구성(파드)을 복제하더라도, 스토리지 클래스를 이용해 파드가 필요로 하는 볼륨을 자동으로 피로비저닝하여 연결한다. 따라서 첫번째 파드를 primary(master), 두번째 파드를 secondary 복제본처럼 구성하는 것도 가능하다.

 

디플로이먼트와 스테이트풀셋 둘 다 동일한 컨테이너 스펙을 기반으로 둔 파드들을 관리한다는 점에서는 같지만 가장 결정적인 차이는 순서와 고유성이다.

 

스테이트풀셋 파드는 순서와 고유성을 보장한다.

가죽과 반려동물의 비유를 떠올리면 이해하기 쉽다. 스페이트풀셋이 생성한 파드는 상호 대체할 수 없는 파드이다.

 

 


 

 

스테이트 풀셋을 사용할 때의 주의사항

  • 파드에 지정된 스토리지는 관리자에 의해 퍼시스턴트 볼륨 프로비저너를 기반으로 하는 storage class를 요청해서 프로비전하거나 사전에 피로비전 돼야한다.
  • 헤드리스 서비스가 필요하다
  • 스테이트풀셋은 파드를 하나씩 순차적으로 배포하기때문에 이전의 파드가 정상적으로 작동하는 경우에만 다음 파드가 배포된다. 파드의 상태가 불안정한 경우, 새로운 파드가 생성되지 않을 수 있다.
  • 스테이트풀셋은 파드를 생성할 때 PVC를 사용한다. 스토리지의 안정성을 보장하기 위해서는 PVC의 안정성을 유지해야한다. PVC가 삭제되거나 더 이상 사용할 수 없는 경우에는 파드를 생성할 수 없다
  • 스테이트풀셋은 파드를 노드에 할당하기때문에 노드 장애가 발생할 경우 파드를 다른 노드로 이동시켜한다. 이를 위해서는 노드 장애에 대한 대응 정책을 수립해야 하며, 필요에 따라 자동으로 파드를 이동시키는 기능을 사용할 수 있다.
  • 스테이트풀셋을 사용하여 배포된 서비스를 업그레이드할 때는 업그레이드 전략을 정의해야 한다. 업그레이드 전략을 정의하지 않으면 파드가 중복 생성되거나 삭제되는 등의 문제가 발생할 수 있다. 

 

 

Q. 네트워크 트래픽에 따라 요청이 랜덤하게 분산되는 일반적인 서비스에 비해, 헤드리스 서비스는 특정 스테이트풀셋에게 트래픽을 보냅니다. 왜 그렇게 해야 하나요?

 StatefulSet은 각각의 Pod에 고유한 식별자를 부여하고, Pod을 생성할 때 순서를 지정할 수 있다.
이러한 특성으로 인해 StateulSet으로 관리되는 Pod들은 서로 다른 역할을 수행하게 되는데, 이때 각각의 Pod은 서로 다른 데이터를 저장하고 처리하는 등의 역할을 수행하게 된다.

 헤드리스 서비스는 이러한 스테이트풀셋으로 관리되는 파드들에 직접적으로 접근하기 위한 서비스 유형이다.
이 서비스는 일반적인 서비스와 다르게 Cluster IP를 할당하지 않으며, 대신 각각의 파드에 고유한 DNS 이름을 부여한다.
이렇게 하면 클러스터 내에서 각각의 파드를 고유하게 식별할 수 있고, 데이터베이스나 메시징 시스템과 같은 스테이트풀셋의 서비스에서 이러한 고유성이 매우 중요하다.

 따라서 헤드리스 서비스를 사용하면 각 파드에 직접적으로 접근할 수 있고, 이를 통해 데이터베이스 같은 서비스에서 발생하는 데이터의 일관성과 무결성을 보장할 수 있다. 그리고 스테이트풀셋의 파드들은 자신이 처리해야 할 특정 데이터를 가지고 있고, 해당 데이터를 처리하는데 필요한 파드에 대해 트레픽을 보내야 하기 때문에 헤드리스 서비스를 사용하여 트래픽을 분산하는 것이 유리하다.
 

 

 

참고 레퍼런스

https://kubernetes.io/ko/docs/concepts/storage/volumes/

https://kubernetes.io/ko/docs/concepts/storage/dynamic-provisioning/

https://github.com/kubernetes/examples/blob/master/staging/persistent-volume-provisioning/README.md