파드마다 각각 다른 스토리지를 사용해 각각 다른 상태를 유지하기 위해서는 스테이트풀셋(StatefulSet) 리소스를 사용한다.
또한, 목적에 따라 해당 파드에 연결하기 위해서 Headless Service를 사용한다.
스테이트풀셋은 디플로이먼트와 같이 파드를 배포하고 복제본을 제공하며 스케일링을 관리할 수 있다.
그러나 디플로이먼트와 다른 점은 파드의 순서 및 파드의 고유성을 보장하며, 동일한 스펙으로 생성되지만 각각 고유한 볼륨을 가지고 있다.
스테이트풀셋의 주의사항은 아래와 같다.
파드에 사용할 스토리지는 PVC를 통해서만 가능하다.
스테이트풀셋을 삭제하거나 파드를 삭제하더라도 볼륨은 삭제되지 않는다.
헤드리스 서비스가 필요하다.
apiVersion: v1
kind: Service
metadata:
name: myapp-svc-headless
labels:
app: myapp-svc-headless
spec:
ports:
- name: http
port: 80
clusterIP: None
selector:
app: myapp-sts
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: myapp-sts
spec:
selector:
matchLabels:
app: myapp-sts
serviceName: myapp-svc-headless
replicas: 2
template:
metadata:
labels:
app: myapp-sts
spec:
containers:
- name: myapp
image: ghcr.io/c1t1d0s7/go-myweb
ports:
- containerPort: 8080
kubectl scale statefulset myapp-sts --replicas=3
kubectl scale statefulset myapp-sts --replicas=2
kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-sts-0 1/1 Running 0 4m25s 10.244.0.7 minikube <none> <none>
myapp-sts-1 1/1 Running 0 4m20s 10.244.0.8 minikube <none> <none>
kubectl run nettool -it --image=ghcr.io/c1t1d0s7/network-multitool --rm bash
host myapp-svc-headless
myapp-svc-headless.default.svc.cluster.local has address 10.244.0.7
myapp-svc-headless.default.svc.cluster.local has address 10.244.0.8
서비스의 Cluster IP가 아닌(어차피 없음) 각 파드의 IP로 응답한다.
curl myapp-sts-1.myapp-svc-headless:8080
Hello World!
myapp-sts-1
curl myapp-sts-0.myapp-svc-headless:8080
Hello World!
myapp-sts-0
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: myapp-sts-vol
spec:
selector:
matchLabels:
app: myapp-sts-vol
serviceName: myapp-svc-headless
replicas: 2
template:
metadata:
labels:
app: myapp-sts-vol
spec:
containers:
- name: myapp
image: ghcr.io/c1t1d0s7/go-myweb:alpine
ports:
- containerPort: 8080
volumeMounts:
- name: myapp-data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: myapp-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
storageClassName: standard
kubectl apply -f myapp-sts-vol.yaml
kubectl get all
kubectl describe po myapp-sts-vol-0
Volumes:
myapp-data:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: myapp-data-myapp-sts-vol-0
ReadOnly: false
kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-3c80b3a9-7346-460f-998f-142712c25395 1Gi RWO Delete Bound default/myapp-data-myapp-sts-vol-0 standard 90s
persistentvolume/pvc-4214359b-1a52-4bfe-bb78-ad7d4af4f358 1Gi RWO Delete Bound default/myapp-data-myapp-sts-vol-1 standard 84s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/myapp-data-myapp-sts-vol-0 Bound pvc-3c80b3a9-7346-460f-998f-142712c25395 1Gi RWO standard 90s
persistentvolumeclaim/myapp-data-myapp-sts-vol-1 Bound pvc-4214359b-1a52-4bfe-bb78-ad7d4af4f358 1Gi RWO standard 84s
kubectl scale statefulset myapp-sts-vol --replicas=3
kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-3c80b3a9-7346-460f-998f-142712c25395 1Gi RWO Delete Bound default/myapp-data-myapp-sts-vol-0 standard 5m4s
persistentvolume/pvc-4214359b-1a52-4bfe-bb78-ad7d4af4f358 1Gi RWO Delete Bound default/myapp-data-myapp-sts-vol-1 standard 4m58s
persistentvolume/pvc-e9875c67-ce4e-47c9-9e5f-4321060f349e 1Gi RWO Delete Bound default/myapp-data-myapp-sts-vol-2 standard 12s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/myapp-data-myapp-sts-vol-0 Bound pvc-3c80b3a9-7346-460f-998f-142712c25395 1Gi RWO standard 5m4s
persistentvolumeclaim/myapp-data-myapp-sts-vol-1 Bound pvc-4214359b-1a52-4bfe-bb78-ad7d4af4f358 1Gi RWO standard 4m58s
persistentvolumeclaim/myapp-data-myapp-sts-vol-2 Bound pvc-e9875c67-ce4e-47c9-9e5f-4321060f349e 1Gi RWO standard 12s
kubectl delete -f myapp-sts-vol.yaml
kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-3c80b3a9-7346-460f-998f-142712c25395 1Gi RWO Delete Bound default/myapp-data-myapp-sts-vol-0 standard 6m25s
persistentvolume/pvc-4214359b-1a52-4bfe-bb78-ad7d4af4f358 1Gi RWO Delete Bound default/myapp-data-myapp-sts-vol-1 standard 6m19s
persistentvolume/pvc-e9875c67-ce4e-47c9-9e5f-4321060f349e 1Gi RWO Delete Bound default/myapp-data-myapp-sts-vol-2 standard 93s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/myapp-data-myapp-sts-vol-0 Bound pvc-3c80b3a9-7346-460f-998f-142712c25395 1Gi RWO standard 6m25s
persistentvolumeclaim/myapp-data-myapp-sts-vol-1 Bound pvc-4214359b-1a52-4bfe-bb78-ad7d4af4f358 1Gi RWO standard 6m19s
persistentvolumeclaim/myapp-data-myapp-sts-vol-2 Bound pvc-e9875c67-ce4e-47c9-9e5f-4321060f349e 1Gi RWO standard 93s
컨트롤러 및 파드가 삭제된 후에도 여전히 pv와 pvc는 남아있다.
데이터의 안전을 보장하기 위한 조치로 불필요한 경우에는 수동으로 삭제해야 한다.
kubectl delete pvc --all
회수 정책이 Delete이므로 pvc만 삭제하면 pv도 같이 삭제된다.