쿠버네티스 인 액션 10장 ( Statefulset )

2023. 9. 9. 19:24Kubernetes

스테이트풀셋이란? 

 

stateful : 상태유지

 

- pod 가 항상 일정  

- stateful set 명 + 0~n 까지 이름이 부여됨

 

 

10.1.1 개별 스토리지를 갖는 레플리카 여러 개 실행하기 

레플리카셋은 항상 같은 pvc 와 pv를 사용함.

여러개의 파드 레플리카를 실행 하면서 개별 스토리지 볼륨을 사용하는 파드를 가지려면 어떻게 해야할까?

레플리카셋은 동일한 파드의 복제본을 생성한다. 

 

10.1.2 각 파드에 안정적인 아이덴티티 제공하기 

- 레플리카셋이 파드 교체시 새 파드가 갖는 스토리지 볼륨의 데이터는 종료된 이전의 파드 것일지라도 완전히 새로운 호스트 이름과 IP 를 갖는다. 

- 특정 애플리케이션은 관리자가 다른 모든 클러스터 멤버의 리스트와 멤버들의 IP 주소를 각 멤버의 설정 파일에 기재해야한다. (사례 존재?)

 

각 인스턴스 별 전용 서비스 사용하기 

해결방법 :  각 개별 멤버에게 전용 서비스를 생성해 클러스터 멤버에 안정적인 네트워크 주소를 제공하는 것이다. 서비스 IP 는 안정적이므로 설정에서 각 멤버를 서비스 IP 를 통해 가리킬 수있다. 

- 그러나, 이는 어리석은 해결방법일 뿐아니라 모든 문제를 해결하지도 못한다. 

- 개별 파드는 자신이 어떤 서비스를 통해 노출되는지 알 수 없으므로 그 IP 를 사용해 다른 파드에 자신을 등록 할 수 없다. 

 

10.2 스테이트 풀셋 이해하기 

- 이런 유형의 파드를 실행하기 위해 레플리카 셋을 사용하는 대신 스테이트풀셋 리소스를 사용한다. 

- 스테이트 풀셋은 애플리케이션의 인스턴스가 각각 안정적인 이름 상태를 가지며 개별적으로 취급돼야 하는 애플리케이션에 알맞게 만들어졌다. 

 

10.2.1 스테이트 풀셋과 레플리카셋 비교하기 

- 레플리카셋으로 생성된 파드와 달리 스테이트 풀셋으로 생성된 파드는 다른 레플리카와 완전히 같지 않다. 

- 각 파드는 다른 피어와 구별되는 자체의 볼륨 세트(스토리지) 를 가진다. 

10.2.2 안정적인 네트워크 아이덴티티 제공하기 

거버닝 서비스 소개 

http://svc명.namespace명.default.svc.cluster.local 

- stateless  파드는 stateless 파드와 동일하다. 한 개가 필요하면 그중 어느것이라도 선택하면 된다.

하지만, stateful 파드는 각각 서로 다르므로 ( 다른 상태를 가지므로) 그룹의 특정 파드에서 동작하기를 원할 것이다. 

이런 이유로 스테이트 풀셋은 거버닝 헤드리스 서비스를 생성해서 각 파드에게 실제 네트워크 아이덴티티를 제공해야한다. 

- 예를들어 default 라는 네임스페이스에 속하는 foo 라는 이름의 거버닝 서비스가 있고 파드의 이름이 A-0 이라면,

a-o.foo.default.svc.cluster.local 이라는 FQDN(Fully Qualified Domain Name) 을 통해 접근할 수있다. 

 

이러한 이유로 스테이트 풀셋은 인스턴스 하나라도 비정상인경우 스케일다운 작업을 허용하지 않는다. 인스턴스 하나가 정상적으로 동작하지 않는 시점에 인스턴스 하나를 스케일 다운 하는 경우 , 결과적으로 동시에 두개의 클러스터 멤버를 잃게 될것이다. 

 

볼륨 클레임 템플릿과 파드 템플릿을 같이 구성 

스테이트 풀셋이 파드를 생성하는 것과 같은 방식으로 퍼시스턴트볼륨 클레임(PVC) 또한 생성해야한다.

이런 이유로 스테이트 풀셋은 각 파드와 함께하는 PVC를 복제하는 하나 이상의 볼륨 클레임 템플릿을 가질 수있다.

 

퍼시스턴트 볼륨 클레임의 생성과 삭제의 이해 

퍼시스턴트 볼륨을 해제 하려면 퍼시스턴트 볼륨 클레임을 수동으로 삭제한다.

자동으로 삭제되면 바인딩 되면 퍼시스턴트 볼륨은 재활용되거나 삭제돼 콘텐츠가 손실 되기 때문에 자동으로 삭제되지 않기 때문이다. 

  

10.3.2 스테이트 풀셋을 통한 애플리케이션 배포하기 

- 데이터 파일을 저장하기 위한 퍼시스턴트 볼륨 (클러스터가 퍼시스턴트 볼륨의 동적 프로비저닝을 지원하지 않는다면 직접 생성해야 한다.)

- 스테이트 풀셋에 필요한 거버닝 서비스

- 스테이트 풀셋 자체 

 

거버닝 서비스 생성하기 

스테이트 풀셋을 배포하기전에 먼저 헤드리스 서비스를 생성해야한다. 이는 스테이트 풀 파드에 네트워크 아이덴티티를 제공하기 위해 사용된다.

