1. 程式人生 > 其它 >【K8s教程】StatefulSet 基礎

【K8s教程】StatefulSet 基礎

參考:https://kubernetes.io/zh/docs/tutorials/stateful-application/basic-stateful-set/

建立 StatefulSet

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

順序建立 Pod

對於一個擁有 N 個副本的 StatefulSet,Pod 被部署時是按照 {0 …… N-1} 的序號順序建立的。

StatefulSet 中的 Pod

StatefulSet 中的 Pod 擁有一個唯一的順序索引和穩定的網路身份標識。

檢查 Pod 的順序索引

如同 StatefulSets 概念中所提到的, StatefulSet 中的 Pod 擁有一個具有黏性的、獨一無二的身份標誌。 這個標誌基於 StatefulSet 控制器分配給每個 Pod 的唯一順序索引。 Pod 的名稱的形式為-。 webStatefulSet 擁有兩個副本,所以它建立了兩個 Pod:web-0和web-1。

使用穩定的網路身份標識

每個 Pod 都擁有一個基於其順序索引的穩定的主機名。使用kubectl exec在每個 Pod 中執行hostname。

使用 kubectl run 執行一個提供 nslookup 命令的容器,該命令來自於 dnsutils 包。 通過對 Pod 的主機名執行 nslookup,你可以檢查他們在叢集內部的 DNS 地址。

headless service 的 CNAME 指向 SRV 記錄(記錄每個 Running 和 Ready 狀態的 Pod)。 SRV 記錄指向一個包含 Pod IP 地址的記錄表項。

Pod 的序號、主機名、SRV 條目和記錄名稱沒有改變,但和 Pod 相關聯的 IP 地址可能發生了改變。 在本教程中使用的叢集中它們就改變了。這就是為什麼不要在其他應用中使用 StatefulSet 中的 Pod 的 IP 地址進行連線,這點很重要。

如果你需要查詢並連線一個 StatefulSet 的活動成員,你應該查詢 Headless Service 的 CNAME。 和 CNAME 相關聯的 SRV 記錄只會包含 StatefulSet 中處於 Running 和 Ready 狀態的 Pod。

如果你的應用已經實現了用於測試 liveness 和 readiness 的連線邏輯,你可以使用 Pod 的 SRV 記錄(web-0.nginx.default.svc.cluster.local, web-1.nginx.default.svc.cluster.local)。因為他們是穩定的,並且當你的 Pod 的狀態變為 Running 和 Ready 時,你的應用就能夠發現它們的地址。

寫入穩定的儲存

如果 web-0 和 web-1 被重新排程了,但它們仍然繼續監聽各自的主機名,因為和它們的 PersistentVolumeClaim 相關聯的 PersistentVolume 被重新掛載到了各自的 volumeMount 上。 不管 web-0 和 web-1 被排程到了哪個節點上,它們的 PersistentVolumes 將會被掛載到合適的掛載點上。

擴容/縮容 StatefulSet

擴容/縮容 StatefulSet 指增加或減少它的副本數。這通過更新 replicas 欄位完成。 你可以使用kubectl scale 或者kubectl patch來擴容/縮容一個 StatefulSet。

擴容

kubectl get pods -w -l app=nginx
kubectl scale sts web --replicas=5

StatefulSet 控制器擴充套件了副本的數量。 如同建立 StatefulSet 所述,StatefulSet 按序號索引順序的建立每個 Pod,並且會等待前一個 Pod 變為 Running 和 Ready 才會啟動下一個 Pod。

縮容

kubectl get pods -w -l app=nginx
kubectl patch sts web -p '{"spec":{"replicas":3}}'

順序終止 Pod

控制器會按照與 Pod 序號索引相反的順序每次刪除一個 Pod。在刪除下一個 Pod 前會等待上一個被完全關閉。

檢視 Pod 的 穩定儲存,我們發現當刪除 StatefulSet 的 Pod 時,掛載到 StatefulSet 的 Pod 的 PersistentVolumes 不會被刪除。 當這種刪除行為是由 StatefulSet 縮容引起時也是一樣的。

更新 StatefulSet

Kubernetes 1.7 版本的 StatefulSet 控制器支援自動更新。 更新策略由 StatefulSet API Object 的spec.updateStrategy 欄位決定。這個特效能夠用來更新一個 StatefulSet 中的 Pod 的 container images,resource requests,以及 limits,labels 和 annotations。 RollingUpdate滾動更新是 StatefulSets 預設策略。

Rolling Update 策略

RollingUpdate 更新策略會更新一個 StatefulSet 中所有的 Pod,採用與序號索引相反的順序並遵循 StatefulSet 的保證。

Patch web StatefulSet 來執行 RollingUpdate 更新策略。

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'

