StatefulSet 是Kubernetes1.9版本中穩定的特性,本文使用的環境為 Kubernetes 1.11。如何搭建環境可以參考kubeadm安裝kubernetes V1.11.1 集群
0. 介紹
使用Kubernetes來調度無狀態的應用非常簡單,那Kubernetes如何來管理調度有狀態的應用呢?Kubernetes中提供了一個StatefulSet控制器來管理有狀態的應用,本文就介紹StatefulSet的應用,解決以下幾個問題:
- 如何創建StatefulSet
- StatefulSet如何管理Pods
- 如何刪除StatefulSet
- 如何對StatefulSet進行擴容
- 如何更新StatefulSet中的Pods
1. StatefulSet 是什么
StatefulSet是Kubernetes提供的管理有狀態應用的負載管理控制器API。在Pods管理的基礎上,保證Pods的順序和一致性。與Deployment一樣,StatefulSet也是使用容器的Spec來創建Pod,與之不同StatefulSet創建的Pods在生命周期中會保持持久的標記(例如Pod Name)。
StatefulSet適用於具有以下特點的應用:
- 具有固定的網絡標記(主機名)
- 具有持久化存儲
- 需要按順序部署和擴展
- 需要按順序終止及刪除
- 需要按順序滾動更新
2. 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: docker.io/nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
volumeMode: Filesystem
resources:
requests:
storage: 50Mi
storageClassName: local-storage
StatefulSet創建順序是從0到N-1,終止順序則是相反。如果需要對StatefulSet擴容,則之前的N個Pod必須已經存在。如果要終止一個Pod,則它的后序Pod必須全部終止。
If web-0 should fail, after web-1 is Running and Ready, but before web-2 is launched, web-2 will not be launched until web-0 is successfully relaunched and becomes Running and Ready.
在Kubernetes 1.7版本后,放松了順序的保證策略,對應的參數為 .spec.podManagementPolicy
執行創建命令,並且觀察對象是否正常創建。
[root@devops-101 ~]# kubectl create -f ss-nginx.yml
service "nginx" created
statefulset "web" created
[root@devops-101 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
nginx ClusterIP None <none> 80/TCP 1d
[root@devops-101 ~]# kubectl get statefulset
NAME DESIRED CURRENT AGE
web 2 2 1d
看一下Pod是否是有順序的
[root@devops-101 ~]# kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 11m
web-1 1/1 Running 0 11m
根據Pod的順序,每個Pod擁有對應的主機名,在Pod中執行hostname
命令確認下。
[root@devops-101 ~]# for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1
使用帶有nslookup命令的busybox鏡像啟動一個Pod,檢查集群內的DNS地址設置。
3. 擴縮容
將Pod實例擴充到5個。
[root@devops-101 ~]# kubectl scale sts web --replicas=5
statefulset.apps/web scaled
[root@devops-101 ~]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 5m
web-1 1/1 Running 0 5m
web-2 0/1 Pending 0 1s
web-2 0/1 Pending 0 1s
因為我的集群PV不是動態供給的,所以擴容停留在等待PV的階段,本文要按照后面的辦法手工創建相應的PV。
將實例減少到2個。
[root@devops-101 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 24m
web-1 1/1 Running 0 23m
web-2 1/1 Running 0 18m
web-3 1/1 Running 0 10m
web-4 1/1 Running 0 6m
[root@devops-101 ~]# kubectl patch sts web -p '{"spec":{"replicas":2}}'
statefulset.apps/web patched
4. 更新策略
4.1 滾動更新
默認的更新策略,以相反的順序依次更新Pod
4.2 Partition
4.3 金絲雀發布 Canary
金絲雀發布。
5. 刪除 StatefulSet
StatefulSet支持級連刪除和非級連刪除,在非級連刪除模式下,僅刪除StatefulSet不刪除Pod,級連刪除則全部刪除。
非級連刪除StatefulSet后,如果刪除Pod,就不會重新拉起原來的Pod,而是新建一個Pod。但是如果重新創建StatefulSet,則會對現有的Pod按照規則進行重新整理。
一些分布式系統,並不希望按照順序來管理啟停Pod,因此在1.7版本之后,提供了.spec.podManagementPolicy
這個參數,默認為OrderedReady
,可以設置為Parallel
這樣Pod的創建就不必等待,而是會同時創建、同時刪除。
X. 坑
官方的文檔沒有創建PVC對應的PV,按照官方文檔操作創建后會遇到下面的錯誤,需要提前創建PV及PVC。關於存儲的更詳細的內容,可以參考Kubernetes 存儲系統 Storage 介紹。
pod has unbound PersistentVolumeClaims
官方文檔里解釋了,因為他所用的集群配置為動態提供PV,所以不用手工創建。
As the cluster used in this tutorial is configured to dynamically provision PersistentVolumes, the PersistentVolumes were created and bound automatically.
PV的創建腳本如下:
kind: List
apiVersion: v1
items:
- apiVersion: v1
kind: PersistentVolume
metadata:
name: es-storage-pv-01
spec:
capacity:
storage: 100Mi
volumeMode: Filesystem
accessModes: ["ReadWriteOnce"]
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /home/es
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- devops-102
- devops-103
- apiVersion: v1
kind: PersistentVolume
metadata:
name: es-storage-pv-02
spec:
capacity:
storage: 100Mi
volumeMode: Filesystem
accessModes: ["ReadWriteOnce"]
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /home/es01
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- devops-102
- devops-103