Kubernetes控制器之StatefulSet


  參考:https://kubernetes.io/zh/docs/concepts/workloads/controllers/statefulset/

    https://www.kubernetes.org.cn/deployment

  StatefulSet

  StatefulSet是為了解決有狀態服務的問題(對應Deployments和ReplicaSets是為無狀態服務而設計),其應用場景包括

  • 穩定的持久化存儲,即Pod重新調度后還是能訪問到相同的持久化數據,基於PVC來實現
  • 穩定的網絡標志,即Pod重新調度后其PodName和HostName不變,基於Headless Service(即沒有Cluster IP的Service)來實現
  • 有序部署,有序擴展,即Pod是有順序的,在部署或者擴展的時候要依據定義的順序依次依次進行(即從0到N-1,在下一個Pod運行之前所有之前的Pod必須都是Running和Ready狀態),基於init containers來實現
  • 有序收縮,有序刪除(即從N-1到0)

  從上面的應用場景可以發現,StatefulSet由以下幾個部分組成:

  • 用於定義網絡標志(DNS domain)的Headless Service
  • 用於創建PersistentVolumes的volumeClaimTemplates
  • 定義具體應用的StatefulSet

  StatefulSet中每個Pod的DNS格式為statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local,其中

  • serviceName為Headless Service的名字
  • 0..N-1為Pod所在的序號,從0開始到N-1
  • statefulSetName為StatefulSet的名字
  • namespace為服務所在的namespace,Headless Servic和StatefulSet必須在相同的namespace
  • .cluster.local為Cluster Domain 默認域就是cluster.local

  限制

  • 給定 Pod 的存儲必須由 PersistentVolume 驅動 基於所請求的 storage class 來提供,由管理員預先提供。
  • 刪除或者收縮 StatefulSet 並不會刪除它關聯的存儲卷。這樣做是為了保證數據安全,它通常比自動清除 StatefulSet 所有相關的資源更有價值。
  • StatefulSet 當前需要 headless 服務 來負責 Pod 的網絡標識。您需要負責創建此服務。
  • 當刪除 StatefulSets 時,StatefulSet 不提供任何終止 Pod 的保證。為了實現 StatefulSet 中的 Pod 可以有序和優雅的終止,可以在刪除之前將 StatefulSet 縮放為 0。
  • 在默認 Pod 管理策略(OrderedReady) 時使用 滾動更新,可能進入需要 人工干預 才能修復的損壞狀態。

  組件

  下面的示例演示了 StatefulSet 的組件。

# cat web.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
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        #image: k8s.gcr.io/nginx-slim:0.8
        image: lowyard/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: "managed-nfs-storage"
      resources:
        requests:
          storage: 1Gi
  • 名為 nginx 的 Headless Service 用來控制網絡域名。
  • 名為web的StatefulSet .spec.replicas表明獨立的3個Pod副本啟動nginx容器
  • volumeClaimTemplates 將通過 PersistentVolumes 驅動提供的 PersistentVolumes 來提供穩定的存儲。需要由管理員事先創建,本次創建的是NFS存儲創建參考:https://www.cnblogs.com/minseo/p/12456987.html

  Pod選擇器

  必須設置StatefulSet的.spec.selector字段,使之匹配其在.spec.template.metadata.labels 中設置的標簽。在 Kubernetes 1.8 版本之前,被忽略 .spec.selector 字段會獲得默認設置值。在 1.8 和以后的版本中,未指定匹配的 Pod 選擇器將在創建 StatefulSet 期間導致驗證錯誤。

  Pod標識

  StatefulSet Pod 具有唯一的標識,該標識包括順序標識、穩定的網絡標識和穩定的存儲。該標識和 Pod 是綁定的,不管它被調度在哪個節點上。

  有序索引

  對於具有 N 個副本的 StatefulSet,StatefulSet 中的每個 Pod 將被分配一個整數序號,從 0 到 N-1,該序號在 StatefulSet 上是唯一的。

  穩定的網絡 ID

  StatefulSet 中的每個 Pod 根據 StatefulSet 的名稱和 Pod 的序號派生出它的主機名。組合主機名的格式為$(StatefulSet 名稱)-$(序號)。上例將會創建三個名稱分別為 web-0、web-1、web-2 的 Pod

 

 

   StatefulSet 可以使用 headless 服務 控制它的 Pod 的網絡域。管理域的這個服務的格式為: $(服務名稱).$(命名空間).svc.cluster.local,其中 cluster.local 是集群域。 一旦每個 Pod 創建成功,就會得到一個匹配的 DNS 子域,格式為:$(pod 名稱).$(所屬服務的 DNS 域名),其中所屬服務由 StatefulSet 的 serviceName 域來設定。

  下面給出一些選擇集群域、服務名、StatefulSet 名、及其怎樣影響 StatefulSet 的 Pod 上的 DNS 名稱的示例:

Cluster Domain Service (ns/name) StatefulSet (ns/name) StatefulSet Domain Pod DNS Pod Hostname
cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1}
cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1}
kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..N-1}.nginx.foo.svc.kube.local web-{0..N-1}

 

注意: 集群域會被設置為 cluster.local,除非有其他配置。

   穩定的存儲

  Kubernetes 為每個 VolumeClaimTemplate 創建一個 PersistentVolume。在上面的 nginx 示例中,每個 Pod 將會得到基於 StorageClass my-storage-class 提供的 1 Gib 的 PersistentVolume。如果沒有聲明 StorageClass,就會使用默認的 StorageClass。當一個 Pod 被調度(重新調度)到節點上時,它的 volumeMounts 會掛載與其 PersistentVolumeClaims 相關聯的 PersistentVolume。請注意,當 Pod 或者 StatefulSet 被刪除時,與 PersistentVolumeClaims 相關聯的 PersistentVolume 並不會被刪除。要刪除它必須通過手動方式來完成。

  Pod名稱標簽

  當 StatefulSet 控制器 創建 Pod 時,它會添加一個標簽 statefulset.kubernetes.io/pod-name,該標簽設置為 Pod 名稱。這個標簽允許您給 StatefulSet 中的特定 Pod 綁定一個 Service。

  查看該標簽