StatefulSet 裡的 Pod 採用和序號相反的順序更新。在更新下一個 Pod 前,StatefulSet 控制器終止每個 Pod 並等待它們變成 Running 和 Ready。 請注意,雖然在順序後繼者變成 Running 和 Ready 之前 StatefulSet 控制器不會更新下一個 Pod,但它仍然會重建任何在更新過程中發生故障的 Pod,使用的是它們當前的版本。 已經接收到更新請求的 Pod 將會被恢復為更新的版本,沒有收到請求的 Pod 則會被恢復為之前的版本。 像這樣,控制器嘗試繼續使應用保持健康並在出現間歇性故障時保持更新的一致性。

小竅門:你還可以使用 kubectl rollout status sts/ 來檢視 rolling update 的狀態。

分段更新

你可以使用 RollingUpdate 更新策略的 partition 引數來分段更新一個 StatefulSet。 分段的更新將會使 StatefulSet 中的其餘所有 Pod 保持當前版本的同時僅允許改變 StatefulSet 的 .spec.template。

Patch web StatefulSet 來對 updateStrategy 欄位新增一個分割槽。

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'

請注意,雖然更新策略是 RollingUpdate,StatefulSet 控制器還是會使用原始的容器恢復 Pod。 這是因為 Pod 的序號比 updateStrategy 指定的 partition 更小。

灰度釋出

你可以通過減少 上文指定的 partition 來進行灰度釋出,以此來測試你的程式的改動。

通過 patch 命令修改 StatefulSet 來減少分割槽。

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'

當指定了分割槽時,如果更新了 StatefulSet 的 .spec.template,則所有序號大於或等於分割槽的 Pod 都將被更新。 如果一個序號小於分割槽的 Pod 被刪除或者終止,它將被按照原來的配置恢復。

分階段的釋出

你可以使用類似灰度釋出的方法執行一次分階段的釋出(例如一次線性的、等比的或者指數形式的釋出)。 要執行一次分階段的釋出,你需要設定 partition 為希望控制器暫停更新的序號。

分割槽當前為2。請將分割槽設定為0。

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'

將 partition 改變為 0 以允許 StatefulSet 控制器繼續更新過程。

On Delete 策略

OnDelete 更新策略實現了傳統(1.7 之前)行為,它也是預設的更新策略。 當你選擇這個更新策略並修改 StatefulSet 的 .spec.template 欄位時,StatefulSet 控制器將不會自動的更新 Pod。

刪除 StatefulSet

StatefulSet 同時支援級聯和非級聯刪除。使用非級聯方式刪除 StatefulSet 時,StatefulSet 的 Pod 不會被刪除。使用級聯刪除時,StatefulSet 和它的 Pod 都會被刪除。

非級聯刪除

使用 kubectl delete 刪除 StatefulSet。 請確保提供了 --cascade=false 引數給命令。這個引數告訴 Kubernetes 只刪除 StatefulSet 而不要刪除它的任何 Pod。

kubectl delete statefulset web --cascade=false

StatefulSet 永遠不會刪除和一個 Pod 相關聯的 PersistentVolumes。

級聯刪除

kubectl delete statefulset web

如同你在縮容一節看到的,Pod 按照和他們序號索引相反的順序每次終止一個。 在終止一個 Pod 前,StatefulSet 控制器會等待 Pod 後繼者被完全終止。

請注意,雖然級聯刪除會刪除 StatefulSet 和它的 Pod,但它並不會刪除和 StatefulSet 關聯的 Headless Service。你必須手動刪除nginx Service。

即使你已經刪除了 StatefulSet 和它的全部 Pod,這些 Pod 將會被重新建立並掛載它們的 PersistentVolumes。

Pod 管理策略

對於某些分散式系統來說,StatefulSet 的順序性保證是不必要和/或者不應該的。 這些系統僅僅要求唯一性和身份標誌。為了解決這個問題,在 Kubernetes 1.7 中 我們針對 StatefulSet API 物件引入了 .spec.podManagementPolicy。 此選項僅影響擴縮操作的行為。更新不受影響。

OrderedReady Pod 管理策略

OrderedReady pod 管理策略是 StatefulSets 的預設選項。它告訴 StatefulSet 控制器遵循上文展示的順序性保證。

Parallel Pod 管理策略

Parallel pod 管理策略告訴 StatefulSet 控制器並行的終止所有 Pod, 在啟動或終止另一個 Pod 前,不必等待這些 Pod 變成 Running 和 Ready 或者完全終止狀態。

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"
  podManagementPolicy: "Parallel"
  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

這份清單和上文完全一樣,只是 web StatefulSet 的 .spec.podManagementPolicy 設定成了 Parallel。

清理現場

kubectl delete sts web
kubectl get pod -l app=nginx -w
kubectl delete svc nginx

你需要刪除本教程中用到的 PersistentVolumes 的持久化儲存介質。基於你的環境、儲存配置和提供方式,按照必須的步驟保證回收所有的儲存。

作者:Varden 出處:http://www.cnblogs.com/varden/ 本文內容如有雷同,請聯絡作者! 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。