当前位置: 首页 > news >正文

k8s(kubernetes)的PV / PVC / StorageClass(理论+实践)

NFS总是不支持PVC扩容

先来个一句话总结:PV、PVC是K8S用来做存储管理的资源对象,它们让存储资源的使用变得可控,从而保障系统的稳定性、可靠性。StorageClass则是为了减少人工的工作量而去自动化创建PV的组件。所有Pod使用存储只有一个原则:先规划后申请再使用

一、理论

1、PV概念

PV是对K8S存储资源的抽象,PV一般由运维人员创建和配置,供容器申请使用。

没有PV之前,服务器的磁盘没有分区的概念,有了PV之后,相当于通过PV对服务器的磁盘进行分区。

2、PVC概念

PVC 是Pod对存储资源的一个申请,主要包括存储空间申请、访问模式等。创建PV后,Pod就可以通过PVC向PV申请磁盘空间了。类似于某个应用程序向操作系统的D盘申请1G的使用空间。

PVC 创建成功之后,Pod 就可以以存储卷(Volume)的方式使用 PVC 的存储资源了。Pod 在使用 PVC 时必须与PVC在同一个Namespace下。

3、PV / PVC的关系

PV相当于对磁盘的分区,PVC相当于APP(应用程序)向某个分区申请多少空间。比如说安装WPS程序时,一般会告知我们安装它需要多少存储空间,让你选择在某个磁盘下安装。如果将来某个分区磁盘满了,也不会影响别的分区磁盘的使用。

一旦 PV 与PVC绑定,Pod就可以使用这个 PVC 了。如果在系统中没有满足 PVC 要求的 PV,PVC则一直处于 Pending 状态,直到系统里产生了一个合适的 PV。

4、StorageClass概念

K8S有两种存储资源的供应模式:静态模式和动态模式,资源供应的最终目的就是将适合的PV与PVC绑定:

  • 静态模式:管理员预先创建许多各种各样的PV,等待PVC申请使用。

  • 动态模式:管理员无须预先创建PV,而是通过StorageClass自动完成PV的创建以及与PVC的绑定。

StorageClass就是动态模式,根据PVC的需求动态创建合适的PV资源,从而实现存储卷的按需创建。

一般某个商业性的应用程序,会用到大量的Pod,如果每个Pod都需要使用存储资源,那么就需要人工时不时的去创建PV,这也是个麻烦事儿。解决方法就是使用动态模式:当Pod通过PVC申请存储资源时,直接通过StorageClass去动态的创建对应大小的PV,然后与PVC绑定,所以基本上PV → PVC是一对一的关系。

5、Provisioner概念

在创建 PVC 时需要指定 StorageClass,PVC 选择到对应的StorageClass后,与其关联的 Provisioner 组件来动态创建 PV 资源。

那Provisioner是个啥呢?其实就一个存储驱动,类似操作系统里的磁盘驱动。

StorageClass 资源对象的定义主要包括:名称、Provisioner、存储的相关参数配置、回收策略。StorageClass一旦被创建,则无法修改,只能删除重新创建。

PV和PVC的生命周期,包括4个阶段:资源供应(Provisioning)、资源绑定(Binding)、资源使用(Using)、资源回收(Reclaiming)。首先旧的有资源供应,说白了就是得有存储驱动,然后才能创建、绑定和使用、回收。

6、使用PV / PVC前后对比

6.1、通过描述对比

在没有使用PV、PVC之前,各个Pod都可以任意的向存储资源里(比如NFS)写数据,随便一个Pod都可以往磁盘上插一杠子,长期下去磁盘的管理会越来越混乱,然后导致数据使用超限,磁盘爆掉,最后导致磁盘上的所有应用全部挂掉。

为了解决这个问题,引入了PV、PVC的概念,达到限制Pod写入存储数据大小的目的,从而更好地保障了系统的可用性、稳定性。

有了PVC、PV之后,所有Pod使用存储资源,保持一个原则:先规划 → 后申请 → 再使用。

那你肯定有一个疑问,“StorageClass是自动化创建PV,跟原本的无序不可控是一样的效果啊,都可以随便占用存储资源啊”。

其实不然,使用StorageClass只是自动化了创建PV的流程,但依旧执行的是一个存储可控的流程。每个Pod使用多少存储空间是固定的,Pod没有办法超额使用存储空间,更不会影响到别的应用,要出故障也只是某个Pod自己出故障。

6.2、通过图片对比

没有使用PV、PVC之前的情况,如下面2张图:

有了PV、PVC之后的情况,如下图

二、实践

在实践PV、PVC、StorageClass之前,需要读者朋友自行安装NFS服务器。文中演示的内容是通过yaml编排自动到NFS服务器起上创建PV。

1、Pod使用PV、PVC挂载存储卷

