๐Ÿช์ฟ ๋ฒ„๋„คํ‹ฐ์Šค StatefulSets

๊น€์„ฑ์ธยท2023๋…„ 10์›” 18์ผ
0

[DevOps] ๐ŸณDocker & Kubernetes

๋ชฉ๋ก ๋ณด๊ธฐ
34/62
post-thumbnail

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” workload API ๊ฐ์ฒด

  • ๋””ํ”Œ๋กœ์ด๋จผํŠธ ๊ด€๋ฆฌ์™€ Pod์˜ ์„ธํŠธ ์ˆ˜๋ฅผ scaling ๊ด€๋ฆฌ, ์ˆœ์„œ์™€ ๊ณ ์œ ํ•œ Pod๋ฅผ ์ œ๊ณตํ•จ.
  • ๋””ํ”Œ๋กœ์ด๋จผํŠธ์ฒ˜๋Ÿผ StatefulSet์€ ๋™์ผํ•œ ์ปจํ…Œ์ด๋„ˆ spec์„ ๊ธฐ๋ฐ˜์œผ๋กœ Pod๋ฅผ ๊ด€๋ฆฌํ•จ.
  • ๋””ํ”Œ๋กœ์ด๋จผํŠธ์™€ ๋‹ค๋ฅธ ์ ์€, ๊ฐ Pod์— sticky ์‹๋ณ„์ž๋ฅผ ์œ ์ง€ํ•จ.
  • ํ•ด๋‹น Pods๋“ค์€ ๊ฐ™์€ spec์œผ๋กœ ๋งŒ๋“ค์–ด ์กŒ์ง€๋งŒ, ์ƒํ˜ธ ๊ตํ™˜์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ฐ ํฌ๋“œ๋Š” ๋ฆฌ์Šค์ผ€์ฅด๋ง ๋˜๋Š” ๋™์•ˆ์—๋„ ์˜๊ตฌ์‹๋ณ„์ž๋ฅผ ์œ ์ง€ํ•จ.

ํฌ๋“œ๋ฅผ ์ง€์› ๋‹ค ๋‹ค์‹œ ์ƒ์„ฑํ•ด๋„ ๋ฆฌ์†Œ์Šค๋ฅผ ์œ ์ง€๊ฐ€๋Šฅํ•œ Stateful ์ƒํƒœ

Using StatefulSets

(์‚ฌ์šฉ ์ผ€์ด์Šค)

  • ์•ˆ์ •์ , ๊ณ ์œ ํ•œ ๋„คํŠธ์›Œํฌ ์‹๋ณ„์ž
  • ์•ˆ์ •์  ์ง€์†์  ์Šคํ† ๋ฆฌ์ง€
  • ์ˆœ์„œ๋ฅผ ๊ฐ€์ง€๊ณ , ์šฐ์•„ํ•œ ๋””ํ”Œ๋กœ์ด๋จผํŠธ์™€ ์Šค์ผ€์ผ๋ง(๋ฐฐ์น˜์™€ ํ™•์žฅ)
  • ์ˆœ์„œ๋ฅผ ๊ฐ€์ง€๊ณ , ์ž๋™์œผ๋กœ ๋กค๋ง ์—…๋ฐ์ดํŠธ

๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค

  • ์ง€์ •๋œ ํฌ๋“œ์˜ ์Šคํ† ๋ฆฌ์ง€๋Š” ์š”์ฒญ๋œ ์Šคํ† ๋ฆฌ์ง€ ํด๋ž˜์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ Persistent Volume Provisioner์— ์˜ํ•ด ํ”„๋กœ๋น„์ €๋‹๋˜๊ฑฐ๋‚˜ ๊ด€๋ฆฌ์ž์— ์˜ํ•ด ์‚ฌ์ „ ํ”„๋กœ๋น„์ €๋‹๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • StatefulSet์„ ์‚ญ์ œ ํ•˜๊ฑฐ๋‚˜ ์ถ•์†Œํ•ด๋„ StatefulSet๊ณผ ๊ด€๋ จ๋œ ๋ณผ๋ฅจ์€ ์‚ญ์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ชจ๋“  ๊ด€๋ จ StatefulSet ๋ฆฌ์†Œ์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๊ฐ€์น˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์•ˆ์ „์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. (๊ด€๋ฆฌ์ž๊ฐ€ ๊ด€๋ฆฌ๋ฅผ ํ•ด์ค˜์•ผํ•จ)
  • StatefulSets๋Š” ํ˜„์žฌ Pods์˜ ๋„คํŠธ์›Œํฌ ID๋ฅผ ์ฑ…์ž„์ง€๋Š” ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ์ด ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค ์ฑ…์ž„์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • StatefulSet๋Š” StatefulSet์„ ์‚ญ์ œํ•  ๋•Œ ํฌ๋“œ์˜ ์ข…๋ฃŒ์— ๋Œ€ํ•œ ๋ณด์žฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. StatefulSet์—์„œ ํฌ๋“œ์˜ ์งˆ์„œ ์žˆ๋Š” ์ •์ƒ ์ข…๋ฃŒ๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ญ์ œ ์ „์— StatefulSet์„ 0์œผ๋กœ ์ถ•์†Œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ Pod Management Policy(OrderedReady)์™€ ํ•จ๊ป˜ Rolling Updates(๋กค๋ง ์—…๋ฐ์ดํŠธ)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ณต๊ตฌ์— ์ˆ˜๋™ ๊ฐœ์ž…์ด ํ•„์š”ํ•œ ๊ณ ์žฅ ์ƒํƒœ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์ˆ˜๋™๋ณต๊ตฌ ํ•„์š”)

ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx

clusterIP : None์œผ๋กœ ์ž‘์„ฑ

  • ๊ธฐ์กด ์„œ๋น„์Šค์™€ ๋‹ฌ๋ฆฌ kube-proxy ๊ฐ€ ๋ฐธ๋Ÿฐ์‹ฑ์ด๋‚˜ ํ”„๋ก์‹œ ํ˜•ํƒœ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์Œ.
  • ๋„๋ฉ”์ธ ๋„ค์ž„์„ ์‚ฌ์šฉํ•ด์„œ ํฌ๋“œ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•จ.

StatuefulSet

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx" # ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค ์„ค์ •
  replicas: 3 # by default is 1
  minReadySeconds: 10 # by default is 0
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10 # ๊ฐ•์ œ์ข…๋ฃŒ๊นŒ์ง€ ๋Œ ใ…ฃ์‹œ๊ฐ„
      containers:
      - name: nginx
        image: registry.k8s.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates: # pvc๋ฅผ ํฌ๋“œ์™€ ํ•จ๊ป˜ ๋งŒ๋“ค์–ด์คŒ (ํŒŒ๋“œ์— pvc๊ฐ€ ํ•˜๋‚˜์”ฉ ๋ฌผ๋ฆผ)
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi
  • serviceName
    • ์—ฐ๊ฒฐํ•  ํ—ค๋“œ๋ฆฌ์Šค ์„œ๋น„์Šค ์ง€์ •, ๋ ˆ์ด๋ธ” ์ผ์น˜
  • terminationGracePeriodSeconds
    • ์ผ๋ฐ˜ํฌ๋“œ์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์„ค์ •. ์ข…๋ฃŒ ์š”์ฒญํ›„ ๊ธฐ๋‹ค๋ฆด ์‹œ๊ฐ„
  • volumeClaimTemplate
    • volumeClaim ํ…œํ”Œ๋ฆฟ ์ž‘์„ฑ
  • volumeMounts
    • ๋ถˆ๋ฅจ ๋งˆ์šดํŠธ ์„ค์ •

์Šคํ…Œ์ดํŠธํ’€์…‹ ํฌ๋“œ ์‹๋ณ„

๋ฐฐํฌ ์ˆœ์„œ : 0 ~ n
์ข…๋ฃŒ/ ์—…๋ฐ์ดํŠธ ์ˆœ์„œ : n ~ 0


์—…๋ฐ์ดํŠธ ์ „๋žต

