StatefulSet 基礎概念
本教學課程簡介如何使用 StatefulSet 管理應用程式。它示範如何建立、刪除、擴展和更新 StatefulSet 的 Pod。
開始之前
在開始本教學課程之前,您應該熟悉以下 Kubernetes 概念:
您需要有一個 Kubernetes 叢集,並且 kubectl 命令列工具必須設定為與您的叢集通訊。建議在至少有兩個節點且未充當控制平面主機的叢集上執行本教學課程。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用這些 Kubernetes playground 之一:
您應該設定 kubectl
以使用預設命名空間的內容。如果您正在使用現有的叢集,請確保可以使用該叢集的預設命名空間進行練習。理想情況下,在未執行任何實際工作負載的叢集中練習。
閱讀關於 StatefulSet 的概念頁面也很有用。
註:
本教學課程假設您的叢集已設定為動態佈建 PersistentVolume。您還需要有一個預設 StorageClass。如果您的叢集未設定為動態佈建儲存空間,您將必須在本教學課程開始之前手動佈建兩個 1 GiB 磁碟區,並設定您的叢集,以便這些 PersistentVolume 對應到 StatefulSet 定義的 PersistentVolumeClaim 範本。目標
StatefulSet 旨在與有狀態應用程式和分散式系統一起使用。然而,在 Kubernetes 上管理有狀態應用程式和分散式系統是一個廣泛而複雜的主題。為了示範 StatefulSet 的基本功能,而不是將前一個主題與後一個主題混淆,您將使用 StatefulSet 部署一個簡單的 Web 應用程式。
完成本教學課程後,您將熟悉以下內容。
- 如何建立 StatefulSet
- StatefulSet 如何管理其 Pod
- 如何刪除 StatefulSet
- 如何擴展 StatefulSet
- 如何更新 StatefulSet 的 Pod
建立 StatefulSet
首先,使用以下範例建立 StatefulSet(以及它所依賴的 Service)。它與 StatefulSet 概念中呈現的範例相似。它建立一個無頭服務 nginx
,以發佈 StatefulSet web
中 Pod 的 IP 位址。
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: registry.k8s.io/nginx-slim:0.21
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
您將需要使用至少兩個終端機視窗。在第一個終端機中,使用 kubectl get
來監看 StatefulSet 的 Pod 建立。
# use this terminal to run commands that specify --watch
# end this watch when you are asked to start a new watch
kubectl get pods --watch -l app=nginx
在第二個終端機中,使用 kubectl apply
來建立無頭服務和 StatefulSet
kubectl apply -f https://k8s.io/examples/application/web/web.yaml
service/nginx created
statefulset.apps/web created
上述命令會建立兩個 Pod,每個 Pod 都執行一個 NGINX Web 伺服器。取得 nginx
服務...
kubectl get service nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None <none> 80/TCP 12s
...然後取得 web
StatefulSet,以驗證兩者都已成功建立
kubectl get statefulset web
NAME READY AGE
web 2/2 37s
有序 Pod 建立
StatefulSet 預設以嚴格的順序建立其 Pod。
對於具有 n 個副本的 StatefulSet,當部署 Pod 時,它們會依序建立,順序從 {0..n-1}。檢查第一個終端機中 kubectl get
命令的輸出。最終,輸出將如下面的範例所示。
# Do not start a new watch;
# this should already be running
kubectl get pods --watch -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 ContainerCreating 0 0s
web-0 1/1 Running 0 19s
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 18s
請注意,web-1
Pod 要等到 web-0
Pod 處於執行中 (參閱Pod Phase) 和就緒 (參閱 Pod Conditions 中的 type
) 狀態才會啟動。
在本教學稍後的章節,您將練習平行啟動。
註:
若要設定指派給 StatefulSet 中每個 Pod 的整數序號,請參閱起始序號。StatefulSet 中的 Pod
StatefulSet 中的 Pod 具有唯一的序號索引和穩定的網路身分。
檢查 Pod 的序號索引
取得 StatefulSet 的 Pod
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 1m
web-1 1/1 Running 0 1m
如 StatefulSets 概念中所述,StatefulSet 中的 Pod 具有黏性的唯一身分。此身分基於由 StatefulSet 控制器 指派給每個 Pod 的唯一序號索引。
Pod 的名稱採用 <statefulset 名稱>-<序號索引>
的形式。由於 web
StatefulSet 有兩個副本,因此它會建立兩個 Pod,web-0
和 web-1
。
使用穩定的網路身分
每個 Pod 都有一個基於其序號索引的穩定主機名稱。使用 kubectl exec
在每個 Pod 中執行 hostname
命令
for i in 0 1; do kubectl exec "web-$i" -- sh -c 'hostname'; done
web-0
web-1
使用 kubectl run
執行一個容器,該容器從 dnsutils
套件提供 nslookup
命令。在 Pod 的主機名稱上使用 nslookup
,您可以檢查它們在叢集內的 DNS 位址
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm
這會啟動一個新的 shell。在新的 shell 中,執行
# Run this in the dns-test container shell
nslookup web-0.nginx
輸出結果類似於
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-0.nginx
Address 1: 10.244.1.6
nslookup web-1.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-1.nginx
Address 1: 10.244.2.6
(現在退出容器 shell:exit
)
無頭服務的 CNAME 指向 SRV 記錄 (每個執行中且就緒的 Pod 各有一個)。SRV 記錄指向包含 Pod IP 位址的 A 記錄項目。
在一個終端機中,監看 StatefulSet 的 Pod
# Start a new watch
# End this watch when you've seen that the delete is finished
kubectl get pod --watch -l app=nginx
在第二個終端機中,使用 kubectl delete
刪除 StatefulSet 中的所有 Pod
kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted
等待 StatefulSet 重新啟動它們,並等待兩個 Pod 都轉換為執行中和就緒狀態
# This should already be running
kubectl get pod --watch -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2s
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 34s
使用 kubectl exec
和 kubectl run
檢視 Pod 的主機名稱和叢集內 DNS 項目。首先,檢視 Pod 的主機名稱
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1
然後,執行
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm
這會啟動一個新的 shell。
在新的 shell 中,執行
# Run this in the dns-test container shell
nslookup web-0.nginx
輸出結果類似於
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-0.nginx
Address 1: 10.244.1.7
nslookup web-1.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: web-1.nginx
Address 1: 10.244.2.8
(現在退出容器 shell:exit
)
Pod 的序號、主機名稱、SRV 記錄和 A 記錄名稱沒有改變,但與 Pod 相關聯的 IP 位址可能已變更。在本教學中使用的叢集中,它們已經變更。這就是為什麼重要的是不要將其他應用程式設定為透過特定 Pod 的 IP 位址連接到 StatefulSet 中的 Pod (透過解析其主機名稱連接到 Pod 是可以的)。
探索 StatefulSet 中特定的 Pod
如果您需要尋找並連接到 StatefulSet 的作用中成員,您應該查詢無頭服務的 CNAME (nginx.default.svc.cluster.local
)。與 CNAME 相關聯的 SRV 記錄將僅包含 StatefulSet 中處於執行中和就緒狀態的 Pod。
如果您的應用程式已經實作了測試活性和就緒性的連線邏輯,則可以使用 Pod 的 SRV 記錄 (web-0.nginx.default.svc.cluster.local
、web-1.nginx.default.svc.cluster.local
),因為它們是穩定的,並且您的應用程式將能夠在 Pod 轉換為執行中和就緒狀態時探索到 Pod 的位址。
如果您的應用程式想要尋找 StatefulSet 中任何健康的 Pod,因此不需要追蹤每個特定的 Pod,您也可以連接到由該 StatefulSet 中的 Pod 支援的 type: ClusterIP
服務的 IP 位址。您可以使用追蹤 StatefulSet 的同一個服務 (在 StatefulSet 的 serviceName
中指定) 或選擇正確 Pod 集合的另一個服務。
寫入穩定儲存空間
取得 web-0
和 web-1
的 PersistentVolumeClaims
kubectl get pvc -l app=nginx
輸出結果類似於
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 48s
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 48s
StatefulSet 控制器建立了兩個 PersistentVolumeClaims,它們綁定到兩個 PersistentVolumes。
由於本教學中使用的叢集配置為動態佈建 PersistentVolumes,因此 PersistentVolumes 會自動建立和綁定。
NGINX 網頁伺服器預設從 /usr/share/nginx/html/index.html
提供索引檔案。StatefulSet spec
中的 volumeMounts
欄位確保 /usr/share/nginx/html
目錄由 PersistentVolume 支援。
將 Pod 的主機名稱寫入其 index.html
檔案,並驗證 NGINX 網頁伺服器是否提供主機名稱
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 -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1
註:
如果您看到上述 curl 命令的 403 Forbidden 回應,您將需要修正 volumeMounts
掛載的目錄權限 (由於使用 hostPath 磁碟區時的錯誤),方法是執行
for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done
然後再重試上面的 curl
命令。
在一個終端機中,監看 StatefulSet 的 Pod
# End this watch when you've reached the end of the section.
# At the start of "Scaling a StatefulSet" you'll start a new watch.
kubectl get pod --watch -l app=nginx
在第二個終端機中,刪除 StatefulSet 的所有 Pod
kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted
檢查第一個終端機中 kubectl get
命令的輸出,並等待所有 Pod 都轉換為執行中和就緒狀態。
# This should already be running
kubectl get pod --watch -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2s
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 34s
驗證網頁伺服器是否繼續提供其主機名稱
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1
即使 web-0
和 web-1
被重新排程,它們仍然繼續提供其主機名稱,因為與其 PersistentVolumeClaims 相關聯的 PersistentVolumes 會重新掛載到其 volumeMounts
。無論 web-0
和 web-1
排程在哪個節點上,它們的 PersistentVolumes 都將掛載到適當的掛載點。
擴展 StatefulSet
擴展 StatefulSet 是指增加或減少副本數量 (水平擴展)。這是透過更新 replicas
欄位來完成的。您可以使用 kubectl scale
或 kubectl patch
來擴展 StatefulSet。
向上擴展
向上擴展表示新增更多副本。前提是您的應用程式能夠在 StatefulSet 中分配工作,新的較大 Pod 集合可以執行更多該工作。
在一個終端機視窗中,監看 StatefulSet 中的 Pod
# If you already have a watch running, you can continue using that.
# Otherwise, start one.
# End this watch when there are 5 healthy Pods for the StatefulSet
kubectl get pods --watch -l app=nginx
在另一個終端機視窗中,使用 kubectl scale
將副本數量擴展到 5
kubectl scale sts web --replicas=5
statefulset.apps/web scaled
檢查第一個終端機中 kubectl get
命令的輸出,並等待另外三個 Pod 轉換為執行中和就緒狀態。
# This should already be running
kubectl get pod --watch -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2h
web-1 1/1 Running 0 2h
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 19s
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 0s
web-3 0/1 ContainerCreating 0 0s
web-3 1/1 Running 0 18s
web-4 0/1 Pending 0 0s
web-4 0/1 Pending 0 0s
web-4 0/1 ContainerCreating 0 0s
web-4 1/1 Running 0 19s
StatefulSet 控制器擴展了副本數量。與 StatefulSet 建立 一樣,StatefulSet 控制器依序建立每個 Pod,並針對其序號索引,並且在啟動後續 Pod 之前,等待每個 Pod 的前導者處於執行中和就緒狀態。
向下擴展
向下擴展表示減少副本數量。例如,您可能會因為服務的流量水平降低,並且在目前規模下存在閒置資源而執行此操作。
在一個終端機中,監看 StatefulSet 的 Pod
# End this watch when there are only 3 Pods for the StatefulSet
kubectl get pod --watch -l app=nginx
在另一個終端機中,使用 kubectl patch
將 StatefulSet 向下擴展回三個副本
kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched
等待 web-4
和 web-3
轉換為 Terminating 狀態。
# This should already be running
kubectl get pods --watch -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3h
web-1 1/1 Running 0 3h
web-2 1/1 Running 0 55s
web-3 1/1 Running 0 36s
web-4 0/1 ContainerCreating 0 18s
NAME READY STATUS RESTARTS AGE
web-4 1/1 Running 0 19s
web-4 1/1 Terminating 0 24s
web-4 1/1 Terminating 0 24s
web-3 1/1 Terminating 0 42s
web-3 1/1 Terminating 0 42s
有序 Pod 終止
控制平面一次刪除一個 Pod,順序與其序號索引相反,並且在刪除下一個 Pod 之前,等待每個 Pod 完全關閉。
取得 StatefulSet 的 PersistentVolumeClaims
kubectl get pvc -l app=nginx
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 13h
www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 13h
www-web-2 Bound pvc-e1125b27-b508-11e6-932f-42010a800002 1Gi RWO 13h
www-web-3 Bound pvc-e1176df6-b508-11e6-932f-42010a800002 1Gi RWO 13h
www-web-4 Bound pvc-e11bb5f8-b508-11e6-932f-42010a800002 1Gi RWO 13h
仍然有五個 PersistentVolumeClaims 和五個 PersistentVolumes。在探索 Pod 的 穩定儲存空間 時,您看到當 StatefulSet 的 Pod 被刪除時,掛載到 StatefulSet Pod 的 PersistentVolumes 不會被刪除。當 Pod 刪除是由於向下擴展 StatefulSet 引起時,情況仍然如此。
更新 StatefulSets
StatefulSet 控制器支援自動更新。使用的策略由 StatefulSet API 物件的 spec.updateStrategy
欄位決定。此功能可用於升級 StatefulSet 中 Pod 的容器映像、資源請求和/或限制、標籤和註解。
有兩種有效的更新策略,RollingUpdate
(預設) 和 OnDelete
。
RollingUpdate
RollingUpdate
更新策略將更新 StatefulSet 中的所有 Pod,以相反的序號順序,同時尊重 StatefulSet 保證。
您可以透過指定 .spec.updateStrategy.rollingUpdate.partition
,將使用 RollingUpdate
策略的 StatefulSet 更新拆分為分割區。您將在本教學稍後練習。
首先,嘗試簡單的滾動更新。
在一個終端機視窗中,修補 web
StatefulSet 以再次變更容器映像
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"registry.k8s.io/nginx-slim:0.24"}]'
statefulset.apps/web patched
在另一個終端機中,監看 StatefulSet 中的 Pod
# End this watch when the rollout is complete
#
# If you're not sure, leave it running one more minute
kubectl get pod -l app=nginx --watch
輸出結果類似於
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 7m
web-1 1/1 Running 0 7m
web-2 1/1 Running 0 8m
web-2 1/1 Terminating 0 8m
web-2 1/1 Terminating 0 8m
web-2 0/1 Terminating 0 8m
web-2 0/1 Terminating 0 8m
web-2 0/1 Terminating 0 8m
web-2 0/1 Terminating 0 8m
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 19s
web-1 1/1 Terminating 0 8m
web-1 0/1 Terminating 0 8m
web-1 0/1 Terminating 0 8m
web-1 0/1 Terminating 0 8m
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 6s
web-0 1/1 Terminating 0 7m
web-0 1/1 Terminating 0 7m
web-0 0/1 Terminating 0 7m
web-0 0/1 Terminating 0 7m
web-0 0/1 Terminating 0 7m
web-0 0/1 Terminating 0 7m
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 10s
StatefulSet 中的 Pod 以相反的序號順序更新。StatefulSet 控制器終止每個 Pod,並等待它轉換為執行中和就緒狀態,然後再更新下一個 Pod。請注意,即使 StatefulSet 控制器在序號後繼者處於執行中和就緒狀態之前不會繼續更新下一個 Pod,它也會將更新期間失敗的任何 Pod 還原到該 Pod 的現有版本。
已接收更新的 Pod 將還原到更新後的版本,而尚未接收更新的 Pod 將還原到先前的版本。透過這種方式,控制器嘗試在間歇性故障的情況下繼續保持應用程式健康,並保持更新一致。
取得 Pod 以檢視其容器映像
for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
registry.k8s.io/nginx-slim:0.24
registry.k8s.io/nginx-slim:0.24
registry.k8s.io/nginx-slim:0.24
StatefulSet 中的所有 Pod 現在都執行先前的容器映像。
註:
您也可以使用kubectl rollout status sts/<name>
檢視 StatefulSet 滾動更新的狀態暫存更新
您可以透過指定 .spec.updateStrategy.rollingUpdate.partition
,將使用 RollingUpdate
策略的 StatefulSet 更新拆分為分割區。
如需更多背景資訊,您可以閱讀 StatefulSet 概念頁面中的 分割區滾動更新。
您可以使用 .spec.updateStrategy.rollingUpdate
中的 partition
欄位來暫存 StatefulSet 的更新。對於此更新,您將保持 StatefulSet 中現有的 Pod 不變,同時變更 StatefulSet 的 Pod 範本。然後,您 - 或在教學之外的某些外部自動化 - 可以觸發該準備好的更新。
首先,修補 web
StatefulSet 以將分割區新增至 updateStrategy
欄位
# The value of "partition" determines which ordinals a change applies to
# Make sure to use a number bigger than the last ordinal for the
# StatefulSet
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset.apps/web patched
再次修補 StatefulSet 以變更此 StatefulSet 使用的容器映像
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"registry.k8s.io/nginx-slim:0.21"}]'
statefulset.apps/web patched
刪除 StatefulSet 中的一個 Pod
kubectl delete pod web-2
pod "web-2" deleted
等待替換的 web-2
Pod 處於執行中和就緒狀態
# End the watch when you see that web-2 is healthy
kubectl get pod -l app=nginx --watch
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 4m
web-1 1/1 Running 0 4m
web-2 0/1 ContainerCreating 0 11s
web-2 1/1 Running 0 18s
取得 Pod 的容器映像
kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
registry.k8s.io/nginx-slim:0.24
請注意,即使更新策略是 RollingUpdate
,StatefulSet 仍使用原始容器映像還原了 Pod。這是因為 Pod 的序號小於 updateStrategy
指定的 partition
。
推出金絲雀
您現在將嘗試該暫存變更的 金絲雀發布。
您可以透過遞減您在 上方 指定的 partition
來推出金絲雀 (以測試修改後的範本)。
修補 StatefulSet 以遞減分割區
# The value of "partition" should match the highest existing ordinal for
# the StatefulSet
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
statefulset.apps/web patched
控制平面觸發 web-2
的替換 (透過優雅的 delete 實作,然後在刪除完成後建立新的 Pod)。等待新的 web-2
Pod 處於執行中和就緒狀態。
# This should already be running
kubectl get pod -l app=nginx --watch
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 4m
web-1 1/1 Running 0 4m
web-2 0/1 ContainerCreating 0 11s
web-2 1/1 Running 0 18s
取得 Pod 的容器
kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
registry.k8s.io/nginx-slim:0.21
當您變更 partition
時,StatefulSet 控制器會自動更新 web-2
Pod,因為 Pod 的序號大於或等於 partition
。
刪除 web-1
Pod
kubectl delete pod web-1
pod "web-1" deleted
等待 web-1
Pod 處於執行中和就緒狀態。
# This should already be running
kubectl get pod -l app=nginx --watch
輸出結果類似於
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m
web-1 0/1 Terminating 0 6m
web-2 1/1 Running 0 2m
web-1 0/1 Terminating 0 6m
web-1 0/1 Terminating 0 6m
web-1 0/1 Terminating 0 6m
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 18s
取得 web-1
Pod 的容器映像
kubectl get pod web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
registry.k8s.io/nginx-slim:0.24
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 都變成執行中和就緒狀態。
# This should already be running
kubectl get pod -l app=nginx --watch
輸出結果類似於
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3m
web-1 0/1 ContainerCreating 0 11s
web-2 1/1 Running 0 2m
web-1 1/1 Running 0 18s
web-0 1/1 Terminating 0 3m
web-0 1/1 Terminating 0 3m
web-0 0/1 Terminating 0 3m
web-0 0/1 Terminating 0 3m
web-0 0/1 Terminating 0 3m
web-0 0/1 Terminating 0 3m
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 3s
取得 StatefulSet 中 Pod 的容器映像詳細資訊
for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
registry.k8s.io/nginx-slim:0.21
registry.k8s.io/nginx-slim:0.21
registry.k8s.io/nginx-slim:0.21
透過將 partition
移動到 0
,您允許 StatefulSet 繼續更新程序。
OnDelete
您可以透過將 .spec.template.updateStrategy.type
設定為 OnDelete
來為 StatefulSet 選擇此更新策略。
修補 web
StatefulSet 以使用 OnDelete
更新策略
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"OnDelete"}}}'
statefulset.apps/web patched
當您選擇此更新策略時,當 StatefulSet 的 .spec.template
欄位被修改時,StatefulSet 控制器不會自動更新 Pod。您需要自行管理發布 - 手動或使用個別的自動化。
刪除 StatefulSets
StatefulSet 支援非級聯和級聯刪除。在非級聯 delete 中,當 StatefulSet 被刪除時,StatefulSet 的 Pod 不會被刪除。在級聯 delete 中,StatefulSet 及其 Pod 都會被刪除。
閱讀 在叢集中使用級聯刪除 以大致了解級聯刪除。
非級聯刪除
在一個終端機視窗中,監看 StatefulSet 中的 Pod。
# End this watch when there are no Pods for the StatefulSet
kubectl get pods --watch -l app=nginx
使用 kubectl delete
刪除 StatefulSet。請務必提供 --cascade=orphan
參數給指令。此參數會告知 Kubernetes 只刪除 StatefulSet,而不要刪除其任何 Pod。
kubectl delete statefulset web --cascade=orphan
statefulset.apps "web" deleted
取得 Pod,以檢查其狀態
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m
web-1 1/1 Running 0 7m
web-2 1/1 Running 0 5m
即使 web
已被刪除,所有 Pod 仍然處於「執行中」和「就緒」狀態。刪除 web-0
kubectl delete pod web-0
pod "web-0" deleted
取得 StatefulSet 的 Pod
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-1 1/1 Running 0 10m
web-2 1/1 Running 0 7m
由於 web
StatefulSet 已被刪除,因此 web-0
未被重新啟動。
在一個終端機中,監看 StatefulSet 的 Pod。
# Leave this watch running until the next time you start a watch
kubectl get pods --watch -l app=nginx
在第二個終端機中,重新建立 StatefulSet。請注意,除非您刪除了 nginx
Service(您不應該這樣做),否則您會看到一個錯誤,指出 Service 已存在。
kubectl apply -f https://k8s.io/examples/application/web/web.yaml
statefulset.apps/web created
service/nginx unchanged
忽略此錯誤。它僅表示嘗試建立 nginx 無頭 Service,即使該 Service 已存在。
檢查在第一個終端機中執行的 kubectl get
指令的輸出。
# This should already be running
kubectl get pods --watch -l app=nginx
NAME READY STATUS RESTARTS AGE
web-1 1/1 Running 0 16m
web-2 1/1 Running 0 2m
NAME READY STATUS RESTARTS AGE
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 18s
web-2 1/1 Terminating 0 3m
web-2 0/1 Terminating 0 3m
web-2 0/1 Terminating 0 3m
web-2 0/1 Terminating 0 3m
當 web
StatefulSet 被重新建立時,它首先重新啟動了 web-0
。由於 web-1
已經處於「執行中」和「就緒」狀態,當 web-0
轉換為「執行中」和「就緒」時,它採用了這個 Pod。由於您使用等於 2 的 replicas
重新建立了 StatefulSet,一旦 web-0
被重新建立,並且一旦 web-1
被確定已處於「執行中」和「就緒」狀態,web-2
就會被終止。
現在再次查看 Pod 的網頁伺服器所提供的 index.html
檔案內容
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1
即使您刪除了 StatefulSet 和 web-0
Pod,它仍然提供最初輸入到其 index.html
檔案中的主機名稱。這是因為 StatefulSet 永遠不會刪除與 Pod 關聯的 PersistentVolume。當您重新建立 StatefulSet 並重新啟動 web-0
時,其原始 PersistentVolume 會被重新掛載。
串聯刪除
在一個終端機視窗中,監看 StatefulSet 中的 Pod。
# Leave this running until the next page section
kubectl get pods --watch -l app=nginx
在另一個終端機中,再次刪除 StatefulSet。這次,省略 --cascade=orphan
參數。
kubectl delete statefulset web
statefulset.apps "web" deleted
檢查在第一個終端機中執行的 kubectl get
指令的輸出,並等待所有 Pod 轉換為「終止中」。
# This should already be running
kubectl get pods --watch -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 11m
web-1 1/1 Running 0 27m
NAME READY STATUS RESTARTS AGE
web-0 1/1 Terminating 0 12m
web-1 1/1 Terminating 0 29m
web-0 0/1 Terminating 0 12m
web-0 0/1 Terminating 0 12m
web-0 0/1 Terminating 0 12m
web-1 0/1 Terminating 0 29m
web-1 0/1 Terminating 0 29m
web-1 0/1 Terminating 0 29m
正如您在縮減規模章節中所看到的,Pod 會依序終止,順序與其序數索引相反。在終止 Pod 之前,StatefulSet 控制器會等待該 Pod 的後繼者完全終止。
註:
雖然串聯刪除會移除 StatefulSet 及其 Pod,但串聯刪除不會刪除與 StatefulSet 關聯的無頭 Service。您必須手動刪除nginx
Service。kubectl delete service nginx
service "nginx" deleted
再次重新建立 StatefulSet 和無頭 Service
kubectl apply -f https://k8s.io/examples/application/web/web.yaml
service/nginx created
statefulset.apps/web created
當所有 StatefulSet 的 Pod 轉換為「執行中」和「就緒」時,檢索其 index.html
檔案的內容
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1
即使您完全刪除了 StatefulSet 及其所有 Pod,重新建立的 Pod 仍會掛載其 PersistentVolume,而 web-0
和 web-1
繼續提供其主機名稱。
最後,刪除 nginx
Service...
kubectl delete service nginx
service "nginx" deleted
...以及 web
StatefulSet
kubectl delete statefulset web
statefulset "web" deleted
Pod 管理策略
對於某些分散式系統,StatefulSet 的排序保證是不必要和/或不受歡迎的。這些系統僅需要唯一性和身分。
您可以指定Pod 管理策略來避免這種嚴格的排序;可以是 OrderedReady
(預設值)或 Parallel
。
OrderedReady Pod 管理
OrderedReady
Pod 管理是 StatefulSet 的預設值。它告訴 StatefulSet 控制器要遵守上面示範的排序保證。
當您的應用程式需要或期望變更(例如,推出新版本的應用程式)按照 StatefulSet 提供的序數(Pod 號碼)的嚴格順序發生時,請使用此選項。換句話說,如果您有 Pod app-0
、app-1
和 app-2
,Kubernetes 會先更新 app-0
並檢查它。一旦檢查通過,Kubernetes 會更新 app-1
,最後更新 app-2
。
如果您新增了兩個以上的 Pod,Kubernetes 會設定 app-3
並等待其變成健康狀態,然後再部署 app-4
。
由於這是預設設定,您已經練習過使用它。
Parallel Pod 管理
另一種選擇 Parallel
Pod 管理,告訴 StatefulSet 控制器並行啟動或終止所有 Pod,而無需等待 Pod 變成 Running
和 Ready
狀態,或在啟動或終止另一個 Pod 之前完全終止。
Parallel
Pod 管理選項僅影響擴展操作的行為。更新不受影響;Kubernetes 仍然依序推出變更。在本教學中,應用程式非常簡單:一個網頁伺服器告訴您它的主機名稱(因為這是 StatefulSet,所以每個 Pod 的主機名稱都不同且可預測)。
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: registry.k8s.io/nginx-slim:0.24
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
此 Manifest 與您上面下載的 Manifest 相同,不同之處在於 web
StatefulSet 的 .spec.podManagementPolicy
設定為 Parallel
。
在一個終端機中,監看 StatefulSet 中的 Pod。
# Leave this watch running until the end of the section
kubectl get pod -l app=nginx --watch
在另一個終端機中,將 StatefulSet 重新配置為 Parallel
Pod 管理
kubectl apply -f https://k8s.io/examples/application/web/web-parallel.yaml
service/nginx updated
statefulset.apps/web updated
保持您正在執行監看的終端機開啟。在另一個終端機視窗中,擴展 StatefulSet
kubectl scale statefulset/web --replicas=5
statefulset.apps/web scaled
檢查執行 kubectl get
指令的終端機的輸出。它可能看起來像這樣
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 0s
web-3 0/1 Pending 0 7s
web-3 0/1 ContainerCreating 0 7s
web-2 0/1 Pending 0 0s
web-4 0/1 Pending 0 0s
web-2 1/1 Running 0 8s
web-4 0/1 ContainerCreating 0 4s
web-3 1/1 Running 0 26s
web-4 1/1 Running 0 2s
StatefulSet 啟動了三個新的 Pod,並且它沒有等待第一個 Pod 變成「執行中」和「就緒」狀態,才啟動第二個和第三個 Pod。
如果您的工作負載具有狀態元件,或需要 Pod 能夠以可預測的命名方式互相識別,尤其是在您有時需要快速提供更多容量的情況下,這種方法非常有用。如果本教學的簡單網頁服務突然每分鐘收到額外 1,000,000 個請求,那麼您會想要執行更多 Pod - 但您也不想等待每個新的 Pod 啟動。並行啟動額外的 Pod 可以縮短請求額外容量與使其可供使用之間的時間。
清理
您應該開啟兩個終端機,準備好執行 kubectl
指令作為清理的一部分。
kubectl delete sts web
# sts is an abbreviation for statefulset
您可以監看 kubectl get
以查看這些 Pod 被刪除。
# end the watch when you've seen what you need to
kubectl get pod -l app=nginx --watch
web-3 1/1 Terminating 0 9m
web-2 1/1 Terminating 0 9m
web-3 1/1 Terminating 0 9m
web-2 1/1 Terminating 0 9m
web-1 1/1 Terminating 0 44m
web-0 1/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-3 0/1 Terminating 0 9m
web-2 0/1 Terminating 0 9m
web-1 0/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-2 0/1 Terminating 0 9m
web-2 0/1 Terminating 0 9m
web-2 0/1 Terminating 0 9m
web-1 0/1 Terminating 0 44m
web-1 0/1 Terminating 0 44m
web-1 0/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-0 0/1 Terminating 0 44m
web-3 0/1 Terminating 0 9m
web-3 0/1 Terminating 0 9m
web-3 0/1 Terminating 0 9m
在刪除期間,StatefulSet 會同時移除所有 Pod;它不會等待 Pod 的序數後繼者終止,才刪除該 Pod。
關閉執行 kubectl get
指令的終端機,並刪除 nginx
Service
kubectl delete svc nginx
刪除本教學中使用的 PersistentVolume 的永久儲存媒體。
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pvc-2bf00408-d366-4a12-bad0-1869c65d0bee 1Gi RWO standard 25m
www-web-1 Bound pvc-ba3bfe9c-413e-4b95-a2c0-3ea8a54dbab4 1Gi RWO standard 24m
www-web-2 Bound pvc-cba6cfa6-3a47-486b-a138-db5930207eaf 1Gi RWO standard 15m
www-web-3 Bound pvc-0c04d7f0-787a-4977-8da3-d9d3a6d8d752 1Gi RWO standard 15m
www-web-4 Bound pvc-b2c73489-e70b-4a4e-9ec1-9eab439aa43e 1Gi RWO standard 14m
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-0c04d7f0-787a-4977-8da3-d9d3a6d8d752 1Gi RWO Delete Bound default/www-web-3 standard 15m
pvc-2bf00408-d366-4a12-bad0-1869c65d0bee 1Gi RWO Delete Bound default/www-web-0 standard 25m
pvc-b2c73489-e70b-4a4e-9ec1-9eab439aa43e 1Gi RWO Delete Bound default/www-web-4 standard 14m
pvc-ba3bfe9c-413e-4b95-a2c0-3ea8a54dbab4 1Gi RWO Delete Bound default/www-web-1 standard 24m
pvc-cba6cfa6-3a47-486b-a138-db5930207eaf 1Gi RWO Delete Bound default/www-web-2 standard 15m
kubectl delete pvc www-web-0 www-web-1 www-web-2 www-web-3 www-web-4
persistentvolumeclaim "www-web-0" deleted
persistentvolumeclaim "www-web-1" deleted
persistentvolumeclaim "www-web-2" deleted
persistentvolumeclaim "www-web-3" deleted
persistentvolumeclaim "www-web-4" deleted
kubectl get pvc
No resources found in default namespace.