1.1、编排PV、PVC、Pod挂载PVC

文中演示的是:Pod的某个目录挂载到NFS的某个目录下。使用了nginx镜像,将html文件写在PV所在的NFS服务器上,最终可以看到利用PV / PVC 成功挂载上去了。

yaml文件如下:

# PV编排
apiVersion: v1
kind: PersistentVolume
metadata:name: nfs-pv1namespace: dev1labels:pv: nfs-pv1
spec:capacity:storage: 1GiaccessModes:- ReadWriteOnce# Recycle 删除PVC会同步删除PV | Retain 删除PVC不会同步删除PVpersistentVolumeReclaimPolicy: Recyclenfs:path: /data/nfstest/share/pv1server: 10.20.1.20readOnly: false
---
# PVC 编排,通过selector查找PV,K8S里的资源查找都是通过selector查找label标签
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: nfs-pvc1namespace: dev1labels:pv: nfs-pvc1
spec:resources:requests:storage: 100MiaccessModes:- ReadWriteOnceselector:matchLabels:pv: nfs-pv1
---
# Pod挂载PVC,这里为了测试,直接通过node节点的hostPort暴露服务
apiVersion: v1
kind: Pod
metadata:name: webappnamespace: dev1labels:app: webapp
spec:containers:- name: webappimage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80hostPort: 8081volumeMounts:- name: workdirmountPath: /usr/share/nginx/htmlvolumes:- name: workdirpersistentVolumeClaim:claimName: nfs-pvc1

执行kubectl命令,查看实践效果如下:

2、Pod使用StorageClass自动挂载存储卷

2.1、安装 Provisioner

文中选择通过helm的方式安装nfs-subdir-external-provisioner,这种方式相对简单。安装文档、安装过程见下文:

  • 安装文档

https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/#nfs

https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

  • 安装过程

通过以下3个步骤完成nfs-subdir-external-provisioner的安装。

  1. 安装helm,本文以mac为例

brew install heml

     2.安装nfs-subdir-external-provisioner,执行以下2个命令:

$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
$ helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner -n kube-system \--set image.repository=dyrnq/nfs-subdir-external-provisioner \--set nfs.server=10.20.1.20 \--set nfs.path=/data/nfstest/nfs-storage

这里注意几个参数:

image.repository:修改了镜像的地址,默认用的国外镜像很有可能拉不下来

nfs.server:你的NFS服务器地址

nfs.path:存储目录

  1. 查看helm安装的结果:

执行命令:helm list -A,查看helm安装结果:

查看是否创建了对应的pod,如果没有修改镜像地址会一直拉取失败,如下图:

修改镜像地址后成功启动Pod,如下图:

2.2、使用StorageClass

文中演示的是:Pod利用StorageClass自动创建PV,同时在对应的存储目录上创建了文件,写入了数据。

yaml文件如下:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: nfs-storage-1
provisioner: cluster.local/nfs-subdir-external-provisioner
parameters:# 设置为"false"时删除PVC不会保留数据,"true"则保留数据archiveOnDelete: "false"
mountOptions:# 指定NFS版本,这个需要根据NFS Server版本号设置- nfsvers=4
---
# 创建PVC
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: nfs-storage-pvc-1namespace: dev1
spec:storageClassName: nfs-storage-1    #需要与上面创建的storageclass的名称一致accessModes:- ReadWriteOnceresources:requests:storage: 10Mi
---
kind: Pod
apiVersion: v1
metadata:name: nfs-storage-pod-1namespace: dev1
spec:containers:- name: nfs-storage-pod-1image: busyboxcommand:- "/bin/sh"args:- "-c"- "touch /mnt/teststorage && echo 111 > /mnt/teststorage && exit 0 || exit 1"  ## 创建一个名称为"SUCCESS"的文件volumeMounts:- name: nfs-pvcmountPath: "/mnt"restartPolicy: "Never"volumes:- name: nfs-pvcpersistentVolumeClaim:claimName: nfs-storage-pvc-1

执行kubectl命令后,可以看到如下效果:

可以看到如我们预料的那样,通过storageClass自动创建了PV,同时在NFS对应的存储目录上创建了文件,写入了数据。

至此,我们实践过程全部结束。

三、总结

本文主要讲解了PV、PVC、StorageClass的理论和实战。

一句话总结:PV、PVC是K8S用来做存储管理的资源对象,它们让存储资源的使用变得可控,从而保障系统的稳定性、可靠性。StorageClass则是为了减少人工的工作量而去自动化创建PV的组件。所有Pod使用存储只有一个原则:先规划后申请再使用

四、Volume之Persistent Volume持久卷

基本概念

