有状态服务的存储状态
下面我们来继续探究StatefulSet对存储状态的管理机制,在前面我们创建Pod需要使用存储的时候,只需要在资源文件中添加spec.volumes字段声明使用volume就可以,比如设置为hostpath或者emptyDir 。但实际环境中开发人员并不清楚我们那些Volume可以使用,所以存储我们就需要使用Kubernetes的另一个资源对象PVC(Persistent Volume Claim)的功能。
- PVC 的全称是:PersistentVolumeClaim(持久化卷声明),PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接声明使用 PVC 即可,不会暴露后端存储的信息。
- PV 的全称是:PersistentVolume(持久化卷),是对底层的共享存储的一种抽象,PV 由运维人员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。
PVC消耗的是PV资源,PV消耗的是后端共享存储。当我们创建一个PVC时,kubernetes 就会自动为PVC绑定一个符合条件的 PV,这里我们PV我们后续会在持久化存储文章中详细讲解,在这个例子中不做过多描述,这里我们已经提前创建完成。
继续以上面拓扑状态的应用为例,我们在资源文件中声明使用PVC:
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: nginx:1.9.1 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: - ReadWriteOnce # Volume 的挂载方式是可读写,并且只能被挂载在一个节点上而非被多个节点共享。 resources: requests: storage: 1Gi #Volume 大小至少是 1 GiB。
我们为这个 StatefulSet 额外添加了一个volumeClaimTemplates字段。它跟 Deployment 里 Pod 模板(PodTemplate)的作用类似。也就是说,凡是被这个 StatefulSet 管理的 Pod,都会声明一个对应的 PVC;而这个 PVC 的定义,就来自于 volumeClaimTemplates这个模板字段。更重要的是,这个 PVC 的名字,会被分配一个与这个 Pod 完全一致的编号。其中这个自动创建的 PVC,与 PV 绑定成功后,就会进入 Bound 状态,这就意味着这个 Pod 可以挂载并使用这个 PV 了。
我们来创建这个资源对象:
$ kubectl create -f statefulset.yaml $ 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
可以看到PVC的命名方式为<PVC名字>-<StatefulSet名字>-<Pod编号>,PVC的状态已经显示为Bound,说明已经绑定到符合条件的PV,现在我们测试验证下数据是否会丢失 ?
分别往Pod的Volume目录中写入内容为hostname的index.html文件,然后分别访问pod的Nginx进程,查看返回信息是否正确
$ for i in 0 1; do kubectl exec web-$i -- sh -c 'echo hello $(hostname) > /usr/share/nginx/html/index.html'; done $ for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done hello web-0 hello web-1
然后我们手动删除这两个Pod
$ kubectl delete pod -l app=nginx pod "web-0" deleted pod "web-1" deleted
被删除之后,这两个 Pod 会被按照编号的顺序被重新创建出来。然后我们在新创建的容器里通过访问“http://localhost”的方式去访问 web-0 里的 Nginx 服务:
# 在被重新创建出来的Pod容器里访问http://localhost $ kubectl exec -it web-0 -- curl localhost hello web-0
可以发现请求依然会返回:“hello web-0”,也就是说,原先与:“web-0” 的 Pod 绑定的 PV,在这个 Pod 被重新创建之后,依然和新的“ web-0 ” Pod 绑定在了一起。对于 Pod web-1 来说,也是完全一样的情况。
这是因为我们删除pod后,之前绑定的PV和PVC并不会删除,数据仍然保存在后端的远程存储如Ceph中,StatefulSet发现Pod消失后,会自动创建一个新的Pod,名字编号也是和之前相同,而这个新的Pod声明使用的还是之前的PVC名字,所以在这个新的 Pod 创建出来之后,Kubernetes 会为它查找之前绑定的PVC ,就会直接找到旧 Pod 遗留下来的同名的 PVC,进而找到跟这个 PVC 绑定在一起的 PV。这样新的 Pod 就可以挂载到旧 Pod 对应的那个 Volume,并且获取到保存在 Volume 里的数据。通过这种方式,Kubernetes 的 StatefulSet 就实现了对应用存储状态的管理。
Reference:
https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
https://luckymrwang.github.io/2021/03/27/%E7%90%86%E8%A7%A3%E6%9C%89%E7%8A%B6%E6%80%81%E5%BA%94%E7%94%A8%E6%8E%A7%E5%88%B6%E5%99%A8StatefulSet/
https://support.huaweicloud.com/basics-cce/kubernetes_0015.html
标签:web,存储,PV,PVC,008statefulset,nginx,pvc,命名,Pod From: https://www.cnblogs.com/itcomputer/p/17044928.html