StatefulSet支持通过VolumeClaimTemplate
为每个Pod自动创建PVC和PV,在缩容或删除Pod时,会保留PVC和PV,重新扩容后会自动使用已有PVC和PV,确保PV中的数据不会丢失。本文介绍如何通过VolumeClaimTemplate
为StatefulSet中的Pod挂载云盘存储卷,实现StatefulSet的持久化存储。
使用场景
StatefulSet具有以下特点:
稳定的部署次序:按顺序有序部署或扩展,即从0到N-1,在运行下一个Pod时,所有之前的Pod都是Running和Ready状态。
稳定的缩容次序:按顺序有序收缩或删除,即从N-1到0,在删除下一个Pod时 ,所有之前的Pod都已被删除。
稳定的网络标志:Pod重新调度后其PodName和HostName不变。
稳定的持久化存储:基于PVC,Pod重新调度后仍能访问到相同的持久化数据。
基于上述特点,您可以通过VolumeClaimTemplates
为StatefulSet中的Pod挂载云盘存储卷,实现以下特性:
VolumeClaimTemplate
表示一类PVC的模板,系统会根据StatefulSet配置的replicas数量,创建相应数量的PVC。这些PVC除了名称不一样,其他配置均相同。
创建StatefulSet时,通过
VolumeClaimTemplate
可以自动创建PVC和PV。其中,Pod的名称序号和PVC的名称序号一一对应。例如,名为web-0的Pod所使用的PVC为disk-essd-web-0,名为web-1的Pod所使用的PVC为disk-essd-web-1。扩容StatefulSet时,随着Pod的增加,如果已有对应序号的PVC,会自动使用该PVC和对应的PV;如果没有,会自动创建新的PVC和PV。
缩容StatefulSet时,随着Pod的减少,PVC和PV保持不变。
删除StatefulSet中的Pod时,会保留PVC和PV,新创建的Pod会自动使用已删除Pod所使用的PVC和PV。
使用云盘作为PV,可以实现持久化存储。
创建StatefulSet并挂载云盘存储卷
使用以下YAML示例,创建statefulset.yaml文件。
以下YAML可创建一个StatefulSet和一个Service。其中StatefulSet包含2个Pod,且通过
volumeClaimTemplates
自动创建PVC和PV,为每个Pod挂载了一个20 GiB的ESSD PL1云盘。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 serviceName: "nginx" replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6 ports: - containerPort: 80 name: web volumeMounts: - name: disk-essd mountPath: /data volumeClaimTemplates: - metadata: name: disk-essd spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "alicloud-disk-essd" resources: requests: storage: 20Gi
volumeClaimTemplates
中的参数说明如下:参数
说明
accessModes
存储卷的访问模式。
storageClassName
要使用的StorageClass名称。
本文使用的
alicloud-disk-essd
是ACK默认提供的StorageClass。该StorageClass定义了云盘存储卷使用ESSD云盘,默认PL等级为PL1。storage
云盘存储卷的容量大小。
部署StatefulSet。
kubectl create -f statefulset.yaml
查看StatefulSet中Pod的部署情况。
kubectl get pod -l app=nginx
预期返回:
NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 70s web-1 1/1 Running 0 55s
查看PVC。
kubectl get pvc
预期返回如下,可以看到已自动创建了Pod对应的PVC和PV。
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE disk-essd-web-0 Bound d-uf6727q3zpydr645**** 20Gi RWO alicloud-disk-essd <unset> 93s disk-essd-web-1 Bound d-uf63en5prlz6halx**** 20Gi RWO alicloud-disk-essd <unset> 78s
验证StatefulSet扩缩容时,PVC的变化情况
StatefulSet扩容后自动创建新的PVC和PV
增加StatefulSet的副本数,将StatefulSet扩容到3个Pod。
kubectl scale sts web --replicas=3
查看Pod,确认扩容成功。
kubectl get pod -l app=nginx
预期返回如下,Pod已增加到3个。
NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 2m46s web-1 1/1 Running 0 2m31s web-2 1/1 Running 0 28s
查看PVC,确认已自动创建新的PVC和PV。
kubectl get pvc
预期返回如下,可以看到随着StatefulSet扩容到3个Pod后,PVC和PV也扩容到3个。
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE disk-essd-web-0 Bound d-uf6727q3zpydr645**** 20Gi RWO alicloud-disk-essd <unset> 3m11s disk-essd-web-1 Bound d-uf63en5prlz6halx**** 20Gi RWO alicloud-disk-essd <unset> 2m56s disk-essd-web-2 Bound d-uf6f3nbkzljbqyb0**** 20Gi RWO alicloud-disk-essd <unset> 54s
StatefulSet缩容后PVC保持不变
减少StatefulSet的副本数,将StatefulSet缩容回2个Pod。
kubectl scale sts web --replicas=2
查看Pod,确认缩容成功。
kubectl get pod -l app=nginx
预期返回如下,Pod已减少到2个。
NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 3m51s web-1 1/1 Running 0 3m36s
查看PVC,确认缩容后PVC保持不变。
kubectl get pvc
预期返回如下,可以看到StatefulSet缩容到2个Pod后,PVC仍是3个,说明PVC不会随着StatefulSet缩容而缩减。
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE disk-essd-web-0 Bound d-uf6727q3zpydr645**** 20Gi RWO alicloud-disk-essd <unset> 4m6s disk-essd-web-1 Bound d-uf63en5prlz6halx**** 20Gi RWO alicloud-disk-essd <unset> 3m51s disk-essd-web-2 Bound d-uf6f3nbkzljbqyb0**** 20Gi RWO alicloud-disk-essd <unset> 109s
StatefulSet再次扩容后使用已有PVC
增加StatefulSet的副本数,将StatefulSet重新扩容到3个Pod。
kubectl scale sts web --replicas=3
查看Pod,确认扩容成功。
kubectl get pod -l app=nginx
预期返回如下,Pod已重新增加到3个。
NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 4m49s web-1 1/1 Running 0 4m34s web-2 1/1 Running 0 8s
查看PVC,确认新创建的Pod会使用原有PVC。
kubectl get pvc
预期返回:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE disk-essd-web-0 Bound d-uf6727q3zpydr645**** 20Gi RWO alicloud-disk-essd <unset> 5m6s disk-essd-web-1 Bound d-uf63en5prlz6halx**** 20Gi RWO alicloud-disk-essd <unset> 4m51s disk-essd-web-2 Bound d-uf6f3nbkzljbqyb0**** 20Gi RWO alicloud-disk-essd <unset> 2m49s
验证删除StatefulSet的Pod,PVC保持不变
查看Pod所使用的PVC。
以名为web-1的Pod为例:
kubectl describe pod web-1 | grep ClaimName
预期返回:
ClaimName: disk-essd-web-1
删除StatefulSet中的一个Pod。
以删除名为web-1的Pod为例:
kubectl delete pod web-1
查看StatefulSet中的Pod情况。
kubectl get pod -l app=nginx
预期返回如下,已自动创建新的Pod。由于StatefulSet的命名特性,新创建的Pod和之前的Pod名称一致。
NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 7m8s web-1 1/1 Running 0 11s web-2 1/1 Running 0 2m27s
查看PVC。
kubectl get pvc
预期返回如下,可以看到新创建的Pod仍会使用原有PVC。
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE disk-essd-web-0 Bound d-uf6727q3zpydr645**** 20Gi RWO alicloud-disk-essd <unset> 7m55s disk-essd-web-1 Bound d-uf63en5prlz6halx**** 20Gi RWO alicloud-disk-essd <unset> 7m40s disk-essd-web-2 Bound d-uf6f3nbkzljbqyb0**** 20Gi RWO alicloud-disk-essd <unset> 5m38s
验证云盘存储卷的持久化存储
查看挂载路径。
以名为web-1的Pod为例:
kubectl exec web-1 -- ls /data
预期返回:
lost+found
在挂载路径中写入文件。
以名为web-1的Pod为例:
kubectl exec web-1 -- touch /data/test kubectl exec web-1 -- ls /data
预期返回:
lost+found statefulset
删除Pod。
以删除名为web-1的Pod为例:
kubectl delete pod web-1
查看新创建的Pod。
kubectl get pod -l app=nginx
预期返回:
NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 10m web-1 1/1 Running 0 10s web-2 1/1 Running 0 6m14s
确认新创建的Pod已重新挂载云盘,云盘中的数据仍然存在。
kubectl exec web-1 -- ls /data
预期返回如下,可以看到云盘中存在之前写入的
test
文件,说明云盘存储卷中的数据可以持久化存储。lost+found statefulset