「1. PV 持久卷」:PersistentVolume,其是K8s中对实际物理存储系统的抽象。作为K8s中集群层面的资源,与节点资源类似。PV不属于任何命名空间「2. PVC 持久卷申领」:PersistentVolumeClaim,其是K8s中用户对存储请求的抽象。类似地,Pod会消耗节点资源,而PVC则会消耗PV资源

具体地,通过PV实现了对底层真实存储系统的抽象,使得开发者只需通过创建PVC资源即可。而开发者可以直接将PVC的名称作为卷在工作负载资源中进行引用。当集群中存在满足PVC要求的PV时,则会将该PV与PVC进行双向绑定

静态制备

此场景下K8s集群的管理员需要先创建相应的PV资源,然后才能供开发者使用该资源。下面即是通过hostPath卷创建PV资源的示例。此时不难理解,PV实际上是对物理存储资源的抽象

# 1. 创建持久卷PVapiVersion: v1
kind: PersistentVolume
metadata:# PV卷名称name: mongodb-pv
spec:# 容量capacity: # 存储大小: 100MBstorage: 100Mi# 该卷支持的访问模式accessModes:- ReadWriteOnce # RWO, 该卷可以被一个节点以读写方式挂载- ReadOnlyMany  # ROX, 该卷可以被多个节点以只读方式挂载# 回收策略: 保留persistentVolumeReclaimPolicy: Retain# 该持久卷的实际存储类型: 此处使用HostPath类型卷hostPath:path: /tmp/MongodbData

这里对卷的访问模式进行说明,其支持下述选项。值得一提的是,卷虽然可以能够支持多种访问模式,但其在同一时刻只能以一种访问模式进行挂载。例如,某卷可以被节点A以RWO模式挂载,也可以被B节点以ROX模式挂载。但不能同时使用两种模式挂载

**1. ReadWriteOnce (RWO)**:卷可以被一个节点以读写方式挂载。ReadWriteOnce访问模式允许运行在同一节点上的多个Pod访问卷 **2. ReadOnlyMany (ROX)**:卷可以被多个节点以只读方式挂载 **3. ReadWriteMany (RWX)**:卷可以被多个节点以读写方式挂载 **4. ReadWriteOncePod (RWOP)**:在Kubernetes 1.22以上版本时,卷可以被单个Pod以读写方式挂载

这里对卷的回收策略进行补充说明

「1. Retain 保留」

当PVC资源被删除时,其所绑定的PV不会被删除,但该PV的状态会变为「Released已释放」。由于此时PV所关联的物理存储系统上仍然存在历史数据,故该PV此时不能直接被申领。需要集群管理员手动进行处置。一方面对于PV资源而言,其需要删除并重新创建;另一方面,对于PV所关联的物理存储系统上的数据,需要根据实际情况判断是直接删除还是保留以便能够复用数据

「2. Delete 删除」

其不需要管理员人工进行介入操作,系统不仅会将PV资源删除,同时还会将该PV资源所关联的物理存储系统上的数据一并删除掉

K8s集群的管理员创建PV资源,效果如下所示

当K8s集群中的PV资源准备好后,开发者就可以通过创建PVC资源来获取PV了。这里我们将storageClassName字段设置为空字符串,意为不使用存储类进行动态制备,而是使用集群管理员提前创建好的PV。即所谓的静态制备;然后在部署应用的配置文件中,直接引用PVC的名称进行卷的定义即可。需要注意 PVC所属的命名空间 与 使用该PVC的Pod 需在同一个命名空间下

# 1. 创建持久卷申领PVCapiVersion: v1
kind: PersistentVolumeClaim
metadata:name: mongodb-pvc
spec:resources:# 申请30MB的存储空间requests:storage: 30Mi# 访问模式accessModes:- ReadWriteOnce# 禁止使用动态制备的卷, 即使用静态制备storageClassName: ""---# 2. 创建数据库应用apiVersion: apps/v1
# 资源类型
kind: ReplicaSet
metadata:# RS名称name: my-mongodb-app
spec:# 副本数量replicas: 1# 标签选择器selector:matchLabels:app: db# Pod 模板template:metadata:# 标签信息labels:app: dbspec:# 容器信息containers:- name: my-mongodb-appimage: mongovolumeMounts:# 将名为mongodb-data的卷挂载到容器内的指定路径- name: mongodb-data# MongoDB默认的数据存储路径mountPath: /data/db# 卷信息volumes:       - name: mongodb-data# 引用PVC的名称即可persistentVolumeClaim:claimName: mongodb-pvc

当PVC创建完成后,一旦集群中存在满足PVC指定的容量要求、访问模式的PV资源后。该PVC即会与相应的PV进行双向绑定。如下所示,同时会发现应用所在Pod也部署成功

动态制备

