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

news2024/11/15 17:38:50

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-pv1
  namespace: dev1
  labels:
    pv: nfs-pv1
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  # Recycle 删除PVC会同步删除PV | Retain 删除PVC不会同步删除PV
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /data/nfstest/share/pv1
    server: 10.20.1.20
    readOnly: false
---
# PVC 编排,通过selector查找PV,K8S里的资源查找都是通过selector查找label标签
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc1
  namespace: dev1
  labels:
    pv: nfs-pvc1
spec:
  resources:
    requests:
      storage: 100Mi
  accessModes:
    - ReadWriteOnce
  selector:
    matchLabels:
      pv: nfs-pv1
---
# Pod挂载PVC,这里为了测试,直接通过node节点的hostPort暴露服务
apiVersion: v1
kind: Pod
metadata:
  name: webapp
  namespace: dev1
  labels:
    app: webapp
spec:
  containers:
    - name: webapp
      image: nginx
      imagePullPolicy: IfNotPresent
      ports:
        - containerPort: 80
          hostPort: 8081
      volumeMounts:
        - name: workdir
          mountPath: /usr/share/nginx/html
  volumes:
    - name: workdir
      persistentVolumeClaim:
        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-1
  namespace: dev1
spec:
  storageClassName: nfs-storage-1    #需要与上面创建的storageclass的名称一致
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Mi
---
kind: Pod
apiVersion: v1
metadata:
  name: nfs-storage-pod-1
  namespace: dev1
spec:
  containers:
    - name: nfs-storage-pod-1
      image: busybox
      command:
        - "/bin/sh"
      args:
        - "-c"
        - "touch /mnt/teststorage && echo 111 > /mnt/teststorage && exit 0 || exit 1"  ## 创建一个名称为"SUCCESS"的文件
      volumeMounts:
        - name: nfs-pvc
          mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        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. 创建持久卷PV

apiVersion: v1
kind: PersistentVolume
metadata:
  # PV卷名称
  name: mongodb-pv
spec:
  # 容量
  capacity: 
    # 存储大小: 100MB
    storage: 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. 创建持久卷申领PVC

apiVersion: 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: db
    spec:
      # 容器信息
      containers:
      - name: my-mongodb-app
        image: mongo
        volumeMounts:
        # 将名为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. 创建持久卷申领PVC

apiVersion: 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: db2
    spec:
      # 容器信息
      containers:
      - name: my-mongodb-app-2
        image: mongo
        volumeMounts:
        # 将名为mongodb-data-2的卷挂载到容器内的指定路径
        - name: mongodb-data-2
          # MongoDB默认的数据存储路径
          mountPath: /data/db
      # 卷信息
      volumes:       
      - name: mongodb-data-2
        # 引用PVC的名称即可
        persistentVolumeClaim:
          claimName: mongodb-pvc-2

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2134131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库的索引是什么?

索引就是类似书本的目录一样,拿字典来说,索引存储的记录地址相当于字典的页数,索引存储的键值相等于字典的某个字。我们可以在目录里面快速地浏览,找到某个关键字,我们在翻到具体的页数看字的解释。举例:我…

机器学习特征构建与特征筛选

前言 上一篇文章讲述了原始特征分析和处理,保障后续拿到的是干净的特征变量,但实际这些特征对于建模不一定是有效的,所以需要在原始特征的基础上,结合业务场景做特征变量的衍生,提升数据的表达能力。此外,…

下载 llama2-7b-hf 全流程【小白踩坑记录】

1、文件转换 在官网 https://ai.meta.com/llama/ 申请一个账号,选择要下载的模型,会收到一个邮件,邮件中介绍了下载方法 执行命令 git clone https://github.com/meta-llama/llama.git​ ,然后执行 llama/download.sh&#xff0c…

实习项目|苍穹外卖|day9

实战作业。 用户端新增功能 1. 查询历史订单 接口设计 返回的是orderorderdetails(那我这里就先查order,再根据order_id查) 分页 pageHelper的使用: //controller相关函数GetMapping("/historyOrders")ApiOperati…

线性回归_梯度下降法

from numpy import * import matplotlib.pyplot as plt1.导入数据 # 1.导入数据 # 模型 y wx b points genfromtxt(linear_regress_lsm_data.csv, delimiter,) length len(points) print(point count %d%length) x array(points[:, 0]) y array(points[:, 1]) plt.scatt…

浅谈工业配电系统中漏电产生的成因以及应对方案

摘要 在现代工业厂房的配电系统中,绝缘检测仪作为保障电气设备安全运行的重要工具,发挥着关键作用。本文探讨了绝缘检测仪在工业厂房配电系统中的应用背景、工作原理、具体应用以及其对设备维护与安全管理的影响。通过分析绝缘检测仪在实际操作中的优势…

数据结构修炼——顺序表和链表的区别与联系?从入门到进阶!

目录 一、线性表二、顺序表2.1 概念及结构2.2 接口实现2.3 一些思考以及顺序表的缺点 三、链表3.1 概念及结构3.2 链表的分类3.3 链表的实现3.3.1 无头单向非循环链表3.3.2 带头双向循环链表 四、顺序表和链表的区别 一、线性表 线性表(linear list)是n…