# kubectl get pod --show-labels
NAME                                    READY   STATUS             RESTARTS   AGE   LABELS
db-0                                    0/1     CrashLoopBackOff   13         68m   controller-revision-hash=db-86458bcd44,project=java-demo,run=mysql,statefulset.kubernetes.io/pod-name=db-0
nfs-client-provisioner-7db87779-jdp99   1/1     Running            0          71m   app=nfs-client-provisioner,pod-template-hash=7db87779
web-0                                   1/1     Running            0          56m   app=nginx,controller-revision-hash=web-5d84f996d,statefulset.kubernetes.io/pod-name=web-0
web-1                                   1/1     Running            0          56m   app=nginx,controller-revision-hash=web-5d84f996d,statefulset.kubernetes.io/pod-name=web-1
web-2                                   1/1     Running            0          56m   app=nginx,controller-revision-hash=web-5d84f996d,statefulset.kubernetes.io/pod-name=web-2

   部署和擴縮保證

  • 對於包含 N 個 副本的 StatefulSet,當部署 Pod 時,它們是依次創建的,順序為 0..N-1
  • 當刪除 Pod 時,它們是逆序終止的,順序為 N-1..0
  • 在將縮放操作應用到 Pod 之前,它前面的所有 Pod 必須是 Running 和 Ready 狀態。
  • 在 Pod 終止之前,所有的繼任者必須完全關閉。

  StatefulSet 不應將 pod.Spec.TerminationGracePeriodSeconds 設置為 0。這種做法是不安全的,要強烈阻止。

  在上面的 nginx 示例被創建后,會按照 web-0、web-1、web-2 的順序部署三個 Pod。在 web-0 進入 Running 和 Ready 狀態前不會部署 web-1。在 web-1 進入 Running 和 Ready 狀態前不會部署 web-2。如果 web-1 已經處於 Running 和 Ready 狀態,而 web-2 尚未部署,在此期間發生了 web-0 運行失敗,那么 web-2 將不會被部署,要等到 web-0 部署完成並進入 Running 和 Ready 狀態后,才會部署 web-2。

  如果用戶想將示例中的 StatefulSet 收縮為 replicas=1,首先被終止的是 web-2。在 web-2 沒有被完全停止和刪除前,web-1 不會被終止。當 web-2 已被終止和刪除、web-1 尚未被終止,如果在此期間發生 web-0 運行失敗,那么就不會終止 web-1,必須等到 web-0 進入 Running 和 Ready 狀態后才會終止 web-1。


  Pod管理策略

  在 Kubernetes 1.7 及以后的版本中,StatefulSet 允許您不要求其排序保證,同時通過它的 .spec.podManagementPolicy 域保持其唯一性和身份保證。 在 Kubernetes 1.7 及以后的版本中,StatefulSet 允許您放寬其排序保證,同時通過它的 .spec.podManagementPolicy 域保持其唯一性和身份保證。

  OrderedReady Pod 管理

  OrderedReady Pod 管理是 StatefulSet 的默認設置。它實現了上面描述的功能。

  Parallel Pod 管理

  Parallel Pod 管理讓 StatefulSet 控制器並行的啟動或終止所有的 Pod,啟動或者終止其他 Pod 前,無需等待 Pod 進入 Running 和 ready 或者完全停止狀態。

  更新策略 

  在 Kubernetes 1.7 及以后的版本中,StatefulSet 的 .spec.updateStrategy 字段讓您可以配置和禁用掉自動滾動更新 Pod 的容器、標簽、資源請求或限制、以及注解。

  關於刪除策略 

  OnDelete 更新策略實現了 1.6 及以前版本的歷史遺留行為。當 StatefulSet 的 .spec.updateStrategy.type 設置為 OnDelete 時,它的控制器將不會自動更新 StatefulSet 中的 Pod。用戶必須手動刪除 Pod 以便讓控制器創建新的 Pod,以此來對 StatefulSet 的 .spec.template 的變動作出反應。

  滾動更新  

  RollingUpdate 更新策略對 StatefulSet 中的 Pod 執行自動的滾動更新。在沒有聲明 .spec.updateStrategy 時,RollingUpdate 是默認配置。 當 StatefulSet 的 .spec.updateStrategy.type 被設置為 RollingUpdate 時,StatefulSet 控制器會刪除和重建 StatefulSet 中的每個 Pod。 它將按照與 Pod 終止相同的順序(從最大序號到最小序號)進行,每次更新一個 Pod。它會等到被更新的 Pod 進入 Running 和 Ready 狀態,然后再更新其前身。

  分區

  通過聲明 .spec.updateStrategy.rollingUpdate.partition 的方式,RollingUpdate 更新策略可以實現分區。如果聲明了一個分區,當 StatefulSet 的 .spec.template 被更新時,所有序號大於等於該分區序號的 Pod 都會被更新。所有序號小於該分區序號的 Pod 都不會被更新,並且,即使他們被刪除也會依據之前的版本進行重建。如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition 大於它的 .spec.replicas,對它的 .spec.template 的更新將不會傳遞到它的 Pod。 在大多數情況下,您不需要使用分區,但如果您希望進行階段更新、則這些分區會非常有用。

  強制回滾

  在默認 Pod 管理策略(OrderedReady) 時使用 滾動更新 ,可能進入需要人工干預才能修復的損壞狀態。

  如果更新后 Pod 模板配置進入無法運行或就緒的狀態(例如,由於錯誤的二進制文件或應用程序級配置錯誤),StatefulSet 將停止回滾並等待。

  在這種狀態下,僅將 Pod 模板還原為正確的配置是不夠的。由於已知問題,StatefulSet 將繼續等待損壞狀態的 Pod 准備就緒(永遠不會發生),然后再嘗試將其恢復為正常工作配置。

  恢復模板后,還必須刪除 StatefulSet 嘗試使用錯誤的配置來運行的 Pod。這樣,StatefulSet 才會開始使用被還原的模板來重新創建 Pod。

  部署StatefulSet

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

  目標

  StatefulSets 旨在與有狀態的應用及分布式系統一起使用。然而在 Kubernetes 上管理有狀態應用和分布式系統是一個寬泛而復雜的話題。為了演示 StatefulSet 的基本特性,並且不使前后的主題混淆,你將會使用 StatefulSet 部署一個簡單的 web 應用。

  在閱讀本教程后,你將熟悉以下內容:

  • 如何創建StatefulSet
  • StatefulSet怎樣管理它的Pods
  • 如何刪除StatefulSet
  • 如何對StatefulSet進行擴容/縮容
  • 如果更新一個StatefulSet的Pods

  創建StatefulSet

   需要有動態存儲卷本次私有NFS搭建,搭建完畢以后使用命令查看