对于静态制备而言,无论采用何种回收策略。事实上都需要系统管理员再次创建PV资源。为此动态制备应运而生,K8s集群在收到用户创建的PVC后,会通过PVC中所指定的StorageClass存储类自动地制备出相应的PV资源以供使用。在动态制备场景下,系统管理员只需提前创建相应的若干个StorageClass存储类资源即可。具体地,在StorageClass存储类中会关联真实的物理存储系统和相应的provisioner制备器。其中动态制备的PV会继承相应的StorageClass中定义的回收策略。由于这里我们是通过Kind搭建K8s集群环境的,其已经内置了一个StorageClass存储类。如下所示

此时,开发者只需在创建PVC的过程通过storageClassName字段指定相应的存储类名称即可。类似地在部署应用时直接引用PVC名称定义卷

# 1. 创建持久卷申领PVCapiVersion: v1
kind: PersistentVolumeClaim
metadata:name: mongodb-pvc-2
spec:resources:# 申请20MB的存储空间requests:storage: 30Mi# 访问模式accessModes:- ReadWriteOnce# 使用名为standard的存储类进行动态制备storageClassName: "standard"---# 2. 创建数据库应用apiVersion: apps/v1
# 资源类型
kind: ReplicaSet
metadata:# RS名称name: my-mongodb-app-2
spec:# 副本数量replicas: 1# 标签选择器selector:matchLabels:app: db2# Pod 模板template:metadata:# 标签信息labels:app: db2spec:# 容器信息containers:- name: my-mongodb-app-2image: mongovolumeMounts:# 将名为mongodb-data-2的卷挂载到容器内的指定路径- name: mongodb-data-2# MongoDB默认的数据存储路径mountPath: /data/db# 卷信息volumes:       - name: mongodb-data-2# 引用PVC的名称即可persistentVolumeClaim:claimName: mongodb-pvc-2

效果如下所示,动态制备的PV成功与PVC进行了绑定,应用也处于运行状态

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 梧桐数据库(WuTongDB):RBO(Rule-Based Optimizer)优化器简介
  • COTERRORSET—— LLM训练新基准让模型从自身错误中学习
  • leetcode - 分治思想
  • 前后端数据交互 笔记03(get和post方法)
  • hku-mars雷达相机时间同步方案-软件驱动(MID360与海康MV-CB060-10UMUC-S)
  • [Redis] Redis中的Hash类型和List类型
  • 【CTF Web】BUUCTF BUU UPLOAD COURSE 1 Writeup(文件上传+PHP+文件包含漏洞)
  • 泛微E10产品二开
  • OrionX GPU算力池助力AI OCR场景应用
  • 鹏哥C语言36-37---循环/分支语句练习(折半查找算法)
  • CleanClip for Mac 剪切板 粘贴工具 历史记录 安装(保姆级教程,新手小白轻松上手)
  • (SERIES12)DM性能优化
  • Redis如何实现分布式锁
  • Kali Linux 2024.3 发布,包含新黑客工具
  • 挑战力扣高难度算法、数据库题
  • python3.6+scrapy+mysql 爬虫实战
  • 收藏网友的 源程序下载网
  • “大数据应用场景”之隔壁老王(连载四)
  • IOS评论框不贴底(ios12新bug)
  • java正则表式的使用
  • js学习笔记
  • linux学习笔记
  • nginx 负载服务器优化
  • TCP拥塞控制
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 飞驰在Mesos的涡轮引擎上
  • 开源SQL-on-Hadoop系统一览
  • 网页视频流m3u8/ts视频下载
  • 自制字幕遮挡器
  • 【云吞铺子】性能抖动剖析(二)
  • 说说我为什么看好Spring Cloud Alibaba
  • ​queue --- 一个同步的队列类​
  • ​zookeeper集群配置与启动
  • #nginx配置案例
  • (06)金属布线——为半导体注入生命的连接
  • (27)4.8 习题课
  • (C语言)字符分类函数
  • (solr系列:一)使用tomcat部署solr服务
  • (三)Kafka离线安装 - ZooKeeper开机自启
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET编程C#线程之旅:十种开启线程的方式以及各自使用场景和优缺点
  • .Net开发笔记(二十)创建一个需要授权的第三方组件
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • .NET微信公众号开发-2.0创建自定义菜单
  • //解决validator验证插件多个name相同只验证第一的问题
  • @DateTimeFormat 和 @JsonFormat 注解详解
  • @JsonSerialize注解的使用
  • @RequestParam,@RequestBody和@PathVariable 区别
  • @四年级家长,这条香港优才计划+华侨生联考捷径,一定要看!
  • [ vulhub漏洞复现篇 ] Apache Flink目录遍历(CVE-2020-17519)
  • [ABP实战开源项目]---ABP实时服务-通知系统.发布模式
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]
  • [Bugku]密码???[writeup]
  • [BZOJ] 1001: [BeiJing2006]狼抓兔子