'15단계로 배우는 도커와 쿠버네티스' 기반으로 내용 정리하였습니다.
쿠버네티스의 스테이트풀셋(StatefulSet)은 퍼시스턴트 볼륨과 파드를 함께 조합하여 제어하기에 적합한 컨트롤러다.
일반적으로 스테이트풀(stateful)이라고 하면 내부에 상태를 가져서 상태에 따라 처리내용이 달라지는 것을 의미한다.
예를 들면 자판기의 동전 투입 및 주문 대기 상태에 따라 처리되는 기능이 다른데 이를 스테이트풀한 프로그램이라고 할 수 있다.
컨테이너에서 실행되는 고도의 프로그램은 더욱 많은 상태를 관리한다.
예를 들어, 쇼핑몰 사이트의 경우 상품 재고 상태나 고객별 주문 상태, 상품 배달 상태등의 상태를 관리하며
이를 데이터베이스를 사용한다.
그러나 컨테이너가 파드는 태생적으로 데이터를 보관하는 것이 어렵기 때문에 파드와 퍼시스턴트 볼륨을 조합하여 실행해야 한다. 이러한 요구 상태를 쿠버네티스에서는 스테이트풀셋이라는 컨트롤러를 제공한다.
이 컨트롤러는 파드와 퍼시스턴트 볼륨의 대응 관계를 엄격하게 관리하며, 퍼시스턴트 볼륨의 데이터 보관을 우선시하여 동작한다.
디플로이먼트와의 차이
(gvol-0 / gvol-1 / gvol-2 로 표시가 되어야 하는데 잘못 표시되었음!)
(1) 파드의 이름과 퍼시스턴트 볼륨의 이름
스테이트풀셋도 지정한 레플리카 수에 해당하는 파드를 파드 템플릿에 기술한 내용에 따라 기동한다.
스테이트풀셋에 의해 만들어지는 파드의 이름은 스테이트풀셋의 이름 뒤에 순서대로 번호가 부여된다.
디플로이먼트의 경우는 해시가 붙었다.
스테이트풀셋에서는 파드와 퍼시스턴트 볼륨을 하나의 단위로 취급하여 동일한 번호가 이름에 부여된다.
(2) 서비스와의 연결 및 이름 해결
스테이트풀셋 관리하의 파드에 요청을 전송하기 위한 서비스는 대표 IP를 가지지 않는 ClusterIP 의 헤드리스 모드를 사용해야 한다. 클라이언트가 서비스의 이름으로 IP 주소를 해결하면 스테이트풀셋 관리하의 파드의 IP주소가 랜덤하게 반환된다.
스테이트풀셋의 매니페스트에 spec.serviceName에 연동할 서비스 이름을 설정하면 각 파드의 이름으로 파드의 IP주소를 얻을 수 있다. 데이터베이스를 샤딩해서 사용할 때처럼 각각의 서버를 직접 지정해서 접속해야 할 때 유용하다.
(3) 파드 분실 시 동작
스테이트풀셋 관리하의 파드가 노드 장애 등으로 없어진 경우에는 동일한 이름으로 새롭게 파드가 기동된다.
그리고 기존 파드가 사용했던 퍼시스턴트 볼륨을 이어서 사용한다.
여기서 주의할 점은 파드의 이름이 같아도 파드의 IP 주소를 변했다는 점이다.
그래서 스테이트풀셋 관리하의 파드에 접속하는 경우, 반드시 내부 DNS를 사용해서 이름을 해결해야 한다.
replica set 은 pod 가 새로운 이름으로 기동되지만 stateful set 은 동일한 이름으로 기동된다.
(4) 노드 정지 시의 동작
스테이트풀셋은 데이터를 분실하지 않도록 설계되었다. 하지만 하드웨어 장애나 네트워크 장애로 특정 노드가 마스터와의 연결이 끊어졌을 때, 스테이트풀셋은 새로운 파드를 기동하지 않는다.
가령, 노드의 상태를 관리하는 kubelect과 마스터와의 통신이 일시적으로 끊겼지만 파드는 계속해서 돌아가고 있는 경우를 생각해보자. 이 상황에서 마스터가 대체 파드를 가동하여 퍼시스턴트 볼륨을 마운트하게 되면 오히려 데이터가 파손될 수 있다.
파드가 퍼시스턴트 볼륨을 마운트할 때는 엑세스 모드로 여러 노드에서 읽고 쓰기가 가능한 ReadWriteMany(RWX)와 하나의 노드에서만 읽고 쓸 수 있는 ReadWriteOnce(RWO)를 사용할 수 있다.
이들은 외부 스토리지 시스템에 종속된 파라미터라 NFS와 같이 공유 가능한 퍼시스턴트 볼륨에 RWO를 설정한다고 해도 새로운 하드가 가동되는 것을 억제할 수 는 없다.
다음 중 한 가지 경우에 해당할 때만 스테이트풀셋이 분실된 파드를 다른 노드에서 다시 가동한다.
이러한 상황에서만 파드를 대체하는 이유는?
스테이트풀셋이 노드의 장애를 검지했을 때 대체 노드에 파드를 기동하는 것은 위험하다.
만약에 장애라고 판단한 노드에서 파드가 계속해서 실행 중이라면 동일한 파드가 중복해서 기동하게 되어,
퍼시스턴트 볼륨상의 데이터가 파손될 수 있다.
이러한 위험을 피하기 위해서?
장애 노드를 K8s 클러스터에서 제외한다.
그러면 그 노드에서 동작 중인 파드 전부가 종료되어 안전하게 대체 파드로 교체할 수 있다. 혹은 노드를 재기동해서 통신이 회복되면 파드에 대한 제어도 회복된다.
그런데 스테이트풀셋의 역할은 파드를 컨트롤하는 것으로, 노드를 재기동하거나 제외하는 것은 책임 범위 밖이다.
그래서 외부에서의 동작이 필요하다. 장애가 발생한 노드를 K8s 클러스터에서 제거하는 명령어를 실행하여 다른 노드에 파드가 개시되게 하는 것이다. 그리고 장애 노드를 재기동하여 다시 노드가 정상적인 상태가 되어 파드를 중복으로 실행하는 상황을 피할 수 있다.
(5) 파드 순번 제어
스테이트풀셋의 파드 이름에 붙는 번호는 파드의 기동과 정지뿐만 아니라, 롤링 업데이트의 순서에도 사용된다.
한편 디플로이먼트에서의 파드명은 디플로이먼트의 이름 뒤에 해시 문자열이 붙으며 파드의 기동 순서는 랜덤하게 적용된다.
레플리카 숫자에 도달할 때까지 파드와 퍼시스턴트 볼륨을 짝을 지어서 차례대로 기동한다.
정지할 때는 파드의 이름 뒤에 붙은 번호가 큰 순서로 정지한다.
레플리카 값을 늘리면 파드 이름 뒤에 붙는 순서가 늘어나면서 파드가 기동된다.
반대로 레플리카 값을 줄이면 파드 이름 뒤에 붙는 숫자가 큰 것 부터 삭제된다.
롤링 업데이트 할 때도 파드의 이름에 붙는 번호에 따라 갱신된다.
매니페스트 작성법
먼저 스테이트풀셋의 매니페스트의 특징 네 가지는 다음과 같다.
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
서비스 매니페스트에 있는 'clusterIP:None'은 대표 IP 주소를 사용하지 않는 헤드리스 서비스를 설정하는 것으로
이것이 스테이트풀셋의 사양으로 정해져 있다.
스테이트풀셋 매니페스트의 'spec:ServiceName:' 에 연동할 서비스의 이름을 설정하면 파드의 이름으로 IP 주소를 얻는 것이 가능해진다.
'volumeMounts:'에는 컨테이너 상의 파일 시스템에 퍼시스턴트 볼륨을 마운트할 위치를 지정한다.
퍼시스턴트 볼륨은 spec.volumeClaimTemplate 밑의 배열 중 metadata.name으로 지정한다.
파드 템플릿 spec.template과 볼륨 요구 템플릿 spec.volumeClaimTemplates로 지정한 사양을 바탕으로 spec.replicas로 지정한 수만틈 파드와 볼륨이 만들어진다.
테이크 오버를 자동화하는 코드 개발
(2) RBAC 권한 부여 매니페스트 작성
RBAC란?
Role-Based-Access-Control의 약자로 변역하면 '역할 기준의 접근 제어' 다.
K8s 클러스터 내에 역할을 설정하고 그 역할에 접근 가능한 권한을 정의하는 접근 제어 방식이다.
이는 쿠버네트스의 접근 제어 방식으로 채택되었다.
RBAC는 서비스 어카운트와 매핑된다. 개인을 식별하는 것이 아닌 파드로 동작하는 컨테이너를 식별하며
네임스페이스별로 유일하다.
서비스 어카운트를 사용하여 필요한 최소한의 권한을 컨테이너에 부여한다.
쿠버네티스는 서비스 어카운트 개념을 도입하여 유저가 소속된 조직 데이터베이스와의 동기화, 복잡한 워크플로, 조직 변경에 대한 대응 등의 문제를 피하고 있다.
하지만 클라우드 서비스나 소프트웨어 제품에서는 개인별 유저 관리가 필수이기 때문에 유저 어카운트와 서비스 어카운트가 대응될 수 있도록 구현하고 있다.
(5) 클러스터 구성 변경 자동 대응
데몬셋은 쿠버네티스를 구성하는 모든 노드에서 파드를 실행하기 위해 존재하는 컨트롤러이다.
유닉스 계열의 운영체제에서는 로그 수집, 원격 터미널 접속, 프린터 출력등의 백그라운드 처리를 하는 백그라운드 프로세스이다.
비슷하게 쿠버네티스의 데몬셋은 K8s 클러스터의 뒤에서 다양한 일들을 처리해주는 파드의 컨트롤러이다.
(우리도 스테이트풀셋 작업이 필수적인데 이를 이미 로건이 다 하신건가??)