# kubectl get storageClass
NAME                  PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage   fuseim.pri/ifs   Delete          Immediate           false                  120m

   需要使用兩個終端窗口。在一個終端中使用kubectl get來檢查StatefulSet創建Pods情況

kubectl get pods -w -l app=nginx

   在另一個終端中,使用 kubectl apply來創建定義在 web.yaml 中的 Headless Service 和 StatefulSet。

kubectl apply -f web.yaml 
service/nginx created
statefulset.apps/web created

   上面的命令創建了兩個 Pod,每個都運行了一個 NGINX web 服務器。獲取 nginx Service 和 web StatefulSet 來驗證是否成功的創建了它們。

kubectl get service nginx
NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx   ClusterIP   None         <none>        80/TCP    2m8s
kubectl get statefulset web
NAME   READY   AGE
web    2/2     2m10s

   順序創建Pod

  對於一個擁有 N 個副本的 StatefulSet,Pod 被部署時是按照 {0 …… N-1} 的序號順序創建的。在第一個終端中使用 kubectl get 檢查輸出。這個輸出最終將看起來像下面的樣子。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   0/1     Pending   0          0s
web-0   0/1     Pending   0          0s
web-0   0/1     Pending   0          2s
web-0   0/1     ContainerCreating   0          2s
web-0   1/1     Running             0          4s
web-1   0/1     Pending             0          0s
web-1   0/1     Pending             0          0s
web-1   0/1     Pending             0          2s
web-1   0/1     ContainerCreating   0          2s
web-1   1/1     Running             0          4s

   請注意在 web-0 Pod 處於 Running和Ready 狀態后 web-1 Pod 才會被啟動。

  StatefulSet中的Pod  

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

  檢查Pod順序索引

#參數-l更加標簽進行匹配
kubectl get pods -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          4m6s
web-1   1/1     Running   0          4m1s

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

  本次示例的statefulset name為web
  序號從0開始至設定的副本數n-1

 

   使用穩定的網絡身份標識

  每個Pod都擁有一個基於其順序索引的穩定的主機名。

for i in 0 1;do kubectl exec web-$i -- sh -c 'hostname';done
web-0
web-1

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

kubectl run -it --image busybox:1.28 dns-test --restart=Never --rm
nslookup web-0.nginx
Server:    10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 172.17.71.3 web-0.nginx.default.svc.cluster.local

   DNS格式為 $(Pod名).$(所屬服務的 DNS 域名).$(命名空間).svc.cluster.local

  所屬服務的 DNS 域名由StatefulSet的serviceName設置

  其中域設置默認為cluster.local

  在一個終端查看StatefulSet的Pods

kubectl get pods -w -l app=nginx

   在另一個終端刪除StatefulSet中的Pods

kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

   等待 StatefulSet 重啟它們,並且兩個 Pod 都變成 Running 和 Ready 狀態。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          19m
web-1   1/1     Running   0          19m
web-0   1/1     Terminating   0          20m
web-1   1/1     Terminating   0          20m
web-1   0/1     Terminating   0          20m
web-0   0/1     Terminating   0          20m
web-1   0/1     Terminating   0          20m
web-1   0/1     Terminating   0          20m
web-0   0/1     Terminating   0          20m
web-0   0/1     Terminating   0          20m
web-0   0/1     Pending       0          0s
web-0   0/1     Pending       0          0s
web-0   0/1     ContainerCreating   0          0s
web-0   1/1     Running             0          1s
web-1   0/1     Pending             0          0s
web-1   0/1     Pending             0          0s
web-1   0/1     ContainerCreating   0          0s
web-1   1/1     Running             0          1s

   使用 kubectl exec 和 kubectl run 查看 Pod 的主機名和集群內部的 DNS 表項。

for i in 0 1;do kubectl exec web-$i -- sh -c 'hostname';done
web-0
web-1

   

kubectl run -it --image busybox:1.28 dns-test --restart=Never --rm
If you don't see a command prompt, try pressing enter.
/ # nslookup web-0.nginx
Server:    10.0.0.2
Address 1: 10.0.0.2 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 172.17.71.3 web-0.nginx.default.svc.cluster.local

   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 的 PersistentVolumeClaims。

