k8s(存储)数据卷与数据持久卷

艺帆风顺 发布于 2025-04-02 25 次阅读


为什么需要数据卷?

容器中的文件在磁盘上是临时存放的,这给容器中运行比较重要的应用程序带来一些问题

问题1:当容器升级或者崩溃时,kubelet会重建容器,容器内文件会丢失

问题2:一个Pod中运行多个容器并需要共享文件

kubenetes卷(Volume)这一抽象概念能够解决这两个问题

常用的数据卷

• 节点本地(hostPath, emptyDir)

• 网络(NFS, Ceph, GlusterFS)

• 公有云(AWS EBS)

• K8S资源(configmap, secret)

编辑

emptyDir卷

 是一个临时存储卷,与Pod生命周期绑定一起,如果Pod删除了卷也会被删除。

应用场景:Pod中容器之间数据共享

案例

    apiVersion: v1kind: Podmetadata: name: pod-emptydirspec: containers: - image: centos command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"] name: write volumeMounts: - mountPath: /data name: cache-volume - image: centos command: ["bash","-c","tail -f /data/hello"] name: read volumeMounts: - mountPath: /data name: cache-volume volumes: - name: cache-volume emptyDir: {}

    节点数据卷:hostPath

    hostPath卷: 挂载Node文件系统(Pod所在节点)上文件或者目录到Pod中的容器。

    应用场景: Pod中容器需要访问宿主机文件

    案例:

      apiVersion: v1kind: Podmetadata: name: pod-emptydirspec: containers: - image: centos command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"] name: write volumeMounts: - mountPath: /data name: cache-volume - image: centos command: ["bash","-c","tail -f /data/hello"] name: read volumeMounts: - mountPath: /data name: cache-volume volumes: - name: cache-volume emptyDir: {}

      网络数据卷:NFS

      NFS卷:提供对NFS挂载支持,可以自动将NFS共享路径

      挂载到Pod中

      NFS:是一个主流的文件共享服务器。

      # yum install nfs-utils

      #设置用于同步数据的目录读写权限

      # vi /etc/exports

      /ifs/kubernetes *(rw,no_root_squash)

      # mkdir -p /ifs/kubernetes

      # systemctl start nfs

      # systemctl enable nfs

      编辑

      注:每个Node上都要安装nfs-utils包,因为会使用到某些依赖。

      示例:将Nginx网站程序根目录持久化到

      NFS存储,为多个Pod提供网站程序文件

        apiVersion: apps/v1kind: Deploymentmetadata: labels: app: web name: web-nfsspec: replicas: 3 selector: matchLabels: app: web strategy: {} template: metadata: labels: app: web spec: containers: - image: nginx name: nginx volumeMounts: - name: data mountPath: /usr/share/nginx/html volumes: - name: data nfs: server: 192.168.40.132 path: /ifs/kubernetes

        持久数据卷概述

        PersistentVolume(PV): 对存储资源创建和使用的抽象,使得存储作为集群中的资源管理

        PersistentVolumeClaim(PVC): 让用户不需要关心具体的Volume实现细节

        pvc:申请容量

        pv:提供存储

        1、pvc与pv的匹配策略

        pvc匹配最接近的大于自己申请容量的pv,如果满足不了,pod处于pending

        编辑

        Pod申请PVC作为卷来使用, Kubernetes通过PVC查找绑定的PV,并Mount给Pod。

        PV与PVC使用流程

        编辑 

        编辑

        PV生命周期

        AccessModes(访问模式):

        AccessModes是用来对PV进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

        •ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载

        •ReadOnlyMany(ROX):只读权限,可以被多个节点挂载

        •ReadWriteMany(RWX):读写权限,可以被多个节点挂载

        RECLAIM POLICY(回收策略):

        目前PV支持的策略有三种:

        •Retain(保留):保留数据,需要管理员手工清理数据

        •Recycle(回收):清除PV中的数据,效果相当于执行rm-rf /ifs/kuberneres/*

        •Delete(删除):与PV相连的后端存储同时删除

        STATUS(状态):

        一个PV的生命周期中,可能会处于4中不同的阶段:

        •Available(可用):表示可用状态,还未被任何PVC绑定

        •Bound(已绑定):表示PV已经被PVC绑定

        •Released(已释放):PVC被删除,但是资源还未被集群重新声明

        •Failed(失败):表示该PV的自动回收失败

        目前PV使用方式称为静态供给,需要K8s运维工程师提前创建一堆PV,供开发者使用。

        编辑

        PV 动态供给(StorageClass)

        PV静态供给明显的缺点是维护成本太高了!因此, K8s开始支持PV动态供给,使用StorageClass对象实现。

        编辑

        K8s默认不支持NFS动态供给,需要单独部署社区开发的插件。

        项目地址:GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.

        部署

          cd deploykubectl apply -f rbac.yaml # 授权访问apiserverkubectl apply -f deployment.yaml # 部署插件,需修改里面NFS服务器地址与共享目录kubectl apply -f class.yaml # 创建存储类kubectl get sc # 查看存储类

          StorageClass测试案例:在创建pvc时指定存储类名称

          编辑

          基于NFS实现PV动态供给流程图

          编辑

          StatefulSet 控制器介绍

          无状态与有状态:

          Deployment控制器设计原则:管理的所有Pod一模一样,提供同一个服务,也不考虑在哪台Node运行,可随意扩容和缩容。这种应用称为“无状态”,例如Web服务

          在实际的场景中,这并不能满足所有应用,尤其是分布式应用,会部署多个实例,这些实例之间往往有依赖关系,例如主从关系、主备关系,这种应用称为“有状态”,例如MySQL主从、 Etcd集群

          StatefulSet控制器用于部署有状态应用,满足一些有状态应用的需求:

          • Pod有序的部署、扩容、删除和停止

          • Pod分配一个稳定的且唯一的网络标识

          • Pod分配一个独享的存储

          StatefulSet 部署应用实践

          • 稳定的网络ID(域名)

          使用Headless Service(相比普通Service只是将spec.clusterIP定义为None)来维护Pod网络身份。

          并且添加serviceName: “nginx” 字段指定StatefulSet控制器要使用这个Headless Service。

          DNS解析名称:. ..svc.cluster.local

          • 稳定的存储

          StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate创建

          一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC。

          编辑

          StatefulSet与Deployment区别:有身份的!

          身份三要素:

          • 域名

          • 主机名

          • 存储(PVC)

          应用程序数据存储

          • ConfigMap:存储配置文件

          • Secret:存储敏感数据

          编辑

          ConfigMap 存储应用配置

          创建ConfigMap后,数据实际会存储在K8s中Etcd,然后通过创建Pod时引用该数据。

          应用场景:应用程序配置

          Pod使用configmap数据有两种方式:

          • 变量注入

          • 数据卷挂载

          ConfigMap 存储应用配置

          编辑

          Secret 存储敏感信息

          与ConfigMap类似,区别在于Secret主要存储敏感数据,所有的数据要经过base64编码。

          应用场景:凭据

          kubectl create secret 支持三种数据类型:

          • docker-registry:存储镜像仓库认证信息

          • generic:存储用户名、密码

          • tls:存储证书

          Secret 存储敏感信息案例

          编辑

          当创建容器时出现Pending状态,可以通过以下命令查看

          kubectl describe pod pod名称

          编辑

          编辑

          编辑

          1、pvc与pv匹配条件

          主要参考存储容量和访问模式

          2、pvc与pv的关系

          一对一

          3、存储容量能限制嘛?

          目前不能,主要用于匹配,限制主要取决于后端存储。

          存储类型:

          1、共享存储,例如NFS,直接能多台机器挂载

          2、块存储,例如硬盘、Ceph,只能挂载到单个机器上,并且需要先格式化

          3、对象存储,例如阿里云OSS,通过API访问

          每个pod不等对,怎么体现的不对等(角色)?

          配置文件(节点标识、IP唯一、数据存储)

          部署一个etcd,3个pod,肯定是一个镜像。

          如何区分3个pod的角色?

          启动容器时候,启动不同的配置文件,并且这一步是自动化的。

          自动化如何去做?如何自适应k8s机制?

          主要是连接另一个pod的域名、决定自身角色的条件

          怎么决定自身角色?

          可以根据pod主机名决定(编号)。

          假设当前起的第一个pod,编号肯定是0,容器启动时执行自动化脚本,脚本就可以根据编号角色启动的配置。