OnDelete : ์‚ญ์ œ์‹œ ์ƒˆ๋กœ ํ•˜๋‚˜ ๋งŒ๋“ฌ
RollingUpdate : ๋””ํ”Œ๋กœ์ด๋จผํŠธ์™€ ๋™์ผํ•œ ๋กค๋ง์—…๋ฐ์ดํŠธ ์ „๋žต(ํ•˜๋‚˜ ์—…๋ฐ์ดํŠธ ํ•˜๋‚˜ ๊ต์ฒด)


์ƒ์„ฑ

nginx-statefulset.yaml

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:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  minReadySeconds: 10 # by default is 0
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: registry.k8s.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" ]
      storageClassName: "standard"
      resources:
        requests:
          storage: 1Gi

pending์ƒํƒœ ๋ฐœ์ƒ

Events:
  Type     Reason             Age                  From                Message
  ----     ------             ----                 ----                -------
  Normal   NotTriggerScaleUp  3m37s                cluster-autoscaler  pod didn't trigger scale-up:
  Warning  FailedScheduling   13s (x5 over 3m39s)  default-scheduler   0/3 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod..

storageClass ์„ค์ •์„ ์ž˜๋ชปํ•ด์„œ ์ผ์–ด๋‚œ ์˜ค๋ฅ˜์˜€๋‹ค.
->storageClassName: "standard"


์‹คํ–‰ํ™•์ธ

๋””ํ”Œ๋กœ์ด๋จผํŠธ์™€ ๋‹ค๋ฅด๊ฒŒ ๋ ˆํ”Œ๋ฆฌ์นด์…‹์„ ๊ฐ€์ง€์ง€ ์•Š์Œ

  • ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ๊ฐœ ํŒŒ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์ˆœ์„œ์— ๋งž๊ฒŒ ํ•˜๋‚˜์”ฉ ์ƒ์„ฑ, ์‹คํ–‰๋จ

    web-0 ํŒŒ๋“œ๋ฅผ ์‚ญ์ œํ–ˆ๋‹ค ๋‹ค์‹œ ์‹คํ–‰ํ•ด๋„ www-web-0 pvc์— ๋‹ค์‹œ ์—ฐ๊ฒฐ๋จ


๋„๋ฉ”์ธ ๋„ค์ž„, ์„œ๋น„์Šค ๋™์ž‘ ํ™•์ธ

kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh

kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh
If you don't see a command prompt, try pressing enter.

/ # nslookup web-0.nginx.default.svc
Server:    10.8.0.10
Address 1: 10.8.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx.default.svc
Address 1: 10.4.1.45 web-0.nginx.default.svc.cluster.local
/ # nslookup web-1.nginx.default.svc
Server:    10.8.0.10
Address 1: 10.8.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx.default.svc
Address 1: 10.4.2.28 web-1.nginx.default.svc.cluster.local
/ # nslookup web-2.nginx.default.svc
Server:    10.8.0.10
Address 1: 10.8.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-2.nginx.default.svc
Address 1: 10.4.0.32 web-2.nginx.default.svc.cluster.local


์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—ฐ๊ฒฐ๋œ ๋ชจ์Šต


์Šค์ผ€์ผ๋ง

์Šค์ผ€์ผ ์—…

kubectl scale statefulset web --replicas 5

ํ•˜๋‚˜์”ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ๋งŒ๋“ค์–ด์ง€๋Š” ๋ชจ์Šต

์Šค์ผ€์ผ ๋‹ค์šด

์—ญ์ˆœ์œผ๋กœ ์‚ญ์ œ๋จ

pvc ์œ ์ง€๋จ

statefulSet์‚ญ์ œ

kubectl delete statefulSet <์Šคํ…Œ์ดํŠธํ’€์…‹์ด๋ฆ„>
-> ํ•ด๋„ pvc ์‚ญ์ œ๋˜์ง€ ์•Š์Œ.
-> ๋‹ค์‹œ pod์‹คํ–‰๋˜๋ฉด ์ง€์ •๋˜์–ด ๋งˆ์šดํŠธ๋จ.

0๊ฐœ์˜ ๋Œ“๊ธ€