kubectl get pvc -l app=nginx
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
www-web-0   Bound    pvc-bbc399de-fac4-4f10-bd77-fc40fbf949a9   1Gi        RWO            managed-nfs-storage   131m
www-web-1   Bound    pvc-4d147825-2087-41d8-8fc1-a174de4c3bf6   1Gi        RWO            managed-nfs-storage

   StatefulSet 控制器創建了兩個 PersistentVolumeClaims,綁定到兩個 PersistentVolumes。由於本教程使用的集群配置為動態提供 PersistentVolume,所有的 PersistentVolume 都是自動創建和綁定的。

  NGINX web 服務器默認會加載位於 /usr/share/nginx/html/index.html 的 index 文件。StatefulSets spec 中的 volumeMounts 字段保證了 /usr/share/nginx/html 文件夾由一個 PersistentVolume 支持。

  將 Pod 的主機名寫入它們的index.html文件並驗證 NGINX web 服務器使用該主機名提供服務。

for i in 0 1; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done

for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1

 

注意:
請注意,如果你看見上面的 curl 命令返回了 403 Forbidden 的響應,你需要像這樣修復使用 volumeMounts(due to a bug when using hostPath volumes)掛載的目錄的權限:

for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done
在你重新嘗試上面的 curl 命令之前。

   在一個終端查看 StatefulSet 的 Pod。

kubectl get pods -w -l app=nginx

   在另一個終端刪除 StatefulSet 所有的 Pod。

kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

   在第一個終端里檢查kubectl get命令的輸出,等待所有Pod變成Running和Ready狀態

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          117m
web-1   1/1     Running   0          117m
web-0   1/1     Terminating   0          118m
web-1   1/1     Terminating   0          118m
web-1   0/1     Terminating   0          118m
web-0   0/1     Terminating   0          118m
web-0   0/1     Terminating   0          118m
web-0   0/1     Terminating   0          118m
web-0   0/1     Pending       0          0s
web-0   0/1     Pending       0          0s
web-0   0/1     ContainerCreating   0          0s
web-0   1/1     Running             0          1s
web-1   0/1     Terminating         0          118m
web-1   0/1     Terminating         0          118m
web-1   0/1     Pending             0          0s
web-1   0/1     Pending             0          0s
web-1   0/1     ContainerCreating   0          0s
web-1   1/1     Running             0          0s

   驗證所有 web 服務器在繼續使用它們的主機名提供服務。

for i in 0 1;do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1

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

  擴容/縮容StatefulSet

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

  擴容

  在一個終端窗口觀察 StatefulSet 的 Pod。

kubectl get pods -w -l app=nginx

   在另一個終端窗口使用 kubectl scale 擴展副本數為 5。

kubectl scale sts web --replicas=5
statefulset.apps/web scaled

   在第一個 終端中檢查 kubectl get 命令的輸出,等待增加的 3 個 Pod 的狀態變為 Running 和 Ready。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          6m17s
web-1   1/1     Running   0          6m12s
web-2   0/1     Pending   0          0s
web-2   0/1     Pending   0          0s
web-2   0/1     Pending   0          1s
web-2   0/1     ContainerCreating   0          1s
web-2   1/1     Running             0          3s
web-3   0/1     Pending             0          0s
web-3   0/1     Pending             0          0s
web-3   0/1     Pending             0          1s
web-3   0/1     ContainerCreating   0          1s
web-3   1/1     Running             0          2s
web-4   0/1     Pending             0          0s
web-4   0/1     Pending             0          0s
web-4   0/1     Pending             0          1s
web-4   0/1     ContainerCreating   0          1s
web-4   1/1     Running             0          3s

   縮容

  在一個終端觀察 StatefulSet 的 Pod。

kubectl get pods -w -l app=nginx

   在另一個終端使用 kubectl patch 將 StatefulSet 縮容回三個副本。

kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched

   等待 web-4 和 web-3 狀態變為 Terminating。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          9m49s
