有状态的节点控制器 StatefulSet 的存储状态

2022-04-28 17:04:25   最后更新: 2022-04-28 17:04:25   访问数量:300




 

上一篇文章中,我们介绍了 StatefulSet 及其网络状态:

 

有状态的节点控制器 -- StatefulSet 及其网络状态

 

StatefulSet 通过为每一个 pod 分配有粘性的 ID,并且在 pod 发生变更时,维持 ID 的稳定,从而保证了网络状态下不对等关系的各个 Pod 在启动、删除和重建过程中能够始终保持稳定。

 

但在实际的使用场景中,我们不仅仅需要维护网络拓扑的稳定性,Pod 与分布式存储的存储节点之间关系的稳定性往往也是非常重要的,而这也正是 StatefulSet 的另一个优势。本文我们就来详细介绍一下。

 

 

2.1 PV

 

Persistent Volume 简称 PV,是 Kubernetes 集群中某个网络存储对应的一块存储,是整个集群的分布式存储资源。

 

与此前我们介绍过的 Volume 不同,PV 并不是被定义在 Pod 上的资源,而是独立于 Pod 之外,由运维人员单独维护的资源,当 Pod 需要使用 PV 时,Pod 通过引用 PV 中创建的 PVC(Persistent Volume Claim)来实现对分布式存储空间的创建和分配。

 

例如,下面的 yaml 文件描述了一个 NFS 类型的 PV:

 

# 创建一个NFS类型的PV示例,容量为2G apiVersion: v1 kind: PersistentVolume metadata: name: pv001 labels: name: pv001 spec: nfs: path: /data/training/nfs server: 10.68.4.64 accessModes: - ReadWriteMany capacity: storage: 2Gi

 

 

2.2 Persistent Volume Claim

 

Persistent Volume Claim 简称 PVC,顾名思义,是对 Persistent Volume 资源的请求,正如 Pod 请求节点资源一样,PVC 是对 PV 资源的请求。

 

例如:

 

# 创建PVC示例,申请1G存储空间 apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pv-claim spec: accessModes: ["ReadWriteMany"] resources: requests: storage: 1Gi

 

 

这样,我们就完成了一个 PVC 的创建,在 Pod 中直接使用即可。

 

2.3 Pod 中挂载 pvc

 

下面是一个 Pod 的定义,在 volumes 中,它声明了对 PVC 的使用:

 

apiVersion: v1 kind: Pod metadata: name: pv-pod spec: containers: - name: pv-container image: nginx ports: - containerPort: 80 name: http-server volumeMounts: - mountPath: "/usr/share/nginx/html" name: pv-storage volumes: - name: pv-storage persistentVolumeClaim: claimName: pv-claim

 

 

2.4 PV 的优点

 

PV 的存在,旨在分离分布式存储的集中维护与使用。通过 PV 与 PVC 的分离,在存储的维护上,产生了类似 Kubernetes 集群资源与 Pod 请求之间的抽象。从而让相关维护人员的关注点更加集中和明确。运维人员负责整个 PV 的维护,他们只关心存储的类型、容量、硬件位置等信息,而使用人员则再也不需要关注这些存储本身的细节信息,而只需要关心自己的业务需要使用哪些资源、多少资源。

 

 

显而易见,对于一个 Pod 来说,它需要挂载和使用的分布式存储节点必须是稳定的。Id 为 web-0 的 Pod 如果在某一时刻挂载了 web-1 Pod 对应的存储资源,结果可能是不堪设想的。

 

StatefulSet 控制器通过 volumeClaimTemplates 解决了这一问题。

 

如果我们为一个 StatefulSet 配置了 volumeClaimTemplates,那么就意味着,这个控制器中管理的每个 Pod 都会自动声明一个自己 ID 所对应的 PVC,而这个 PVC 定义所需的属性,则均来自于 volumeClaimTemplates 中的声明。

 

例如:

 

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: - name: www metadata: name: www spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi

 

 

当我们执行 kubectl create 命令后,可以看到 pod 被分配了对应的 pvc:

 

\$ kubectl create -f statefulset.yaml

\$ kubectl get pvc -l app=nginx

NAME STATUS   VOLUME  CAPACITY   ACCESS MODES   STORAGECLASS   AGE

www-web-0   Bound pvc-669431a8-4f5f-4744-bbee-65c9e6564120   1Gi RWO standard    2m37s

www-web-1   Bound pvc-db848c7d-9158-4cd3-8ccc-721127ecd19b   1Gi RWO standard    2m20s

 

这些 PVC,都以“<PVC 名字 >-<StatefulSet 名字 >-< 编号 >”的方式命名,并且处于 Bound 状态。

 

于是,这个 StatefulSet 创建出来的所有 Pod,都会声明使用编号的 PVC。比如,在名叫 web-0 的 Pod 的 volumes 字段,它会声明使用名叫 www-web-0 的 PVC,从而挂载到这个 PVC 所绑定的 PV。

 

当 web-0 Pod 向挂载给他的 PV 节点中写入数据后,即使 web-0 Pod 发生宕机或重启,从而被一个全新的同样 ID 为 web-0 的 Pod 替换后,由于新的 Pod 挂载的仍然是 Id 为 www-web-0 的 PVC,所以,它依然可以读取到此前 web-0 Pod 写入的数据。

 

 

 

 

通过两篇文章,我们全面认识了 StatefulSet,同样作为控制器,它与 Deployment 最大的不同在于它并不借助于 ReplicaSet,而是直接管理所有的 Pod,因为在 StatefulSet 中,Pod 之间的地位是不完全对等的。

 

在 Pod 的管理过程中,StatefulSet 通过为每个 Pod 维护一个唯一 id 以及唯一的 DNS 记录,保证了 Pod 的地位,无论 Pod 发生变更、宕机还是重启,StatefulSet 只需要保证每个 DNS 记录都对应唯一的 Pod,就可以保证它所管理的网络拓扑结构的稳定。

 

同时,对于存储状态来说,StatefulSet 通过维护 PersistentVolumeClaimTemplates 实现对每一个 Pod 所对应的分布式存储节点的管理,借由每个 ID 的 Pod 所对应的 PVC 的稳定,维护了整个 StatefulSet 管理下应用存储状态的稳定。

 

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 

linux 使用及配置相关






kubernetes      pod      容器化      云原生      statefulset      网络状态      perstentvolume     


京ICP备2021035038号