新聞中心
StatefulSet 基礎(chǔ)
本教程介紹了如何使用 StatefulSet 來(lái)管理應(yīng)用。 演示了如何創(chuàng)建、刪除、擴(kuò)容/縮容和更新 StatefulSet 的 Pod。

創(chuàng)新互聯(lián)主打移動(dòng)網(wǎng)站、成都網(wǎng)站制作、做網(wǎng)站、網(wǎng)站改版、網(wǎng)絡(luò)推廣、網(wǎng)站維護(hù)、國(guó)際域名空間、等互聯(lián)網(wǎng)信息服務(wù),為各行業(yè)提供服務(wù)。在技術(shù)實(shí)力的保障下,我們?yōu)榭蛻舫兄Z穩(wěn)定,放心的服務(wù),根據(jù)網(wǎng)站的內(nèi)容與功能再?zèng)Q定采用什么樣的設(shè)計(jì)。最后,要實(shí)現(xiàn)符合網(wǎng)站需求的內(nèi)容、功能與設(shè)計(jì),我們還會(huì)規(guī)劃穩(wěn)定安全的技術(shù)方案做保障。
在開(kāi)始之前
在開(kāi)始本教程之前,你應(yīng)該熟悉以下 Kubernetes 的概念:
- Pods
- Cluster DNS
- Headless Services
- PersistentVolumes
- PersistentVolume Provisioning
- StatefulSets
- kubectl 命令行工具
說(shuō)明:
本教程假設(shè)你的集群被配置為動(dòng)態(tài)制備 PersistentVolume 卷。 如果沒(méi)有這樣配置,在開(kāi)始本教程之前,你需要手動(dòng)準(zhǔn)備 2 個(gè) 1 GiB 的存儲(chǔ)卷。
教程目標(biāo)
StatefulSet 旨在與有狀態(tài)的應(yīng)用及分布式系統(tǒng)一起使用。然而在 Kubernetes 上管理有狀態(tài)應(yīng)用和分布式系統(tǒng)是一個(gè)寬泛而復(fù)雜的話題。 為了演示 StatefulSet 的基本特性,并且不使前后的主題混淆,你將會(huì)使用 StatefulSet 部署一個(gè)簡(jiǎn)單的 web 應(yīng)用。
在閱讀本教程后,你將熟悉以下內(nèi)容:
- 如何創(chuàng)建 StatefulSet
- StatefulSet 怎樣管理它的 Pod
- 如何刪除 StatefulSet
- 如何對(duì) StatefulSet 進(jìn)行擴(kuò)容/縮容
- 如何更新一個(gè) StatefulSet 的 Pod
創(chuàng)建 StatefulSet
作為開(kāi)始,使用如下示例創(chuàng)建一個(gè) StatefulSet。它和 StatefulSet 概念中的示例相似。 它創(chuàng)建了一個(gè) Headless Service ?nginx ?用來(lái)發(fā)布 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: 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.yaml?。
你需要使用兩個(gè)終端窗口。在第一個(gè)終端中,使用 ?kubectl get? 來(lái)監(jiān)視 StatefulSet 的 Pod 的創(chuàng)建情況。
kubectl get pods -w -l app=nginx
在另一個(gè)終端中,使用 ?kubectl apply? 來(lái)創(chuàng)建定義在 ?web.yaml? 中的 Headless Service 和 StatefulSet。
kubectl apply -f web.yaml
service/nginx created
statefulset.apps/web created上面的命令創(chuàng)建了兩個(gè) Pod,每個(gè)都運(yùn)行了一個(gè) NginX Web 服務(wù)器。 獲取 ?nginx ?Service:
kubectl get service nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None 80/TCP 12s 然后獲取 ?web ?StatefulSet,以驗(yàn)證兩者均已成功創(chuàng)建:
kubectl get statefulset web
NAME DESIRED CURRENT AGE
web 2 1 20s順序創(chuàng)建 Pod
對(duì)于一個(gè)擁有 n 個(gè)副本的 StatefulSet,Pod 被部署時(shí)是按照 {0..n-1} 的序號(hào)順序創(chuàng)建的。 在第一個(gè)終端中使用 ?kubectl get? 檢查輸出。這個(gè)輸出最終將看起來(lái)像下面的樣子。
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 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請(qǐng)注意,直到 ?web-0? Pod 處于 Running 并 Ready 狀態(tài)后,?web-1? Pod 才會(huì)被啟動(dòng)。
StatefulSet 中的 Pod
StatefulSet 中的每個(gè) Pod 擁有一個(gè)唯一的順序索引和穩(wěn)定的網(wǎng)絡(luò)身份標(biāo)識(shí)。
檢查 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如同 StatefulSet 概念中所提到的, StatefulSet 中的每個(gè) Pod 擁有一個(gè)具有黏性的、獨(dú)一無(wú)二的身份標(biāo)志。 這個(gè)標(biāo)志基于 StatefulSet 控制器分配給每個(gè) Pod 的唯一順序索引。 Pod 的名稱的形式為 ??。 ?web ?StatefulSet 擁有兩個(gè)副本,所以它創(chuàng)建了兩個(gè) Pod:?web-0? 和 ?web-1?。
使用穩(wěn)定的網(wǎng)絡(luò)身份標(biāo)識(shí)
每個(gè) Pod 都擁有一個(gè)基于其順序索引的穩(wěn)定的主機(jī)名。使用 ?kubectl exec? 在每個(gè) Pod 中執(zhí)行 ?hostname?:
for i in 0 1; do kubectl exec "web-$i" -- sh -c 'hostname'; done
web-0
web-1使用 ?kubectl run? 運(yùn)行一個(gè)提供 ?nslookup ?命令的容器,該命令來(lái)自于 ?dnsutils ?包。 通過(guò)對(duì) Pod 的主機(jī)名執(zhí)行 ?nslookup?,你可以檢查他們?cè)诩簝?nèi)部的 DNS 地址:
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm
這將啟動(dòng)一個(gè)新的 Shell。在新 Shell 中運(yùn)行:
# Run this in the dns-test container shell
nslookup web-0.nginx輸出類(lèi)似于:
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(現(xiàn)在可以退出容器 Shell:?exit?)
headless service 的 CNAME 指向 SRV 記錄(記錄每個(gè) Running 和 Ready 狀態(tài)的 Pod)。 SRV 記錄指向一個(gè)包含 Pod IP 地址的記錄表項(xiàng)。
在一個(gè)終端中監(jiān)視 StatefulSet 的 Pod:
kubectl get pod -w -l app=nginx
在另一個(gè)終端中使用 ?kubectl delete? 刪除 StatefulSet 中所有的 Pod:
kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted等待 StatefulSet 重啟它們,并且兩個(gè) Pod 都變成 Running 和 Ready 狀態(tài):
kubectl get pod -w -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 的主機(jī)名和集群內(nèi)部的 DNS 表項(xiàng)。 首先,查看 Pod 的主機(jī)名:
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1然后,運(yùn)行:
kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh
這將啟動(dòng)一個(gè)新的 Shell。在新 Shell 中,運(yùn)行:
# Run this in the dns-test container shell
nslookup web-0.nginx輸出類(lèi)似于:
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(現(xiàn)在可以退出容器 Shell:?exit?)
Pod 的序號(hào)、主機(jī)名、SRV 條目和記錄名稱沒(méi)有改變,但和 Pod 相關(guān)聯(lián)的 IP 地址可能發(fā)生了改變。 在本教程中使用的集群中它們就改變了。這就是為什么不要在其他應(yīng)用中使用 StatefulSet 中 Pod 的 IP 地址進(jìn)行連接,這點(diǎn)很重要。
如果你需要查找并連接一個(gè) StatefulSet 的活動(dòng)成員,你應(yīng)該查詢 Headless Service 的 CNAME。 和 CNAME 相關(guān)聯(lián)的 SRV 記錄只會(huì)包含 StatefulSet 中處于 Running 和 Ready 狀態(tài)的 Pod。
如果你的應(yīng)用已經(jīng)實(shí)現(xiàn)了用于測(cè)試是否已存活(liveness)并就緒(readiness)的連接邏輯, 你可以使用 Pod 的 SRV 記錄(?web-0.nginx.default.svc.cluster.local?、 ?web-1.nginx.default.svc.cluster.local?)。因?yàn)樗麄兪欠€(wěn)定的,并且當(dāng)你的 Pod 的狀態(tài)變?yōu)?nbsp;Running 和 Ready 時(shí),你的應(yīng)用就能夠發(fā)現(xiàn)它們的地址。
寫(xiě)入穩(wěn)定的存儲(chǔ)
獲取 ?web-0? 和 ?web-1? 的 PersistentVolumeClaims:
kubectl get pvc -l app=nginx
輸出類(lèi)似于:
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 48sStatefulSet 控制器創(chuàng)建了兩個(gè) PersistentVolumeClaims, 綁定到兩個(gè) PersistentVolumes。
由于本教程使用的集群配置為動(dòng)態(tài)制備 PersistentVolume 卷,所有的 PersistentVolume 卷都是自動(dòng)創(chuàng)建和綁定的。
NginX Web 服務(wù)器默認(rèn)會(huì)加載位于 ?/usr/share/nginx/html/index.html? 的 index 文件。 StatefulSet ?spec ?中的 ?volumeMounts ?字段保證了 ?/usr/share/nginx/html? 文件夾由一個(gè) PersistentVolume 卷支持。
將 Pod 的主機(jī)名寫(xiě)入它們的 ?index.html? 文件并驗(yàn)證 NginX Web 服務(wù)器使用該主機(jī)名提供服務(wù):
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/; doneweb-0
web-1說(shuō)明:
請(qǐng)注意,如果你看見(jiàn)上面的 curl 命令返回了
403 Forbidden 的響應(yīng),你需要像這樣修復(fù)使用 ?
volumeMounts?(原因歸咎于 使用 hostPath 卷時(shí)存在的缺陷) 掛載的目錄的權(quán)限 運(yùn)行:
?
for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done?
在你重新嘗試上面的 ?
curl?命令之前。
在一個(gè)終端監(jiān)視 StatefulSet 的 Pod:
kubectl get pod -w -l app=nginx
在另一個(gè)終端刪除 StatefulSet 所有的 Pod:
kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted在第一個(gè)終端里檢查 ?kubectl get? 命令的輸出,等待所有 Pod 變成 Running 和 Ready 狀態(tài)。
kubectl get pod -w -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驗(yàn)證所有 Web 服務(wù)器在繼續(xù)使用它們的主機(jī)名提供服務(wù):
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1雖然 ?web-0? 和 ?web-1? 被重新調(diào)度了,但它們?nèi)匀焕^續(xù)監(jiān)聽(tīng)各自的主機(jī)名,因?yàn)楹退鼈兊?nbsp;PersistentVolumeClaim 相關(guān)聯(lián)的 PersistentVolume 卷被重新掛載到了各自的 ?volumeMount ?上。 不管 ?web-0? 和 ?web-1? 被調(diào)度到了哪個(gè)節(jié)點(diǎn)上,它們的 PersistentVolume 卷將會(huì)被掛載到合適的掛載點(diǎn)上。
擴(kuò)容/縮容 StatefulSet
擴(kuò)容/縮容 StatefulSet 指增加或減少它的副本數(shù)。這通過(guò)更新 ?replicas ?字段完成。 你可以使用 ?kubectl scale? 或者 ?kubectl patch? 來(lái)擴(kuò)容/縮容一個(gè) StatefulSet。
擴(kuò)容
在一個(gè)終端窗口監(jiān)視 StatefulSet 的 Pod:
kubectl get pods -w -l app=nginx
在另一個(gè)終端窗口使用 ?kubectl scale? 擴(kuò)展副本數(shù)為 5:
kubectl scale sts web --replicas=5
statefulset.apps/web scaled
在第一個(gè) 終端中檢查 ?kubectl get? 命令的輸出,等待增加的 3 個(gè) Pod 的狀態(tài)變?yōu)?nbsp;Running 和 Ready。
kubectl get pods -w -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 19sStatefulSet 控制器擴(kuò)展了副本的數(shù)量。StatefulSet 按序號(hào)索引順序創(chuàng)建各個(gè) Pod,并且會(huì)等待前一個(gè) Pod 變?yōu)?nbsp;Running 和 Ready 才會(huì)啟動(dòng)下一個(gè) Pod。
縮容
在一個(gè)終端監(jiān)視 StatefulSet 的 Pod:
kubectl get pods -w -l app=nginx
在另一個(gè)終端使用 ?kubectl patch? 將 StatefulSet 縮容回三個(gè)副本:
kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched
等待 ?web-4? 和 ?web-3? 狀態(tài)變?yōu)?nbsp;Terminating。
kubectl get pods -w -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
控制器會(huì)按照與 Pod 序號(hào)索引相反的順序每次刪除一個(gè) Pod。在刪除下一個(gè) Pod 前會(huì)等待上一個(gè)被完全關(guān)閉。
獲取 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五個(gè) PersistentVolumeClaims 和五個(gè) PersistentVolume 卷仍然存在。 查看 Pod 的穩(wěn)定存儲(chǔ),我們發(fā)現(xiàn)當(dāng)刪除 StatefulSet 的 Pod 時(shí),掛載到 StatefulSet 的 Pod 的 PersistentVolume 卷不會(huì)被刪除。 當(dāng)這種刪除行為是由 StatefulSet 縮容引起時(shí)也是一樣的。
更新 StatefulSet
從 Kubernetes 1.7 版本開(kāi)始,StatefulSet 控制器支持自動(dòng)更新。 更新策略由 StatefulSet API 對(duì)象的 ?spec.updateStrategy? 字段決定。這個(gè)特性能夠用來(lái)更新一個(gè) StatefulSet 中 Pod 的的容器鏡像、資源請(qǐng)求和限制、標(biāo)簽和注解。
?RollingUpdate ?更新策略是 StatefulSet 默認(rèn)策略。
滾動(dòng)更新
?RollingUpdate ?更新策略會(huì)更新一個(gè) StatefulSet 中的所有 Pod,采用與序號(hào)索引相反的順序并遵循 StatefulSet 的保證。
對(duì) ?web ?StatefulSet 應(yīng)用 Patch 操作來(lái)應(yīng)用 ?RollingUpdate ?更新策略:
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched
在一個(gè)終端窗口中對(duì) ?web ?StatefulSet 執(zhí)行 patch 操作來(lái)再次改變?nèi)萜麋R像:
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]'
statefulset.apps/web patched
在另一個(gè)終端監(jiān)控 StatefulSet 中的 Pod:
kubectl get pod -l app=nginx -w
輸出類(lèi)似于:
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 10sStatefulSet 里的 Pod 采用和序號(hào)相反的順序更新。在更新下一個(gè) Pod 前,StatefulSet 控制器終止每個(gè) Pod 并等待它們變成 Running 和 Ready。 請(qǐng)注意,雖然在順序后繼者變成 Running 和 Ready 之前 StatefulSet 控制器不會(huì)更新下一個(gè) Pod,但它仍然會(huì)重建任何在更新過(guò)程中發(fā)生故障的 Pod,使用的是它們當(dāng)前的版本。
已經(jīng)接收到更新請(qǐng)求的 Pod 將會(huì)被恢復(fù)為更新的版本,沒(méi)有收到請(qǐng)求的 Pod 則會(huì)被恢復(fù)為之前的版本。 像這樣,控制器嘗試?yán)^續(xù)使應(yīng)用保持健康并在出現(xiàn)間歇性故障時(shí)保持更新的一致性。
獲取 Pod 來(lái)查看它們的容器鏡像:
for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
k8s.gcr.io/nginx-slim:0.8
k8s.gcr.io/nginx-slim:0.8
k8s.gcr.io/nginx-slim:0.8StatefulSet 中的所有 Pod 現(xiàn)在都在運(yùn)行之前的容器鏡像。
說(shuō)明:
你還可以使用 ?
kubectl rollout status sts/<名稱>? 來(lái)查看 StatefulSet 的滾動(dòng)更新?tīng)顟B(tài)。
分段更新
你可以使用 ?RollingUpdate ?更新策略的 ?partition ?參數(shù)來(lái)分段更新一個(gè) StatefulSet。 分段的更新將會(huì)使 StatefulSet 中的其余所有 Pod 保持當(dāng)前版本的同時(shí)允許改變 StatefulSet 的 ?.spec.template?。
對(duì) ?web ?StatefulSet 執(zhí)行 Patch 操作以為 ?updateStrategy ?字段添加一個(gè)分區(qū):
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset.apps/web patched
再次 Patch StatefulSet 來(lái)改變?nèi)萜麋R像:
kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
statefulset.apps/web patched
刪除 StatefulSet 中的 Pod:
kubectl delete pod web-2
pod "web-2" deleted
等待 Pod 變成 Running 和 Ready。
kubectl get pod -l app=nginx -w
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}}'
k8s.gcr.io/nginx-slim:0.8
請(qǐng)注意,雖然更新策略是 ?RollingUpdate?,StatefulSet 還是會(huì)使用原始的容器恢復(fù) Pod。 這是因?yàn)?nbsp;Pod 的序號(hào)比 ?updateStrategy ?指定的 ?partition ?更小。
金絲雀發(fā)布
你可以通過(guò)減少上文指定的 ?partition ?來(lái)進(jìn)行金絲雀發(fā)布,以此來(lái)測(cè)試你的程序的改動(dòng)。
通過(guò) patch 命令修改 StatefulSet 來(lái)減少分區(qū):
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
statefulset.apps/web patched
等待 ?web-2? 變成 Running 和 Ready。
kubectl get pod -l app=nginx -w
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}}'
k8s.gcr.io/nginx-slim:0.7
當(dāng)你改變 ?partition ?時(shí),StatefulSet 會(huì)自動(dòng)更新 ?web-2? Pod,這是因?yàn)?nbsp;Pod 的序號(hào)大于或等于 ?partition?。
刪除 ?web-1? Pod:
kubectl delete pod web-1
pod "web-1" deleted
等待 ?web-1? 變成 Running 和 Ready。
kubectl get pod -l app=nginx -w
輸出類(lèi)似于:
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}}'
k8s.gcr.io/nginx-slim:0.8
?web-1? 被按照原來(lái)的配置恢復(fù),因?yàn)?nbsp;Pod 的序號(hào)小于分區(qū)。當(dāng)指定了分區(qū)時(shí),如果更新了 StatefulSet 的 ?.spec.template?,則所有序號(hào)大于或等于分區(qū)的 Pod 都將被更新。 如果一個(gè)序號(hào)小于分區(qū)的 Pod 被刪除或者終止,它將被按照原來(lái)的配置恢復(fù)。
分階段的發(fā)布
你可以使用類(lèi)似金絲雀發(fā)布的方法執(zhí)行一次分階段的發(fā)布 (例如一次線性的、等比的或者指數(shù)形式的發(fā)布)。 要執(zhí)行一次分階段的發(fā)布,你需要設(shè)置 ?partition ?為希望控制器暫停更新的序號(hào)。
分區(qū)當(dāng)前為 2。請(qǐng)將分區(qū)設(shè)置為 0:
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'
statefulset.apps/web patched
等待 StatefulSet 中的所有 Pod 變成 Running 和 Ready。
kubectl get pod -l app=nginx -w
輸出類(lèi)似于:
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 的容器鏡像詳細(xì)信息:
for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
k8s.gcr.io/nginx-slim:0.7
k8s.gcr.io/nginx-slim:0.7
k8s.gcr.io/nginx-slim:0.7將 ?partition? 改變?yōu)?nbsp;0 以允許 StatefulSet 繼續(xù)更新過(guò)程。
OnDelete 策略
?OnDelete ?更新策略實(shí)現(xiàn)了傳統(tǒng)(1.7 之前)行為,它也是默認(rèn)的更新策略。 當(dāng)你選擇這個(gè)更新策略并修改 StatefulSet 的 ?.spec.template? 字段時(shí),StatefulSet 控制器將不會(huì)自動(dòng)更新 Pod。
刪除 StatefulSet
StatefulSet 同時(shí)支持級(jí)聯(lián)和非級(jí)聯(lián)刪除。使用非級(jí)聯(lián)方式刪除 StatefulSet 時(shí),StatefulSet 的 Pod 不會(huì)被刪除。使用級(jí)聯(lián)刪除時(shí),StatefulSet 和它的 Pod 都會(huì)被刪除。
非級(jí)聯(lián)刪除
在一個(gè)終端窗口監(jiān)視 StatefulSet 中的 Pod。
kubectl get pods -w -l app=nginx
使用 ?kubectl delete? 刪除 StatefulSet。請(qǐng)確保提供了 ?--cascade=orphan? 參數(shù)給命令。這個(gè)參數(shù)告訴 Kubernetes 只刪除 StatefulSet 而不要?jiǎng)h除它的任何 Pod。
kubectl delete statefulset web --cascade=orphan
statefulset.apps "web" deleted
獲取 Pod 來(lái)檢查它們的狀態(tài):
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 ?已經(jīng)被刪除了,但所有 Pod 仍然處于 Running 和 Ready 狀態(tài)。 刪除 ?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 已經(jīng)被刪除,?web-0? 沒(méi)有被重新啟動(dòng)。
在一個(gè)終端監(jiān)控 StatefulSet 的 Pod。
kubectl get pods -w -l app=nginx
在另一個(gè)終端里重新創(chuàng)建 StatefulSet。請(qǐng)注意,除非你刪除了 ?nginx ?Service(你不應(yīng)該這樣做),你將會(huì)看到一個(gè)錯(cuò)誤,提示 Service 已經(jīng)存在。
kubectl apply -f web.yaml
statefulset.apps/web created
service/nginx unchanged請(qǐng)忽略這個(gè)錯(cuò)誤。它僅表示 kubernetes 進(jìn)行了一次創(chuàng)建 nginx headless Service 的嘗試,盡管那個(gè) Service 已經(jīng)存在。
在第一個(gè)終端中運(yùn)行并檢查 ?kubectl get? 命令的輸出。
kubectl get pods -w -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當(dāng)重新創(chuàng)建 ?web ?StatefulSet 時(shí),?web-0? 被第一個(gè)重新啟動(dòng)。 由于 ?web-1? 已經(jīng)處于 Running 和 Ready 狀態(tài),當(dāng) ?web-0? 變成 Running 和 Ready 時(shí), StatefulSet 會(huì)接收這個(gè) Pod。由于你重新創(chuàng)建的 StatefulSet 的 ?replicas ?等于 2, 一旦 ?web-0? 被重新創(chuàng)建并且 ?web-1? 被認(rèn)為已經(jīng)處于 Running 和 Ready 狀態(tài)時(shí),?web-2? 將會(huì)被終止。
讓我們?cè)倏纯幢?Pod 的 Web 服務(wù)器加載的 ?index.html? 的內(nèi)容:
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1盡管你同時(shí)刪除了 StatefulSet 和 ?web-0? Pod,但它仍然使用最初寫(xiě)入 ?index.html? 文件的主機(jī)名進(jìn)行服務(wù)。 這是因?yàn)?nbsp;StatefulSet 永遠(yuǎn)不會(huì)刪除和一個(gè) Pod 相關(guān)聯(lián)的 PersistentVolume 卷。 當(dāng)你重建這個(gè) StatefulSet 并且重新啟動(dòng)了 ?web-0? 時(shí),它原本的 PersistentVolume 卷會(huì)被重新掛載。
級(jí)聯(lián)刪除
在一個(gè)終端窗口監(jiān)視 StatefulSet 里的 Pod。
kubectl get pods -w -l app=nginx
在另一個(gè)窗口中再次刪除這個(gè) StatefulSet。這次省略 ?--cascade=orphan? 參數(shù)。
kubectl delete statefulset web
statefulset.apps "web" deleted
在第一個(gè)終端檢查 ?kubectl get? 命令的輸出,并等待所有的 Pod 變成 Terminating 狀態(tài)。
kubectl get pods -w -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 29mPod 按照和他們序號(hào)索引相反的順序每次終止一個(gè)。 在終止一個(gè) Pod 前,StatefulSet 控制器會(huì)等待 Pod 后繼者被完全終止。
說(shuō)明:
盡管級(jí)聯(lián)刪除會(huì)刪除 StatefulSet 及其 Pod,但級(jí)聯(lián)不會(huì)刪除與 StatefulSet 關(guān)聯(lián)的 Headless Service。你必須手動(dòng)刪除 ?
nginx?Service。
kubectl delete service nginx
service "nginx" deleted
再一次重新創(chuàng)建 StatefulSet 和 headless Service:
kubectl apply -f web.yaml
service/nginx created
statefulset.apps/web created當(dāng) StatefulSet 所有的 Pod 變成 Running 和 Ready 時(shí),獲取它們的 ?index.html? 文件的內(nèi)容:
for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done
web-0
web-1即使你已經(jīng)刪除了 StatefulSet 和它的全部 Pod,這些 Pod 將會(huì)被重新創(chuàng)建并掛載它們的 PersistentVolume 卷,并且 ?web-0? 和 ?web-1? 將繼續(xù)使用它的主機(jī)名提供服務(wù)。
最后刪除 ?nginx ?service
kubectl delete service nginx
service "nginx" deleted
并且刪除 ?web ?StatefulSet:
kubectl delete statefulset web
statefulset "web" deleted
Pod 管理策略
對(duì)于某些分布式系統(tǒng)來(lái)說(shuō),StatefulSet 的順序性保證是不必要和/或者不應(yīng)該的。 這些系統(tǒng)僅僅要求唯一性和身份標(biāo)志。為了解決這個(gè)問(wèn)題,在 Kubernetes 1.7 中 我們針對(duì) StatefulSet API 對(duì)象引入了 ?.spec.podManagementPolicy?。 此選項(xiàng)僅影響擴(kuò)縮操作的行為。更新不受影響。
OrderedReady Pod 管理策略
?OrderedReady ?Pod 管理策略是 StatefulSet 的默認(rèn)選項(xiàng)。它告訴 StatefulSet 控制器遵循上文展示的順序性保證。
Parallel Pod 管理策略
?Parallel ?Pod 管理策略告訴 StatefulSet 控制器并行的終止所有 Pod, 在啟動(dòng)或終止另一個(gè) Pod 前,不必等待這些 Pod 變成 Running 和 Ready 或者完全終止?fàn)顟B(tài)。
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-parallel.yaml?。
這份清單和你在上文下載的完全一樣,只是 ?web? StatefulSet 的 ?.spec.podManagementPolicy ?設(shè)置成了 ?Parallel?。
在一個(gè)終端窗口監(jiān)視 StatefulSet 中的 Pod。
kubectl get pod -l app=nginx -w
在另一個(gè)終端窗口創(chuàng)建清單中的 StatefulSet 和 Service:
kubectl apply -f web-parallel.yaml
service/nginx created
statefulset.apps/web created查看你在第一個(gè)終端中運(yùn)行的 ?kubectl get? 命令的輸出。
kubectl get pod -l app=nginx -w
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-1 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 10s
web-1 1/1 Running 0 10sStatefulSet 控制器同時(shí)啟動(dòng)了 ?web-0? 和 ?web-1?。
保持第二個(gè)終端打開(kāi),并在另一個(gè)終端窗口中擴(kuò)容 StatefulSet:
kubectl scale statefulset/web --replicas=4
statefulset.apps/web scaled
在 ?kubectl get? 命令運(yùn)行的終端里檢查它的輸出。
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 1/1 Running 0 10s
web-3 1/1 Running 0 26sStatefulSet 啟動(dòng)了兩個(gè)新的 Pod,而且在啟動(dòng)第二個(gè)之前并沒(méi)有等待第一個(gè)變成 Running 和 Ready 狀態(tài)。
清理
你應(yīng)該打開(kāi)兩個(gè)終端,準(zhǔn)備在清理過(guò)程中運(yùn)行 ?kubectl ?命令。
kubectl delete sts web
# sts is an abbreviation for statefulset你可以監(jiān)視 ?kubectl get? 來(lái)查看那些 Pod 被刪除
kubectl get pod -l app=nginx -w
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在刪除過(guò)程中,StatefulSet 將并發(fā)的刪除所有 Pod,在刪除一個(gè) Pod 前不會(huì)等待它的順序后繼者終止。
關(guān)閉 ?kubectl get? 命令運(yùn)行的終端并刪除 ?nginx ?Service:
kubectl delete svc nginx
說(shuō)明:
你需要?jiǎng)h除本教程中用到的 PersistentVolume 卷的持久化存儲(chǔ)介質(zhì)。
基于你的環(huán)境、存儲(chǔ)配置和制備方式,按照必須的步驟保證回收所有的存儲(chǔ)。
文章標(biāo)題:創(chuàng)新互聯(lián)kubernetes教程:KubernetesStatefulSet基礎(chǔ)
網(wǎng)站鏈接:http://m.fisionsoft.com.cn/article/dppjepo.html


咨詢
建站咨詢