初级练习[3]:Hive SQL子查询应用

目录 环境准备看如下链接 子查询 查询所有课程成绩均小于60分的学生的学号、姓名 查询没有学全所有课的学生的学号、姓名 解释: 没有学全所有课,也就是该学生选修的课程数 < 总的课程数。 查询出只选修了三门课程的全部学生的学号和姓名 环境准备看如下链接 环境准备h…

【蓝桥杯省赛真题53】Scratch游乐场 蓝桥杯scratch图形化编程 中小学生蓝桥杯省赛真题讲解

目录 scratch游乐场 一、题目要求 编程实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、python资料 scratch游…

Upstage 将发布新一代 LLM “Solar Pro “预览版

Solar Pro 是最智能的 LLM&#xff0c;经过优化可在单 GPU 上运行&#xff0c;性能超过微软、Meta 和谷歌等科技巨头的模型。 加州圣何塞2024年9月11日电 /美通社/ – Upstage 今天宣布发布其下一代大型语言模型 (LLM) Solar Pro 的预览版。加州圣何塞2024年9月11日电 /美通社…

ElementUI大坑Notification修改样式

默认<style lang"scss" scoped>局部样式&#xff0c;尝试用deep透传也无效 实践成功方法&#xff1a;单独写一个style <style> .el-notification{position: absolute !important;top: 40% !important;left: 40% !important; } </style> 也支持自…

无头服务(Headless Service)

无头服务 ​ 无头服务&#xff08;Headless Service&#xff09;是 Kubernetes 中的一种特殊服务类型&#xff0c;主要用于提供稳定的网络标识&#xff0c;而不需要通过负载均衡来分配流量。它允许直接访问 Pod&#xff0c;而不经过集群内的负载均衡器&#xff0c;并且通常用于…

C# net跨平台上位机开发(avalonia)附demo源码

介绍: 目前微软还没有跨平台桌面程序的开发框架。github上有一个团队开始自行研发跨平台桌面框架,其中一款叫avalonia。avalonia 采用 Xaml+C#,类似于wpf,可运行于.netframework,.netcore,是相对比较成熟的.net跨平台桌面应用技术。下面介绍如何创建 avalonia项目;如何在…

mysql_getshell的几种方法

mysql_getshell 一、mysql的--os-shell 利用原理 --os-shell就是使用udf提权获取WebShell。也是通过into oufile向服务器写入两个文件&#xff0c;一个可以直接执行系统命令&#xff0c;一个进行上传文件。此为sqlmap的一个命令&#xff0c;利用这条命令的先决条件&#xff1a;…

PMP--一模--解题--41-50

文章目录 14.敏捷--方法--回顾--回顾是最重要的一个实践&#xff0c;原因是它能让团队学习、改进和调整其过程。41、 [单选] 新项目中的所有团队成员都希望通过尽快交付价值来获得客户的信任。项目经理了解到一个资源已经在其他项目中与发起人一起工作。某资源似乎在使用个人影…

ICM20948 DMP代码详解(20)

接前一篇文章&#xff1a;ICM20948 DMP代码详解&#xff08;19&#xff09; 本回继续对inv_icm20948_read_mems_reg函数的其余内容进行解析。为了便于理解和回顾&#xff0c;再次贴出inv_icm20948_read_mems_reg函数源码&#xff0c;在EMD-Core\sources\Invn\Devices\Drivers\I…

在docker中安装 zendesk/maxwell 失败,解决方法

文章目录 1、拉取镜像失败2、一键设置镜像加速&#xff1a;修改文件 /etc/docker/daemon.json&#xff08;如果不存在则创建&#xff09;3、保存好之后 执行以下两条命令 1、拉取镜像失败 [rootlocalhost docker]# docker pull zendesk/maxwell Using default tag: latest Err…

有奖直播 | onsemi IPM 助力汽车电气革命及电子化时代冷热管理

在全球汽车行业向电气化和智能化转型的浪潮中&#xff0c;功率管理技术的创新和应用成为了关键驱动力。作为全球领先的半导体解决方案供应商&#xff0c;onsemi&#xff08;安森美&#xff09;致力于通过其先进的智能功率模块&#xff08;IPM&#xff09;技术&#xff0c;推动汽…

Java许可政策再变,Oracle JDK 17 免费期将结束!

原文地址&#xff1a;https://www.infoworld.com/article/3478122/get-ready-for-more-java-licensing-changes.html Oracle JDK 17的许可协议将于9月变更回Oracle Technology Network License Agreement&#xff0c;这将迫使用户重新评估他们的使用策略。 有句老话说&#xf…

【MyBatis---快速学习和复习】

学习视频&#xff08;强推&#xff09;&#xff1a;【MyBatis视频零基础入门到进阶&#xff0c;MyBatis全套视频教程源码级深入详解】 https://www.bilibili.com/video/BV1JP4y1Z73S/?p134&share_sourcecopy_web&vd_source4d877b7310d01a59f27364f1080e3382 MyBatis中…