008statefulset的pvc命名规则

有状态服务的存储状态

下面我们来继续探究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

posted @ 2023-01-11 21:09  arun_yh  阅读(225)  评论(0编辑  收藏  举报