ClusterIP 를 None 으로 설정하면 헤드리스 서비스가 된다.

 

스테이트 풀셋 매니페스트 생성하기 

 

- 레플리카셋은 동시에 pod 가 생성되는데, 스테이트풀셋은 순서대로 기동됨

- replicas를 줄여서(scale down) , 삭제 될때는 숫자가 큰 순서대로 삭제됨. 

 

10.3.3 파드 가지고 놀기 

 

API 서버를 통해 파드와 통신하기 

프록시 실행

kubectl proxy
Starting to serve on 127.0.0.1:8001

 

kubia-0 파드에 요청 보내기 

curl localhost:8001/api/v1/namespaces/default/pods/kubia-0/proxy/
You've hit kubia-0
Data stored on this pod: No data posted yet

 

10.4 스테이트풀셋의 피어 디스커버리 

피어디스커버리란?

: 클러스터의 다른멤버를 찾는 기능 

- 스테이트풀셋의 각 멤버는 모든 다른 멤버를 쉽게 찾을 수있어야 한다. 

- 물론, API 서버와 통신해 찾을 수 있지만 k8s 목표 중하나는 애플리케이션을 완전히 독립적으로 유지하며 기능을 노출하는 것이다. 

그러므로,  어플리케이션이 쿠버네티스 API 와 대화하는 것은 바람직하지 않다.

 

SRV 레코드 소개 

SRV 레코드는 특정 서비스를 제공하는 서버의 호스트 이름과 포트를 가리키는데 사용된다. 

쿠버네티스는 헤드리스 서비스를 뒷받침하는 파드의 호스트 이름을 가리키도록 SRV 레코드를 생성한다. 

새 임시 파드 내부에서 DNS lookup 도구인 dig 를 실행해 스테이트풀 파드의 SRV 레코드를 조회할 수있다.

 

kubectl run -it srvlookup --image=tutum/dnsutils --rm --restart=Never -- dig SRV kubia.default.svc.cluster.local

 

이 명령은 srvlookup 이라 부르는 일회용 파드 (--restart=Never)를 tutum/dnsutils 이미지로 실행하고 콘솔에 연결되며 (--it) 종료되자마자 바로 삭제된다.(--rm). 

그후 다음 명령을 수행한다. 

 

dig SRV kubia.default.svc.cluster.local

10.4.2 스테이트 풀셋 업데이트 

 

스테이트 풀셋 업데이트 방법 : edit 

kubectl edit statefulset kubia

 

10.5 스테이트 풀 셋이 노드 실패를 처리하는 과정 이해하기

 

노드가 실패한 경우 동일한 아이덴티티와 스토리지를 가진 두개의 파드가 절대 실행되지 않는 것을 보장하므로, 스테이트풀셋은 파드가 더이상 실행되지 않는다는 것을 확신할때까지 파드를 생성할 수없으며, 생성 해서도 안된다.

 

오직, 관리자가 알려줘야 한다. 이를 위해 관리자는 파드를 삭제하거나 전체노드를 삭제해야한다.

 

노드가 네트워크 연결이 끊겼을때 control plane이 노드로부터 더 이상 상태 업데이트를 받을 수없으므로, 노드에 있는 모든 파드 상태는 Unknown 이다. 

UNKNOWN 상태인 파드에 무슨일이 일어나는지 이해하기 

 

1. 노드랑 네트워크 연결이 끊김.

2. Unknown 이 몇분간 지속시..

controlplane이 저 노드 안에있는 pod 죽여야 해! container 종료됐니?

----------------------- 

3. kubelet 이 컨테이너가 종료됐어요

4. controlplane: kubelet아 pod 죽이셈(pod에 deletion 표시)

4. kubelet 이 파드 죽였어요 라고 controlplane 에 보고 

5. control plane 이 ㅇㅋ. pod 죽었대 ( pod상태 업데이트 ) 

kubectl describe po kubia-0

파드의 종료 이유에 NodeLost로 표시되면서 terminating 으로 표시된다.

여기에 표시된건 control plane 관점이다. 

 

kubelet 이 파드가 deletion(pod 죽여!)으로 표시된것을 확인하면 파드 종료를 시작한다. 

하지만, 이 경우엔 Kubelet 이 더이상 마스터에 연결할수 없으므로, (네트워크 연결이 끊었으므로)

파드는 계속 실행중임을 의미한다. 

 

10.5.2 수동으로 파드 삭제하기 

kubectl delete po kubia-0

삭제하고 나서 봐도 이상하다. 동일한 파드가 남아있다.

파드는 삭제를 하기 전에 이미 deletion 표시가 돼 있었다. 그 이유는 control plane이 이미 파드를 삭제처리했기 때문이다. (노드를 제거하기 위해서) 

상태가 Terminating 이니 해당 노드의 Kubelet 이 API 서버에 파드의 컨테이너가 종료됐음을 통지하자마자 제거될것이다. 노드의 네트워크가 다운됐으므로 이 작업은 절대로 발생하지 않는다. 

 

 

파드 강제 삭제하기

해결법은 Kublet 이 파드가 더이상 실행중이지 않음을 확인해주는것을 기다리지 않고,

API 서버에게 파드를 삭제하도록 알리는 것이다.

kubectl delete po kubia-0 force --grace-period 0
pod "kubia-0" deleted