대세는 쿠버네티스 [초급~중급] 강의를 보고 정리한 글입니다.
[중급 편] 컨트롤러 StatefulSet
Application의 종류
Stateless Application
- 앱이 여러 개 배포되어도 다 똑같은 서비스의 역할을 한다.
- 하나의 앱이 죽는다면 같은 서비스의 역할을 하는 앱을 복제하면 되고 이름도 어떻게 설정하든 상관없다.
- 볼륨이 반드시 필요하진 않다. 볼륨 하나에 모든 앱의 로그를 저장할 수 있다.
- 대체로 사용자들이 접속하며 여러 앱에 트래픽을 분산한다. (단순 분산)
- ReplicaSet 컨트롤러
- 예) Web Server(Apache, Nginx, IIS)
Stateful Application
- 각각의 앱마다 자신의 역할이 있다.
- 하나의 앱(Arbiter 역할을 하는 앱)이 죽는다면 반드시 Arbiter 역할을 하는 앱을 만들어야 하며 앱 이름은 고유 식별자이므로 변경되어서는 안 된다.
- 각각의 역할이 다르므로 각각 다른 볼륨을 연결해야 한다.
- 대체로 내부 시스템들이 데이터베이스 저장을 위해 네트워크에 연결되며 트래픽은 각 앱의 특징에 맞게 전달되야한다.
예) Primary 앱(read, write), Secondary 앱(read) 라면 조회만 하는 내부 시스템은 Secondary로 트래픽이 가야 한다.
- StatefulSet 컨트롤러는 Stateful Application이 유지되도록 관리한다.
- 목적에 따라 Pod(앱)에 연결하기 위해 Headless Service를 달아준다.
- 예) Database(Primary, Secondary, Arbiter)
StatefulSet Controller
ReplicaSet vs StatefulSet의 기능적 차이
공통점
차이점
- pod가 생길 때 ReplicaSet은 이름을 랜덤 생성하지만 StatefulSet은 0부터 순차적으로 생성한다.
- ReplicaSet은 동시에 pod를 생성하지만 StatefulSet은 순차적으로 pod를 생성한다.
- 하나의 pod가 삭제되면 ReplicaSet은 새 이름으로 pod를 생성하지만 StatefulSet은 삭제된 pod의 이름으로 생성한다.
- replicas 3이고 pod가 3개 있는 상태에서 replicas를 0으로 한다면? ReplicaSet은 모든 pod를 동시에 삭제하지만 StatefulSet은 인덱스가 높은 pod부터 순차적으로 삭제한다.
ReplicaSet vs StatefulSet의 PersistentVolumeClaim, Headless Service 연결 방법의 차이
ReplicaSet
- 미리 PVC를 직접 생성해놔야 하며 ReplicaSet은 template의 persistentVolumeClaim: "PVC1" 설정에 따라 pod를 생성할 때 PVC1에 바로 연결한다.
- replicas를 1 -> 3으로 변경한다면? ReplicaSet은 만든 pod를 모두 같은 PVC에 연결한다.
- ReplicaSet에서 PVC1이 노드 1에 있다면 pod들도 노드1에 있어야 한다. pod가 node2에 생성되면 PVC1에 연결할 수 없어 pod 생성에 오류가 발생한다. 이를 방지하고자 nodeSelector: "node1"으로 설정해야 한다.
StatefulSet
- template에 따라 pod를 생성하고 volumeClaimTemplates에 따라 PVC를 동적으로 생성하여 pod와 바로 연결한다.
- replicas를 1 -> 3으로 변경한다면? StatefulSet은 pod가 추가될 때마다 동적으로 PVC를 만든 후 연결한다.
- pod2를 삭제한다면? pod2와 동일한 이름과 역할의 pod를 만들고 기존에 만들어진 PVC-2에 연결한다.
- pod가 있는 노드에 PVC가 동적으로 만들어지기 때문에 알아서 각 노드에 균등하게 분포된다.
- replicas를 3 -> 0으로 변경한다면? pod는 순차적으로 삭제하지만 PVC는 삭제하지 않는다. 삭제하려면 사용자가 직접 삭제해야 한다.
- StatefulSet을 만들 때 ServiceName 속성에 서비스 이름 지정할 수 있다. 예를 들어, ServiceName: "Headless"로 설정하고 Headless Service를 만들면 pod2에 예측 가능한 도메인 이름(Pod-2.Headless)이 만들어진다. 다른 인터널 pod는 이 도메인으로 Statefulset이 관리하는 pod에 접근할 수 있다
yaml 예시
StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: stateful-db
spec:
replicas: 1
selector:
matchLabels:
type: db
template:
metadata:
labels:
type: db
spec:
containers:
- name: container
image: kubetm/app
terminationGracePeriodSeconds: 10
PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: replica-pvc1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1G
storageClassName: "fast" // 동적으로 PV 생성/연결
ReplicaSet
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replica-pvc
spec:
replicas: 1
selector:
matchLabels:
type: web2
template:
metadata:
labels:
type: web2
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node1 // pod와 pvc가 같은 노드에 생성한다.
containers:
- name: container
image: kubetm/init
volumeMounts:
- name: storageos
mountPath: /applog
volumes:
- name: storageos
persistentVolumeClaim:
claimName: replica-pvc1
terminationGracePeriodSeconds: 10 // 10초 후에 삭제한다.
StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: stateful-pvc
spec:
replicas: 1
selector:
matchLabels:
type: db2
serviceName: "stateful-headless" // 이 이름의 서비스를 만든다. Headless Service와 연결되는 이름
template: // template 기반으로 pod를 만들며 이름은 stateful-pvc에 0부터 인덱스가 붙는다.
metadata:
labels:
type: db2
spec:
containers:
- name: container
image: kubetm/app
volumeMounts:
- name: volume
mountPath: /applog
terminationGracePeriodSeconds: 10
volumeClaimTemplates: // 기반으로 volume-stateful-pvc-<index> 이름의 pvc를 만든다.
- metadata:
name: volume // volumeMounts의 name과 이름이 동일해야한다.
spec:
accessModes:
- ReadWriteOnce
resources: // PVC 만들 때 쓰던 내용과 동일
requests:
storage: 1G
storageClassName: "fast"
Service(Headless)
apiVersion: v1
kind: Service
metadata:
name: stateful-headless // StatefulSet의 ServiceName과 일치해야한다.
spec:
selector:
type: db2
ports:
- port: 80
targetPort: 8080
clusterIP: None // None으로 설정하여 Headless 서비스로 만든다.