web-1   1/1     Running   0          9m44s
web-2   1/1     Running   0          2m37s
web-3   1/1     Running   0          9s
web-4   1/1     Running   0          8s
web-4   1/1     Terminating   0          52s
web-4   0/1     Terminating   0          53s
web-4   0/1     Terminating   0          59s
web-4   0/1     Terminating   0          59s
web-3   1/1     Terminating   0          60s
web-3   0/1     Terminating   0          61s
web-3   0/1     Terminating   0          65s
web-3   0/1     Terminating   0          65s

   順序終止Pod

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

  獲取 StatefulSet 的 PersistentVolumeClaims。

kubectl get pvc -l app=nginx
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
www-web-0   Bound    pvc-bbc399de-fac4-4f10-bd77-fc40fbf949a9   1Gi        RWO            managed-nfs-storage   151m
www-web-1   Bound    pvc-4d147825-2087-41d8-8fc1-a174de4c3bf6   1Gi        RWO            managed-nfs-storage   151m
www-web-2   Bound    pvc-28fb3584-78ce-44a3-9523-6e89907cb9fc   1Gi        RWO            managed-nfs-storage   5m22s
www-web-3   Bound    pvc-256cfeec-46d5-4b35-9357-acd12ef8ee9c   1Gi        RWO            managed-nfs-storage   5m19s
www-web-4   Bound    pvc-26beab6f-852d-46fd-ac32-35632b1dc65e   1Gi        RWO            managed-nfs-storage   5m17s

   五個 PersistentVolumeClaims 和五個 PersistentVolumes 仍然存在。查看 Pod 的 穩定存儲,我們發現當刪除 StatefulSet 的 Pod 時,掛載到 StatefulSet 的 Pod 的 PersistentVolumes 不會被刪除。當這種刪除行為是由 StatefulSet 縮容引起時也是一樣的。

  更新StatefulSet

  Kubernetes1.7版本的StatefulSet控制器支持自動更新。更新策略有StatefulSet API Object的spec.updateSreategy字段決定。這個特性能夠用來更新一個StatefulSet中的Pod的container images,resource requests,limits和annotaions。RollingUpdate滾動更新是StatefulSet默認策略。

  Rolling Update 策略

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

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched (no change)

   因為默認的更新策略是RollingUpdate所以提示沒有修改

  在一個終端窗口中 patch web StatefulSet 來再次的改變容器鏡像。

kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx"}]'

   把鏡像值修改成nginx,該鏡像需要是可以下載的否則更新時會出現下載鏡像錯誤提示ErrImagePull可以通過命令查看是否更新

kubectl edit sts web

 

 

   在另一個終端監控 StatefulSet 中的 Pod。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS        RESTARTS   AGE
web-2   0/1     Pending             0          0s
web-2   0/1     Pending             0          0s
web-2   0/1     ContainerCreating   0          0s
web-2   1/1     Running             0          5s
web-1   1/1     Terminating         0          5s
web-1   0/1     Terminating         0          6s
web-1   0/1     Terminating         0          10s
web-1   0/1     Terminating         0          10s
web-1   0/1     Pending             0          0s
web-1   0/1     Pending             0          0s
web-1   0/1     ContainerCreating   0          0s
web-1   1/1     Running             0          2s
web-0   1/1     Terminating         0          14s
web-0   0/1     Terminating         0          14s
web-0   0/1     Terminating         0          15s
web-0   0/1     Terminating         0          15s
web-0   0/1     Pending             0          0s
web-0   0/1     Pending             0          0s
web-0   0/1     ContainerCreating   0          0s
web-0   1/1     Running             0          1s

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

  獲取 Pod 來查看他們的容器鏡像。

for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
nginx
nginx
nginx

   小竅門:你還可以使用 kubectl rollout status sts/<name> 來查看 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}}}}'

   再次 Patch StatefulSet 來改變容器鏡像。

kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"lowyard/nginx-slim:0.8"}]'

   刪除 StatefulSet 中的 Pod。

kubectl delete pod web-2
pod "web-2" deleted

   等待 Pod 變成 Running 和 Ready。

  獲取Pod容器鏡像

kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
nginx

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

  灰度擴容

  把分段數改成2

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

   刪除web-2以后就使用新的鏡像更新了

kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
lowyard/nginx-slim:0.8

   當你改變 partition 時,StatefulSet 會自動的更新 web-2 Pod,這是因為 Pod 的序號小於或等於 partition

  刪除web-1等待running

kubectl delete pod web-1

   查看鏡像還是舊的鏡像

kubectl get pod web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
nginx

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

  分階段擴容

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

  分區當前為2。請將分區設置為0

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

   等待 StatefulSet 中的所有 Pod 變成 Running 和 Ready。

  獲取Pod的容器

for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
lowyard/nginx-slim:0.8
lowyard/nginx-slim:0.8
lowyard/nginx-slim:0.8

   PS:一般擴容都是整體擴容,分階段擴容用的較少,但在某些特定場合適用

  刪除StatefulSet

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

  非級聯刪除

  在一個終端窗口查看 StatefulSet 中的 Pod。

kubectl get pods -w -l app=nginx

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

kubectl delete statefulset web --cascade=false
statefulset.apps "web" deleted

   獲取pod狀態

# kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          3m41s
web-1   1/1     Running   0          3m46s
web-2   1/1     Running   0          7m51s
web-0   1/1     Running   0          4m36s
web-2   1/1     Running   0          8m46s
web-1   1/1     Running   0          4m41s

   雖然 web 已經被刪除了,但所有 Pod 仍然處於 Running 和 Ready 狀態。 刪除 web-0

kubectl delete pod web-0

   獲取 StatefulSet 的 Pod。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-1   1/1     Running   0          6m13s
web-2   1/1     Running   0          10m

   由於 web StatefulSet 已經被刪除,web-0沒有被重新啟動。

  在一個終端監控 StatefulSet 的 Pod。

kubectl get pods -w -l app=nginx

   在另一個終端里重新創建 StatefulSet。請注意,除非你刪除了 nginx Service (你不應該這樣做),你將會看到一個錯誤,提示 Service 已經存在。

kubectl apply -f web.yaml 
service/nginx unchanged
statefulset.apps/web created

   在第一個終端中運行並檢查 kubectl get 命令的輸出。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-1   1/1     Running   0          10m
web-2   1/1     Running   0          14m
web-1   1/1     Running   0          10m
web-2   1/1     Running   0          14m
web-0   0/1     Pending   0          0s
web-0   0/1     Pending   0          0s
web-0   0/1     ContainerCreating   0          0s
web-0   1/1     Running             0          1s
web-2   1/1     Terminating         0          14m
web-2   0/1     Terminating         0          14m
web-2   0/1     Terminating         0          14m
web-2   0/1     Terminating         0          14m
web-2   0/1     Terminating         0          14m

   當重新創建 web StatefulSet 時,web-0被第一個重新啟動。由於 web-1 已經處於 Running 和 Ready 狀態,當 web-0 變成 Running 和 Ready 時,StatefulSet 會直接接收這個 Pod。由於你重新創建的 StatefulSet 的 replicas 等於 2,一旦 web-0 被重新創建並且 web-1 被認為已經處於 Running 和 Ready 狀態時,web-2將會被終止。

  讓我們再看看被 Pod 的 web 服務器加載的 index.html 的內容。

for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1

   盡管你同時刪除了 StatefulSet 和 web-0 Pod,但它仍然使用最初寫入 index.html 文件的主機名進行服務。這是因為 StatefulSet 永遠不會刪除和一個 Pod 相關聯的 PersistentVolumes。當你重建這個 StatefulSet 並且重新啟動了 web-0 時,它原本的 PersistentVolume 會被重新掛載。

  級聯刪除

  在一個終端窗口觀察 StatefulSet 里的 Pod。

kubectl get pods -w -l app=nginx

   另一個窗口中再次刪除這個 StatefulSet。這次省略 --cascade=false 參數。

kubectl delete statefulset web
statefulset.apps "web" deleted

   在第一個終端檢查 kubectl get 命令的輸出,並等待所有的 Pod 變成 Terminating 狀態。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          114s
web-1   1/1     Running   0          12m
web-0   1/1     Terminating   0          2m30s
web-1   1/1     Terminating   0          12m
web-0   0/1     Terminating   0          2m31s
web-1   0/1     Terminating   0          12m
web-0   0/1     Terminating   0          2m32s
web-0   0/1     Terminating   0          2m32s

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

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

kubectl delete svc nginx
service "nginx" deleted

   再一次重新創建 StatefulSet 和 Headless Service。

kubectl apply -f web.yaml 
service/nginx created
statefulset.apps/web created

   當 StatefulSet 所有的 Pod 變成 Running 和 Ready 時,獲取它們的 index.html 文件的內容。

for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1

   即使你已經刪除了 StatefulSet 和它的全部 Pod,這些 Pod 將會被重新創建並掛載它們的 PersistentVolumes,並且 web-0 和 web-1 將仍然使用它們的主機名提供服務。

  Pod管理策略

  對於某些分布式系統來說,StatefulSet 的順序性保證是不必要和/或者不應該的。這些系統僅僅要求唯一性和身份標志。為了解決這個問題,在 Kubernetes 1.7 中我們針對 StatefulSet API Object 引入了 .spec.podManagementPolicy

  OrderedReady Pod 管理策略

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

  Parallel Pod 管理策略

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

# cat web-parallel.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"
  podManagementPolicy: "Parallel"
  replicas: 2 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        #image: k8s.gcr.io/nginx-slim:0.8
        image: lowyard/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: "managed-nfs-storage"
      resources:
        requests:
          storage: 1Gi

   這份清單和你在上文下載的完全一樣,只是 web StatefulSet 的 .spec.podManagementPolicy 設置成了 Parallel

  在另一個終端窗口創建清單中的 StatefulSet 和 Service。

kubectl apply -f web-parallel.yaml 
service/nginx created
statefulset.apps/web created

   查看你在第一個終端中運行的 kubectl get 命令的輸出。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   0/1     Pending   0          0s
web-1   0/1     Pending   0          0s
web-0   0/1     Pending   0          0s
web-1   0/1     Pending   0          0s
web-0   0/1     ContainerCreating   0          0s
web-1   0/1     ContainerCreating   0          0s
web-0   1/1     Running             0          1s
web-1   1/1     Running             0          2s

   StatefulSet 控制器同時啟動了 web-0 和 web-1

  保持第二個終端打開,並在另一個終端窗口中擴容 StatefulSet。

kubectl scale statefulset/web --replicas=4
statefulset.apps/web scaled

   在 kubectl get 命令運行的終端里檢查它的輸出。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   0/1     Pending   0          0s
web-1   0/1     Pending   0          0s
web-0   0/1     Pending   0          0s
web-1   0/1     Pending   0          0s
web-0   0/1     ContainerCreating   0          0s
web-1   0/1     ContainerCreating   0          0s
web-0   1/1     Running             0          1s
web-1   1/1     Running             0          2s
web-2   0/1     Pending             0          0s
web-3   0/1     Pending             0          0s
web-2   0/1     Pending             0          0s
web-3   0/1     Pending             0          0s
web-2   0/1     ContainerCreating   0          0s
web-3   0/1     ContainerCreating   0          0s
web-3   1/1     Running             0          1s
web-2   1/1     Running             0          2s

   StatefulSet 控制器啟動了兩個新的 Pod,而且在啟動第二個之前並沒有等待第一個變成 Running 和 Ready 狀態。

  保持這個終端打開,並在另一個終端刪除 web StatefulSet。

 kubectl delete sts web
statefulset.apps "web" deleted

   在另一個終端里再次檢查 kubectl get 命令的輸出。

kubectl get pods -w -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          2m33s
web-1   1/1     Running   0          2m33s
web-2   1/1     Running   0          91s
web-3   1/1     Running   0          91s
web-2   1/1     Terminating   0          98s
web-1   1/1     Terminating   0          2m40s
web-3   1/1     Terminating   0          98s
web-0   1/1     Terminating   0          2m40s
web-1   0/1     Terminating   0          2m41s
web-2   0/1     Terminating   0          99s
web-0   0/1     Terminating   0          2m42s
web-2   0/1     Terminating   0          100s
web-2   0/1     Terminating   0          100s
web-1   0/1     Terminating   0          2m42s
web-2   0/1     Terminating   0          100s
web-3   0/1     Terminating   0          100s
web-0   0/1     Terminating   0          2m48s
web-0   0/1     Terminating   0          2m48s
web-1   0/1     Terminating   0          2m53s
web-1   0/1     Terminating   0          2m53s
web-3   0/1     Terminating   0          111s
web-3   0/1     Terminating   0          111s

   StatefulSet 控制器將並發的刪除所有 Pod,在刪除一個 Pod 前不會等待它的順序后繼者終止。





  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM