【云原生】Kubernetes----PersistentVolume(PV)与PersistentVolumeClaim(PVC)详解

目录

引言

一、存储卷

(一)存储卷定义

(二)存储卷的作用

1.数据持久化

2.数据共享

3.解耦

4.灵活性

(三)存储卷的分类

1.emptyDir存储卷

1.1 定义

1.2 特点

1.3 示例

2.hostPath存储卷

2.1 定义

2.2 特点

2.3 示例

3.nfs存储卷

3.1 定义

3.2 特点

3.3 示例

二、PV与PVC

(一)PV与PVC的定义

1.PV

2.PVC

(二)PV与PVC的关系

(三)实现过程

(四)静态PV

1.建立共享目录

2.定义PV

2.1 查看定义字段

2.3 创建PV

3.定义PVC

3.1 查看定义字段

3.2 创建PVC

4.创建pod

(五)动态PV

1.动态pv的定义

1.1 StorageClass

1.2 Provisioner

1.3 NFS-CLIENT-PROVISIONER

2.动态PV的作用

3.动态PV的使用流程

4.实现动态PV

4.1 创建共享目录

4.2 部署NFS-CLIENT-PROVISIONER

4.3 创建Service Account

4.4 创建集群角色并绑定

4.4.1 创建clusterole

4.4.2 集群角色绑定

5.创建NFS Provisioner

5.1 基本介绍

5.2 创建

6. 创建StorageClass

7.创建PVC

7.1 关闭自链接

7.2 创建PVC

8.创建Pod

总结


引言

在Kubernetes(K8s)中,持久化存储是一个至关重要的概念,它确保了在Pod重启或迁移时数据不会丢失。为了实现这一目标,Kubernetes引入了PersistentVolume(PV)和PersistentVolumeClaim(PVC)这两个资源对象。本文将详细介绍PV和PVC的概念、工作原理以及它们之间的交互方式。

一、存储卷

在介绍PV与PVC之前,首先了解一下什么是存储卷

(一)存储卷定义

存储卷是Kubernetes中的一个重要概念,它为容器提供了持久化存储或其他类型的存储的能力。Pod中的容器可以通过存储卷来访问文件系统,存储数据。存储卷的类型有很多,如emptyDir、hostPath、NFS等。这些存储卷类型都有其特定的用途和限制

(二)存储卷的作用

1.数据持久化

当Pod中的容器因为各种原因(如升级、故障等)被销毁或重启时,存储在容器内的数据通常会丢失。通过使用存储卷,可以将数据存储在Pod生命周期之外的位置,确保数据即使在容器或Pod重启后仍然可用。

2.数据共享

存储卷允许多个容器在Pod内部共享数据。这对于需要共享配置、日志或其他数据的容器来说非常有用。通过挂载相同的存储卷,不同的容器可以访问并修改其中的数据。

3.解耦

通过将数据存储在存储卷中,而不是直接存储在容器内部,可以实现应用与数据之间的解耦。这意味着应用的代码和数据可以分开管理,从而简化应用的部署、升级和备份过程。

4.灵活性

Kubernetes支持多种类型的存储卷,包括emptyDir、hostPath、NFS等。这为用户提供了很大的灵活性,可以根据应用的需求选择最适合的存储解决方案。

还有一些其它的特性,如

安全性:通过使用只读存储卷,可以限制容器对数据的修改权限,从而提高数据的安全性。此外,一些存储卷类型(如加密云存储)还可以提供额外的数据保护功能。

可移植性:存储卷的使用使得应用在不同Kubernetes集群之间的迁移变得更加容易。只要目标集群支持相同的存储卷类型,并且已经配置了相应的存储资源,就可以轻松地将应用及其数据迁移到新的环境中。

日志和监控:存储卷可以用于存储应用的日志和监控数据。通过将日志和监控数据写入存储卷中,可以长期保存这些数据,并使用专门的日志和监控工具进行分析和警报。

(三)存储卷的分类

1.emptyDir存储卷

1.1 定义

emptyDir是Kubernetes中一种最简单的存储卷类型,其生命周期与Pod相同。当Pod被分配给某个节点时,会为该Pod创建一个emptyDir卷,并且只要Pod在该节点上运行,卷就一直存在。一旦Pod被删除,emptyDir卷中的数据也会被永久删除

1.2 特点

生命周期:emptyDir的生命周期与Pod相同,即当Pod被删除时,emptyDir也会被删除。

用途:emptyDir常用于临时数据,如缓存空间、基于磁盘的归并排序等。实现容器与容器之间数据共享

存储位置:emptyDir存储卷位于Pod所在节点的本地文件系统中

1.3 示例

在yaml文件中定义emptyDir存储卷属性

[root@master01 data]#vim  pod.yaml 
[root@master01 data]#cat  pod.yaml 
apiVersion: v1                       #指定Kubernetes API 的版本
kind: Pod                            #指定创建的资源类型为Pod
metadata:                            #定义pod元信息
  name: pod-nginx                    #指定pod的名称
spec:                                #定义Pod的期望状态。
  containers:                        #定义Pod中要运行的容器
  - name: nginx                      #指定容器名称为nginx
    image: nginx:1.18.0              #指定镜像
    imagePullPolicy: IfNotPresent    #指定镜像拉取策略,优先使用本地镜像,本地没有则会拉取镜像
    ports:                           #定义端口列表
    - name: http                     #指定端口名称为http
      containerPort: 80              #指定容器暴漏端口为80
    volumeMounts:                    #定义容器要挂载的卷
    - name: web                      #这是卷的名称,与下面的volumes部分中定义的卷名称相对应
      mountPath: /usr/shart/nginx/html #容器内部的挂载路径应该是
  - name: centos                     #指定容器名称centos
    image: centos:7                  #指定镜像
    imagePullPolicy: IfNotPresent    #指定镜像拉取策略
    volumeMounts:                    #定义容器要挂载的卷
    - name: web                      #同样定义卷的名称,与volumes部分定义的名称一致
      mountPath: /data/              #容器内部的挂载路径
    command: ['/bin/sh','-c','while true;do echo $(date +%F--%H:%M:%S) >> /data/index.html;sleep 2;done']
#容器内部执行的命令,使用死循环语句,每两秒输出时间格式为%F(年、月、日)--%H(时):%M(分):%S(秒)到挂载的文件
  volumes:                           #定义了 Pod 中的卷
  - name: web                        #卷的名称,与上面的volumeMounts部分中定义的名称相对应
    emptyDir: {}                     #这定义了一个空目录卷。Pod 中的所有容器都可以访问这个卷
#当Pod被删除时,这个卷也会被删除。空目录卷通常用于临时存储,例如在Pod中的容器之间共享数据

注释:上述yaml文件的最终效果为

最下方volumes定义了一个名为web的卷,类型为emptyDir。emptyDir是一个临时卷,它的生命周期与Pod相同。当Pod被分配给节点时,会创建一个空的卷(emptyDir: {}),并且只要Pod运行在该节点上,卷就一直存在。如果Pod从节点上删除(无论是由于某些错误还是正常的删除操作),则卷中的数据也会被永久删除。

nginx容器将web卷(emptyDir: {})挂载到/usr/share/nginx/html路径下。

centos容器将web卷(emptyDir: {})挂载到/data/路径下。

因此,当这个Pod被创建并运行后,两个容器都可以访问和修改web卷(emptyDir: {})中的数据。这可以用于共享数据、配置文件、日志文件等。但是,由于emptyDir是临时的,所以一旦Pod被删除,这些数据也会丢失

[root@master01 data]#kubectl apply -f pod.yaml 
pod/pod-nginx created
[root@master01 data]#kubectl get pod -owide
NAME        READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
pod-nginx   2/2     Running   0          5s    10.244.1.180   node01   <none>           <none>
[root@master01 data]#curl 10.244.1.180
2024-05-28--13:20:55
2024-05-28--13:20:57
2024-05-28--13:20:59
2024-05-28--13:21:01
2024-05-28--13:21:03
......

进入centos容器查看挂载情况

删除pod数据也就会随之消失,使用副本控制器创建的pod也只会重新创建新的pod,数据并不会移交同步

2.hostPath存储卷

2.1 定义

hostPath卷将主机节点文件系统中的文件或目录挂载到Pod中。这使得容器可以访问到宿主机上的文件或目录,从而实现数据的持久化存储。

2.2 特点

生命周期:hostPath卷的生命周期与节点一致,而不是与Pod一致。即使Pod被删除,hostPath卷中的数据仍会保留在节点上。

用途:hostPath卷通常用于一些需要访问宿主机文件系统的特殊场景,如运行一些需要访问宿主机文件的守护进程。

限制:由于hostPath卷直接挂载到宿主机的文件系统上,因此它可能会受到宿主机文件系统的限制,例如磁盘空间、权限等

2.3 示例
[root@master01 data]#kubectl delete pod --all  #删除所有容器
[root@master01 data]#vim pod-hostpath.yaml 
[root@master01 data]#cat pod-hostpath.yaml 
apiVersion: v1  
kind: Pod 
metadata:
  name: pod-hostpath
spec:
  containers:
  - name: nginx
    image: nginx:1.18.0
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    volumeMounts:                       #定义如何在容器内部挂载存储卷
    - name: web                         #指定要挂载的存储卷的名称,volumes.name字段定义的名称
      mountPath: /usr/share/nginx/html  #容器内部的目录路径,存储卷将被挂载到这个路径上
      readOnly: false                   #false表示容器可以读写该存储卷
  volumes:                              #定义宿主机上的目录文件为Pod中可用的存储卷,
  - name: web                           #自定义存储卷的名称
    hostPath:                           #指定存储卷类型为hostPath,
      path: /data/web/nginx/            #指定宿主机上可以挂载到pod中的目录或文件
      type: DirectoryOrCreate           #指定hostPath的类型,DirectoryOrCreate表示不存时创建
--------------------------------------------------------------------------------------
'readOnly'
#如果设置为true,则容器以只读方式挂载的存储卷;如果设置为false或空值,则容器可以读写该存储卷

'hostPath'
#允许将主机上的文件系统目录或文件挂载到Pod中

'type 可设置的类型值'
#"" (默认):不进行任何特殊处理。
#DirectoryOrCreate:如果指定路径下的目录不存在,则创建它。
#Directory:目录必须存在。
#FileOrCreate:如果指定路径下的文件不存在,则创建它。
#File:文件必须存在。
#Socket:UNIX套接字必须存在。
#CharDevice:字符设备必须存在。
#BlockDevice:块设备必须存在

此pod在node02节点上创建,在node02节点查看文件

[root@node02 ~]#cd  /data/web/nginx/
[root@node02 nginx]#ls
[root@node02 nginx]#echo "this is hostpath" >index.html  
#创建访问页面,因为是将宿主机上的目录挂载到pod上,会覆盖挂载点(/usr/share/nginx/html)下的文件
[root@node02 nginx]#curl 10.244.2.195
this is hostpath

即使删除pod,由于文件是在宿主机上,hostPath存储卷模式下,不会删除节点上的文件

[root@master01 data]#kubectl delete pod pod-hostpath 
pod "pod-hostpath" deleted


-----------------------------------------------------------------------------
//node02节点查看
[root@node02 nginx]#ls
index.html
[root@node02 nginx]#cat  index.html 
this is hostpath

需要注意的是,当宿主机(即node节点)发生故障时,数据仍会丢失,且hostPath卷直接引用主机上的文件或目录,因此它可能会暴露敏感数据或允许Pod执行不受限制的操作。在生产环境中,通常建议使用更安全的存储解决方案,如持久卷(PersistentVolumes)或云提供商提供的存储服务。

当pod生命周期结束后创建新的pod,只要是指定挂载此存储卷,依然可以访问到数据

hostPath会自动优先选择合适的节点,如node02上有指定的挂载路径,则不需要再去node01节点上创建,会自动选择带有指定挂载路径的节点

3.nfs存储卷

3.1 定义

NFS(Network File System)是一种基于TCP/IP传输的网络文件系统协议。通过使用NFS协议,客户机可以像访问本地目录一样访问远程服务器中的共享资源。在Kubernetes中,NFS存储卷允许Pod访问NFS服务器上的共享目录。

3.2 特点

网络存储:NFS存储卷是一种网络存储解决方案,可以实现数据的跨节点共享和访问。

持久性:NFS存储卷的数据存储在NFS服务器上,因此具有持久性。即使Pod被删除或重新调度到其他节点,数据仍然保留在NFS服务器上。

多个客户端访问:NFS支持多个客户端同时挂载和访问同一个NFS服务器上的共享目录。

配置和管理:NFS需要单独配置和管理NFS服务器,包括安装NFS软件包、设置共享目录、配置访问权限等

3.3 示例
[root@master01 data]#kubectl delete pod --all  #删除所有容器

首先,搭建NFS共享服务器,并指定共享目录

//在nfs服务器上操作
[root@nfs ~]#mkdir -p /nfs/volumes
[root@nfs ~]#chmod -R 777 /nfs/volumes/
[root@nfs ~]#echo "this is nfs" >/nfs/volumes/index.html
#创建共享目录,并添加权限,自定义访问界面

[root@nfs ~]#vim /etc/exports
[root@nfs ~]#cat /etc/exports
/nfs/volumes/ 192.168.83.0/24(rw,no_root_squash)
#添加共享目录信息及权限到/etc/exports文件中进行共享


[root@nfs ~]#systemctl start rpcbind
[root@nfs ~]#systemctl start nfs
#启动共享服务
[root@nfs ~]#ss -natp |grep rpcbind  #RPC端口,远程连接
LISTEN   0   128    *:111      *:*      users:(("rpcbind",pid=46682,fd=4),("systemd",pid=1,fd=34))
LISTEN   0   128   :::111     :::*      users:(("rpcbind",pid=46682,fd=11))
[root@nfs ~]#ss -natp |grep 2049     #NFS端口,提供服务
LISTEN     0      64           *:2049                     *:*                  
LISTEN     0      64          :::2049                    :::*

//任意节点查看共享情况
[root@node01 ~]#showmount -e 192.168.83.60
Export list for 192.168.83.60:
/nfs/volumes/ 192.168.83.0/24

定义nfs存储卷文件

[root@master01 data]#vim pod-nfs.yaml 
[root@master01 data]#cat pod-nfs.yaml 
apiVersion: v1  
kind: Pod 
metadata:
  name: pod-nfs
spec:
  containers:
  - name: nginx
    image: nginx:1.18.0
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: nfsv
      mountPath: /usr/share/nginx/html
      readOnly: false
  volumes:
  - name: nfsv
    nfs:                        #指定使用nfs存储卷
      path: /nfs/volumes        #指定nfs服务器的共享目录
      server: 192.168.83.60     #指定挂载的nfs服务器,地址映射后,也可以写主机名

创建pod后,访问容器就可以访问到自定义的web界面

[root@master01 data]#kubectl apply -f pod-nfs.yaml 
pod/pod-nfs created
[root@master01 data]#kubectl get pod -owide 
NAME      READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
pod-nfs   1/1     Running   0          4s    10.244.1.181   node01   <none>           <none>
[root@master01 data]#curl 10.244.1.181
this is nfs

同样的,删除pod后,重新创建,只要使用nfs挂载此文件,可以得到数据的持久化存储。

但是容易发生单点故障,服务器宕机时所有客户端无法访问,多台客户端挂载在同一台服务器上,管理维护较繁琐

总结来说,emptyDir、hostPath和NFS是Kubernetes中三种不同的存储卷类型,它们各自具有不同的特点和用途。

emptyDir适用于临时数据和需要共享数据的Pod,

hostPath适用于需要访问宿主机文件系统的特殊场景,

NFS则是一种网络存储解决方案,可以实现数据的跨节点共享和访问

二、PV与PVC

在Kubernetes中,存储卷(Volumes)是Pod中可以访问的存储的抽象,用于存储数据。然而,随着Kubernetes集群的复杂性和多租户的需求增长,仅仅依赖Pod中的存储卷定义已经不足以满足所有存储需求。为了解决这个问题,Kubernetes引入了PersistentVolume(PV)和PersistentVolumeClaim(PVC)的概念,它们为存储资源提供了更高层次的管理和抽象

(一)PV与PVC的定义

1.PV

定义:PV(Persistent Volume)是对底层的共享存储的一种抽象,它由管理员进行创建和配置。PV是与具体的底层共享存储技术的实现方式相关的,例如Ceph、GlusterFS、NFS等,它们通过插件机制完成与共享存储的对接,实现数据持久化存储。

关键信息:PV作为对存储资源的定义,主要涉及存储能力(即存储空间的大小)、访问模式(如ReadWriteOnce、ReadOnlyMany、ReadWriteMany等)、存储类型、回收策略以及后端存储类型等关键信息的设置。

2.PVC

定义:PVC(Persistent Volume Claim)是用户对存储的一种声明,它与Pod比较类似。Pod消耗的是节点资源,而PVC消耗的是PV资源。PVC可以请求特定的存储空间和访问模式,而不需要用户关心底层的存储实现细节。

关键信息:PVC主要涉及存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。当PVC被创建时,Kubernetes会尝试将其与满足其要求的PV进行绑定。如果系统中存在一个DefaultStorageClass,那么在创建PVC的时候可以不指定storageClassName,系统会自动使用默认的存储类型。

(二)PV与PVC的关系

在 Pod 中定义一个存储卷(该存储卷类型为 PVC),定义的时候直接指定大小,PVC 必须与对应的 PV 建立关系,PVC 会根据配置的定义去 PV 申请,而 PV 是由存储空间创建出来的。PV 和 PVC 是 Kubernetes 抽象出来的一种存储资源

简单来说,类似于LVM逻辑卷,LVM逻辑卷是将磁盘整合建立卷组,而后根据卷组建立逻辑卷并指定使用空间的大小

而PV就是将共享服务器(例如NFS、CEPH等)进行划分,建立一个或多个PV存储卷,PVC指定挂载存储卷的大小及访问模式(读、写),挂载对应的PV卷,达到数据持久化存储

一般来说,PV和PVC之间的相互作用需要遵循以下生命周期

Provisioning---> Binding---> Using---> Releasing ---> Recycling 

 

Provisioning(创建):即 PV 的创建,可以直接创建 PV(静态方式),也可以使用 StorageClass 动态创建

Binding(绑定):将 PV 分配给 PVC

Using(使用):Pod 通 PVC使用该 Volume,并可以通过准入控制StorageProtection(1.9及以前版本为PVCProtection) 阻止删除正在使用的 PVC

Releasing(释放):Pod 释放 Volume 并删除 PVC

Reclaiming(回收): PV,可以保留 PV 以便下次使用,也可以直接从云存储中删除

(三)实现过程

以NFS共享服务器为例

①首先在NFS服务器上建立共享目录

②建立PV卷,定义PV卷的大小与访问模式

③创建PVS请求,是PVC与PC之间建立联系

④创建pod,指定需要使用的PVC

(四)静态PV

静态PV就是手动创建PV,然后等待PVC请求,建立连接

NFS使用PV与PVC

1.建立共享目录

NFS服务器上建立共享目录共享目录

//nfs服务器上操作,创建共享目录
[root@nfs ~]#mkdir -p /nfs/pv/pv{1..4}
[root@nfs ~]#ls /nfs/pv/
pv1  pv2  pv3  pv4
[root@nfs ~]#chmod -R 777 /nfs/pv/

//添加共享目录
[root@nfs ~]#cat /etc/exports
/nfs/pv/pv1 192.168.83.0/24(rw,no_root_squash)
/nfs/pv/pv2 192.168.83.0/24(rw,no_root_squash)
/nfs/pv/pv3 192.168.83.0/24(rw,no_root_squash)
/nfs/pv/pv4 192.168.83.0/24(rw,no_root_squash)
[root@nfs ~]#exportfs -r
[root@nfs ~]#showmount -e
Export list for nfs:
/nfs/pv/pv4 192.168.83.0/24
/nfs/pv/pv3 192.168.83.0/24
/nfs/pv/pv2 192.168.83.0/24
/nfs/pv/pv1 192.168.83.0/24

2.定义PV

2.1 查看定义字段

使用kubectl explain查看pv的定义方式

[root@master01 data]#kubectl explain pv
KIND:     PersistentVolume
VERSION:  v1
   apiVersion	<string>    #设置为v1即可,通用版本
   kind	<string>            #设置PV卷,kind的值为:PersistentVolume
   metadata	<Object>        #PV是集群级别的资源,可以跨namespace,所以不需要指定
   spec	<Object>            #定义PV的特性
   status	<Object>        #状态,创建后自动生成,一般不需要配置

查看pv.spec可设置字段

[root@master01 data]#kubectl explain pv.spec
...
---------------------'accessModes ([string] 类型)'---------------------------
定义了卷的访问模式。PV 可以被单个节点以某种方式访问,或者被多个节点以某种方式访问。
可能的值有:
ReadWriteOnce (RWO): 卷可以被单个节点以读写模式挂载。
ReadOnlyMany (ROX): 卷可以被多个节点以只读模式挂载。
ReadWriteMany (RWX): 卷可以被多个节点以读写模式挂载。
#注意:nfs支持三种访问模式,但是不是所有的存储类型都支持所有的访问模式。
#例如iSCSI不支持ReadWriteMany;HostPath不支持ReadOnlyMany和ReadWriteMany
----------------------------------------------------------------------------

---------------------------------'capacity '--------------------------------
描述了 PV 的存储容量。通常包含一个条目键为storage值为存储容量大小,
如storage: 1Gi
----------------------------------------------------------------------------

-----------------------------------'nfs'------------------------------------
定义存储卷类型为nfs,以下常用两个字段
path: 定义挂载卷路径
server: 定义服务器名称
----------------------------------------------------------------------------

-----------------'persistentVolumeReclaimPolicy (string 类型)'---------------
当 PV 不再被 PVC 引用时(即 PVC 被删除),此字段定义了 PV 的回收策略
Retain: 手动回收,保留 PV,需要管理员手动处理。
Recycle: 基本弃用,只有 NFS 和 HostPath 支持
Delete: 删除与 PV 关联的存储资源。
----------------------------------------------------------------------------

-------------------------------'storageClassName'----------------------------
自定义存储类名称,此配置用于绑定具有相同类别的PVC和PV
如果 PV 属于某个 StorageClass,则该字段将包含 StorageClass 的名称。
PVC 可以请求特定 StorageClass 的 PV。
-----------------------------------------------------------------------------

--------------------------'volumeMode (string 类型)'-------------------------
指定了卷的模式,可以是文件系统或块设备。
Filesystem: PV 作为文件系统挂载到容器中。
Block: PV 作为原始块设备挂载到容器中(通常用于数据库等需要直接访问块设备的场景)。

--------------------------'nodeAffinity (Object)'----------------------------
描述了 PV 对节点的亲和性规则。
-----------------------------------------------------------------------------
......
2.3 创建PV

定义3个PV,分别定义挂载的路径以及访问模式,还有PV划分的大小。

[root@master01 data]#vim pv.yaml
[root@master01 data]#cat pv.yaml
apiVersion: v1
kind: PersistentVolume                     #定义了资源的类型为PersistentVolume
metadata:
  name: pv01
  labels:
    name: pv01
spec:                                      #这是PV的规格描述
  nfs:                                     #指定了PV的后端存储类型为NFS
    path: /nfs/pv/pv1                      #NFS服务器上存储卷的路径
    server: 192.168.83.60                  #NFS服务器的IP地址
  accessModes: ["ReadWriteMany","ReadWriteOnce"]   #定义PV的访问模式为两种,RWX,RWO
  capacity:                                        #定义PV容量
    storage: 1Gi                                   #指定PV存储容量为1GiB
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv02
  labels:
    name: pv02
spec:
  nfs:
    path: /nfs/pv/pv2
    server: 192.168.83.60
  accessModes: ["ReadWriteOnce"]            #定义PV的访问模式为RWO
  capacity:
    storage: 2Gi                            #指定PV存储容量为2GiB
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv03
  labels:
    name: pv03
spec:
  nfs:
    path: /nfs/pv/pv3
    server: 192.168.83.60
  accessModes: ["ReadWriteMany","ReadWriteOnce"] #定义PV的访问模式为两种RWX,RWO
  capacity:
    storage: 2Gi                                 #指定PV存储容量为2GiB
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv04
  labels:
    name: pv04
spec:
  nfs:
    path: /nfs/pv/pv4
    server: 192.168.83.60
  accessModes: ["ReadWriteMany","ReadWriteOnce"]   #定义PV的访问模式为两种RWX,RWO
  capacity:
    storage: 3Gi                                   #指定PV存储容量为3GiB

查看创建结果

[root@master01 data]#kubectl apply -f pv.yaml
persistentvolume/pv01 created
persistentvolume/pv02 created
persistentvolume/pv03 created
persistentvolume/pv04 created
[root@master01 data]#kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv01   1Gi        RWO,RWX        Retain           Available                                   6s
pv02   2Gi        RWO            Retain           Available                                   6s
pv03   2Gi        RWO,RWX        Retain           Available                                   6s
pv04   3Gi        RWO,RWX        Retain           Available                                   6s
     '可用大小'   '访问模式'

3.定义PVC

3.1 查看定义字段
[root@master01 data]#kubectl explain pvc
......

apiVersion: v1
kind: PersistentVolumeClaim
metadata
spec
status
.....

#apiVersion、metadata、status字段与pv基本一致,kind字段设置为PersistentVolumeClaim

查看pvc.spec下的字段

[root@master01 data]#kubectl explain pvc.spec

---------------------'accessModes ([string] 类型)'---------------------------
描述用户应用对存储资源的访问权限
ReadWriteOnce (RWO): 卷可以被单个节点以读写模式挂载。
ReadOnlyMany (ROX): 卷可以被多个节点以只读模式挂载。
ReadWriteMany (RWX): 卷可以被多个节点以读写模式挂载。
#注意:nfs支持三种访问模式,但是不是所有的存储类型都支持所有的访问模式。
#例如iSCSI不支持ReadWriteMany;HostPath不支持ReadOnlyMany和ReadWriteMany
----------------------------------------------------------------------------

--------------------------------'volumeMode'--------------------------------
描述希望使用的 PV 存储卷模式。
可以是文件系统 (Filesystem) 或裸格式的块设备 (Block)。
----------------------------------------------------------------------------

----------------------------'resources (Object)'----------------------------
描述对存储资源的请求。定义申请资源的大小
目前仅支持设置 requests.storage,即对存储空间的设置。
----------------------------------------------------------------------------

-------------------------'storageClassName (string)'------------------------
定义存储类名称,此配置用于绑定具有相同类别的PVC和PV
如果有多个 PV 符合 PVC 的要求,Kubernetes 会基于 PVC 指定的StorageClass来选择 PV
----------------------------------------------------------------------------

----------------------------'selector (Object)'----------------------------
一个可选字段,用于更精细地选择 PV。
可以通过 matchLabels 和 matchExpressions 来选择具有特定标签的 PV。
----------------------------------------------------------------------------


3.2 创建PVC

定义的spec关键字段(如存储大小,访问模式、存储类型)需要与PV信息匹配

[root@master01 data]#vim pvc.yaml
[root@master01 data]#cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim          #指定资源类型为PersistentVolumeClaim,即PVC
metadata:
  name: pvc01
spec:
  accessModes: ["ReadWriteMany"]     #定义期望获得的访问模式为ReadWriteMany,即RWX
  resources:                         #描述 PVC 的资源需求
    requests:                        #列出PVC所请求的特定资源
      storage: 2Gi   #指定PVC所请求的存储容量。指定为2Gi,那么就会匹配存储容量为2Gi的PV

查看创建结果

PV 的状态(STATUS)有以下 4 种
Available(可用):表示可用状态,还未被任何 PVC 绑定
Bound(已绑定):表示 PV 已经绑定到 PVC
Released(已释放):表示 PVC 被删掉,但是资源尚未被集群回收
Failed(失败):表示该 PV 的自动回收失败

4.创建pod

定义创建pod的yaml文件,并定义pvc挂载存储

[root@master01 data]#vim pod-pv.yaml 
[root@master01 data]#cat pod-pv.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-pv
  namespace: default
spec:
  containers:
  - name: nginx
    image: nginx:1.18.0
    volumeMounts:
    - name: web                         #指定要挂载的存储卷名称,与volumes.name字段设置的一致
      mountPath: /usr/share/nginx/html  #将volumes字段设置的存储卷挂载到该路径下
  volumes:
    - name: web                         #定义存储卷名称
      persistentVolumeClaim:            #定义存储卷是由PersistentVolumeClaim(PVC)提供
        claimName: pvc01                #指定PVC名称的pvc01

创建pod

[root@master01 data]#kubectl apply -f pod-pv.yaml 
pod/pod-pv created
[root@master01 data]#kubectl get pod pod-pv -owide
NAME     READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
pod-pv   1/1     Running   0          13s   10.244.2.199   node02   <none>           <none>

在nfs服务器上创建访问页面

//NFS服务器操作
[root@nfs ~]#cd  /nfs/pv/pv3     #PVC绑定的路径
[root@nfs pv3]#echo "this is pv3" >index.html

访问pod就可以看到自定义的访问界面

[root@master01 data]#curl 10.244.2.199
this is pv3

此时就可以实现存储数据的持久化,哪怕pod意外中断退出,或手动删除以后,数据依旧会保存在啊NFS服务器上。但是,此时因为手动创建了四个PV,而且是PVC是指定已经存在的PV,并匹配对应的PV资源类型,如果面对庞大的PVC请求,且请求的资源类型与访问模式不同,如果设置的是静态PV,那么就需要手动创建一个个对应的请求,这是一个庞大的工作量,想要解决这个问题就需要设置动态PV

(五)动态PV

1.动态pv的定义

动态PV是在集群级别使用StorageClass和Provisioner来自动创建PV对象的方式

Kubernetes 本身支持的动态PV创建,但是不包括NFS,所以需要使用外部存储卷插件分配PV。卷插件称为 Provisioner(存储分配器),NFS 使用的是 nfs-client,这个外部PV。

1.1 StorageClass

StorageClass为管理员提供了一种描述存储“类”(Class)的方法。它允许管理员定义不同的存储类别,每个类别可能会映射到不同的服务质量等级、备份策略或其他存储相关的策略。

StorageClass为用户屏蔽了后端存储的细节,用户只需指定StorageClass的名称,而无需关心具体的存储实现。

基于StorageClass,Kubernetes可以动态地为PersistentVolumeClaims(PVCs)创建PersistentVolumes(PVs),从而实现了动态的资源供应。

1.2 Provisioner

用于指定 Volume 插件的类型,包括内置插件(如 kubernetes.io/aws-ebs)和外部插件(如 exte卷插件会使用已经配置好的 NFS 服务器自动创建 rnal-storage 提供的 ceph.com/cephfs)

1.3 NFS-CLIENT-PROVISIONER

Kubernetes的外部存储供应器(provisioner),依赖于NFS服务来动态地创建PV。因此,在部署NFS-CLIENT-PROVISIONER之前,需要确保NFS服务已经部署并正常运行

2.动态PV的作用

自动创建:通过StorageClass指定存储的类型和配置,由Provisioner自动创建和管理PV对象。

无需手动配置:与静态PV不同,动态PV不需要管理员手动配置和管理PV资源。

可扩展与动态分配:适用于可扩展的、动态分配的存储资源,用户只需声明所需的存储要求,无需关心具体的存储配置和管理。

3.动态PV的使用流程

管理员首先定义一个StorageClass,它描述了存储类的属性,如存储类型、后端存储参数(如NFS服务器的地址和路径)、回收策略等。StorageClass中指定了Provisioner插件,该插件负责根据StorageClass的定义动态创建PV

根据StorageClass中指定的Provisioner插件,管理员需要在Kubernetes集群中安装并配置相应的插件

用户或应用开发者在Kubernetes集群中创建一个PVC,指定所需的存储大小、访问模式以及StorageClass的名称

Kubernetes系统监控PVC的创建,并查找与之匹配的StorageClass。一旦找到匹配的StorageClass,Kubernetes会触发Provisioner插件根据StorageClass的定义动态创建一个PV。

创建好的PV会自动与PVC进行绑定。这个绑定过程是基于PVC中的请求参数(如存储大小和访问模式)与PV的属性进行匹配的

当Pod创建时,它可以指定使用某个已绑定的PVC。Kubernetes会将PV挂载到Pod中,使得Pod中的应用可以访问该PV上的数据。

4.实现动态PV

创建之前,清空之前的操作记录

[root@master01 data]#kubectl delete pod --all
pod "pod-pv" deleted
[root@master01 data]#kubectl delete pvc --all
persistentvolumeclaim "pvc01" deleted
[root@master01 data]#kubectl delete pv --all
persistentvolume "pv01" deleted
persistentvolume "pv02" deleted
persistentvolume "pv03" deleted
persistentvolume "pv04" deleted
---------------------------------------------------------------------
#删除时需要注意的是,首先删除PVC,因为PV一旦被占用,则无法进行删除,需要删除PVC释放PV资源
4.1 创建共享目录
//NFS服务器操作
[root@nfs pv3]#mkdir /nfs/k8s
[root@nfs pv3]#chmod -R 777 /nfs/k8s/
[root@nfs pv3]#vim /etc/exports
[root@nfs pv3]#cat /etc/exports
/nfs/k8s 192.168.83.0/24(rw,no_root_squash,sync)
[root@nfs pv3]#exportfs -r     #刷新配置
[root@nfs pv3]#showmount -e    #验证共享目录是否共享成功
Export list for nfs:
/nfs/k8s 192.168.83.0/24
4.2 部署NFS-CLIENT-PROVISIONER

在所有node节点上部署NFS-CLIENT-PROVISIONER镜像

从Docker仓库或其他可信来源下载NFS-CLIENT-PROVISIONER的Docker镜像。并确保每个节点上都有NFS服务

镜像下载地址:external-storage/nfs-client at master · kubernetes-retired/external-storage · GitHub

镜像包下载完毕后上传到node节点服务器,并使用docker命令生成镜像

//node01
[root@node01 opt]#ls nfs-client-provisioner.tar 
nfs-client-provisioner.tar
[root@node01 opt]#docker load -i nfs-client-provisioner.tar
8dfad2055603: Loading layer [==============================>]  4.284MB/4.284MB
a17ae64bae4f: Loading layer [==============================>]  2.066MB/2.066MB
bd01fa00617b: Loading layer [==============================>]  39.72MB/39.72MB
Loaded image: quay.io/external_storage/nfs-client-provisioner:latest



//node02
[root@node02 opt]#ls nfs-client-provisioner.tar 
nfs-client-provisioner.tar
[root@node01 opt]#docker load -i nfs-client-provisioner.tar
8dfad2055603: Loading layer [==============================>]  4.284MB/4.284MB
a17ae64bae4f: Loading layer [==============================>]  2.066MB/2.066MB
bd01fa00617b: Loading layer [==============================>]  39.72MB/39.72MB
Loaded image: quay.io/external_storage/nfs-client-provisioner:latest
4.3 创建Service Account

ServiceAccount是Kubernetes中的一种特殊类型的用户账户,用于为Pod中的进程提供身份验证和权限控制。为NFS-CLIENT-PROVISIONER创建一个ServiceAccount,可以确保它具有在集群中执行其职责所需的必要权限

[root@master01 pv]#vim service-account.yaml
[root@master01 pv]#cat service-account.yaml
apiVersion: v1
kind: ServiceAccount     #指定资源类型为用户
metadata:
  name: nfs-client       #指定用户名称
[root@master01 pv]#kubectl apply -f service-account.yaml 
serviceaccount/nfs-client created
[root@master01 pv]#kubectl get sa    #查看用户
NAME         SECRETS   AGE
default      1         13d
nfs-client   1         13s
4.4 创建集群角色并绑定

ClusterRole定义了集群级别的权限集,而ClusterRoleBinding则将这些权限集绑定到特定的ServiceAccount或用户。为NFS-CLIENT-PROVISIONER创建一个ClusterRole,并为其分配必要的权限(如监听apiserver、获取集群资源列表、创建和删除PV等),然后通过ClusterRoleBinding将其绑定到之前创建的ServiceAccount上。

[root@master01 pv]#kubectl explain clusterrole
#查看定义字段
4.4.1 创建clusterole

创建ClusterRole并添加相应的权限

[root@master01 pv]#vim cluster.yaml
[root@master01 pv]#cat cluster.yaml 
apiVersion: rbac.authorization.k8s.io/v1     #这表示使用的是RBAC API的版本1
kind: ClusterRole                            #定义一个集群级别的角色
metadata: 
  name: clusterrole-nfs        #ClusterRole的名称,用于在Kubernetes集群中唯一标识
rules:                         #ClusterRole中定义的具体权限列表
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
#第一个规则组
#apiGroups: [""]:表示核心API组,不包含任何前缀的API组
#resources: ["persistentvolumes"]:表示对持久卷(PersistentVolumes)的权限。
#verbs: 列出了可以执行的操作get(获取)、list(列表)、watch(监听)、create(创建)和delete(删除)
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
#第二各规则组,与第一个规则类似,但针对的是持久卷声明(PersistentVolumeClaims)
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
#第三个规则组
#apiGroups: ["storage.k8s.io"]:这是存储API组的名称
#resources: ["storageclasses"]:表示对存储类(StorageClasses)的权限。
#verbs: 列出了可以执行的操作,但仅允许读取操作(get、list和watch)
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
#定义了对Kubernetes事件(Events)的权限
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
#定义了对端点(Endpoints)的广泛权限,包括创建、删除、获取、列表、监听、补丁和更新
[root@master01 pv]#kubectl apply -f cluster.yaml 
clusterrole.rbac.authorization.k8s.io/clusterrole-nfs created
[root@master01 pv]#kubectl get clusterroles clusterrole-nfs -owide
NAME              CREATED AT
clusterrole-nfs   2024-05-29T09:30:10Z
4.4.2 集群角色绑定
[root@master01 pv]#vim clusterbind.yaml 
[root@master01 pv]#cat clusterbind.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding                #资源类型为ClusterRoleBinding,集群级别的角色绑定
metadata:
  name: nfs-client-clusterrolebinding   #定义资源名称
subjects:                               #定义了哪些用户或用户组会被授予权限
- kind: ServiceAccount                  #引用一个ServiceAccount
  name: nfs-client                      #ServiceAccount名称为nfs-client,这是之前创建的用户
  namespace: default                    #指定ServiceAccount所在命名空间
roleRef:                                #定义了该绑定所引用的ClusterRole
  kind: ClusterRole                     #正在引用一个ClusterRole
  name: clusterrole-nfs                 #ClusterRole的名称,上一步创建的ClusterRole名称
  apiGroup: rbac.authorization.k8s.io   #这是API组的名称,对于ClusterRole,它通常是rbac.authorization.k8s.io
[root@master01 pv]#kubectl apply -f clusterbind.yaml 
clusterrolebinding.rbac.authorization.k8s.io/nfs-client-clusterrolebinding created
[root@master01 pv]#kubectl get clusterrolebindings nfs-client-clusterrolebinding  -owide
NAME                            ROLE                      AGE   USERS   GROUPS   SERVICEACCOUNTS
nfs-client-clusterrolebinding   ClusterRole/clusterrole   69s                    default/nfs-client-nfs

5.创建NFS Provisioner

5.1 基本介绍

NFS Provisioner是一个自动配置卷程序,本质上就是一个pod,其主要功能是利用现有的和已配置的NFS服务器来支持通过持久卷声明动态配置Kubernetes持久卷

NFS Provisione(即 nfs-client),有两个功能:

①NFS Provisioner能够自动为Kubernetes集群中的Pod提供NFS持久卷。,在 NFS 共享目录下创建挂载点(volume),持久卷的名称遵循一定的格式,通常是namespace-{pvcName}-${pvName}。

②将 PV 与 NFS 的挂载点建立关联。

它的工作原理

当Kubernetes集群中的Pod需要访问NFS持久卷时,通过持久卷声明(PersistentVolumeClaim)来请求。NFS Provisioner会监听这些声明,并自动创建和配置相应的NFS持久卷

5.2 创建

使用Deployment创建nfs-client-provisioner,防止因为它发生故障时退出,导致NFS服务器无法使用

[root@master01 pv]#cat nfs-client-pro.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  strategy:                            #指定更新Pod的策略
    type: Recreate                     #更新Deployment时,将使用重建(Recreate)策略
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client   #指定Pod使用的ServiceAccount的名称
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest  #之前下载的镜像
          imagePullPolicy: IfNotPresent
          volumeMounts:                #定义容器内的挂载点,挂载到什么位置
            - name: nfs-k8s            #挂载卷名称。volumes定义的
              mountPath: /persistentvolumes #挂载到该路径
          env:                         #定义容器的环境变量。
            - name: PROVISIONER_NAME   #变量名称,配置provisioner的Name
              value: nfs-storage       #变量值,此值在建立StorageClass时使用
            - name: NFS_SERVER         #变量名称,指定NFS服务器
              value: 192.168.83.60     #NFS服务器地址或主机名
            - name: NFS_PATH           #变量名称,指定共享目录
              value: /nfs/k8s          #NFS共享目录
      volumes:                         #定义Pod中的卷
        - name: nfs-k8s                #卷的名称,与上面的volumeMounts定义中的名称相匹配
          nfs:                         #定义NFS卷的参数
            server: 192.168.83.60      #NFS服务器的地址
            path: /nfs/k8s             #NFS服务器上的共享路径

-------------------------------------------------------------------------------
Recreate(重建): 使用此策略时,Kubernetes会首先终止所有的旧Pods,然后等待这些Pods都被
完全删除并清理后,再创建新的Pods。这意味着在更新过程中,服务可能会经历一段不可用时间,因
为所有的Pods都会被同时替换。虽然这种方法可能导致服务中断,但它有时更简单、更可靠,特别是
当应用程序不支持滚动更新或者需要确保在更新过程中没有两个版本的Pods同时运行时。
[root@master01 pv]#kubectl apply -f nfs-client-pro.yaml 
deployment.apps/nfs-client-provisioner created
[root@master01 pv]#kubectl get deployments.apps nfs-client-provisioner 
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
nfs-client-provisioner   1/1     1            1           15s
[root@master01 pv]#kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-544dbf9f94-f948s   1/1     Running   0          45s

6. 创建StorageClass

负责建立 PVC 并调用 NFS provisioner 进行预定的工作,并让 PV 与 PVC 建立关联

定义StorageClass:StorageClass是Kubernetes中用于描述存储类的一种资源对象。通过定义StorageClass,可以指定如何为PVC提供后端存储(如NFS)。

在StorageClass中,可以指定Provisioner(如NFS-CLIENT-PROVISIONER)、存储类型、配置参数等。

StorageClass的作用:当PVC被创建时,Kubernetes会根据PVC的存储要求查找匹配的StorageClass,并委托给相应的Provisioner来创建满足要求的PV。因此,StorageClass是PVC和PV之间的桥梁,它使得Kubernetes能够根据PVC的要求动态地创建和管理PV。

[root@master01 pv]#cat nfs-storageclass.yaml 
apiVersion: storage.k8s.io/v1     #指定了Kubernetes API的版本和组
kind: StorageClass                #创建StorageClass资源
metadata:
  name: nfs-client-storageclass   #指定名称
provisioner: nfs-storage          
#指定了用于供应存储卷的供应器(provisioner)的名称
#与创建nfs-client-provisioner的PROVISIONER_NAME变量的值相同
parameters:                       #供应器需要的任何额外参数
  archiveOnDelete: "false"        #false表示在删除PVC时不会对数据进行存档,即删除数据

PROVISIONER:这是负责为PersistentVolumeClaims(PVCs)动态创建PersistentVolumes(PVs)的存储系统

RECLAIMPOLICY:定义了当PersistentVolume(PV)的声明(PVC)被删除时,PV应该怎么做。Delete策略意味着PV和它上面的数据将被删除。

VOLUMEBINDINGMODE:定义了如何以及何时将PersistentVolumeClaims(PVCs)绑定到PersistentVolumes(PVs)。Immediate模式意味着一旦PVC被创建,就会立即查找并绑定一个合适的PV。

ALLOWVOLUMEEXPANSION:定义了是否允许扩展已存在的PersistentVolume(PV)。设置为false表示不允许扩展。

7.创建PVC

7.1 关闭自链接

在创建PVC之前,首先需要修改以下APIserver的参数

vim /etc/kubernetes/manifests/kube-apiserver.yaml
.......
spec:
  containers:
  - command:
    - kube-apiserver
    - --feature-gates=RemoveSelfLink=false       #添加此字段

此字段用于关闭自链接(self-link)功能

在Kubernetes 1.20及更高版本中,由于API的更改,许多组件不再使用或提供自链接字段。当NFS Provisioner尝试访问PVC(Persistent Volume Claim)的自链接以创建PV时,可能会因为找不到该字段而报错。

报错示例

报错信息可能类似于“unexpected error getting claim reference: selfLink was empty, can't make reference”。

这表明Provisioner试图获取PVC的自链接,但发现它是空的

[root@master01 data]#kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml 
pod/kube-apiserver created
#更新apiserver
[root@master01 data]#kubectl get pod -n kube-system  |grep apiserver
kube-apiserver                     0/1     CrashLoopBackOff   1          19s
kube-apiserver-master01            1/1     Running            0          99s
[root@master01 data]#kubectl delete pod kube-apiserver -n kube-system 
pod "kube-apiserver" deleted
#删除之前的kube-apiserver
7.2 创建PVC
[root@master01 pv]#vim  pvc.yaml 
[root@master01 pv]#cat  pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs
spec:
  accessModes: ["ReadWriteMany"]
  storageClassName: nfs-client-storageclass   #指定关联StorageClass对象名称
  resources:
    requests:
      storage: 2Gi

PVC 通过 StorageClass 自动申请到空间

如果Provisioner没有创建PV,那么它的日志中可能包含有关为什么无法创建PV的详细信息。使用kubectl logs <nfs-provisioner-pod-name> -n <namespace>来获取日志

创建完pvc后,会在NFS服务器的共享目录中建立一个文件

[root@nfs nfs]#ls  /nfs/k8s/
default-pvc-nfs-pvc-e2f92c4e-a04c-4243-a131-566c0103717e
#自动创建的PV会以${namespace}-${pvcName}-${pvName}的目录格式放到NFS服务器上

8.创建Pod

[root@master01 pv]#vim pod.yaml
[root@master01 pv]#cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.18.0
    volumeMounts:
    - name: nfs-pvc
      mountPath: /usr/share/nginx/html
  volumes:
  - name: nfs-pvc
    persistentVolumeClaim:     #使用PersistentVolumeClaim作为卷源
      claimName: pvc-nfs       #引用之前创建的PersistentVolumeClaim的名称

在NFS服务器的PV目录上自定义一个web访问界面

创建pod后访问的页面通过挂载,就可以访问到PV的自定义web界面

总结

(一)PV

1.定义

PV是Kubernetes集群中的一块网络存储,它独立于Pod存在,并由管理员创建和配置。

PV可以是各种存储系统,如NFS、iSCSI、云提供商的存储、本地存储等。

PV定义了存储的容量、访问模式(ReadWriteOnce、ReadOnlyMany、ReadWriteMany)、存储类别等属性。

2.生命周期

PV的生命周期是独立于Pod的,即使Pod被删除,PV仍然存在,可以被其他Pod继续使用。

PV的状态包括可用(Available)、绑定(Bound)、释放(Released)、回收(Retained)等状态。

3.作用

PV具体对存储进行配置和分配,pod等资源可以使用PV抽象出来的存储资源。

PV提供了各种存储资源,如NFS、iSCSI等,为PVC提供实际存储的载体。

(二)PVC

1.定义

PVC是用户对存储资源的请求,它定义了Pod对存储的需求。

在创建Pod时,可以通过PVC来请求存储资源。

PVC可以指定所需的存储容量、访问模式等参数,但通常不需要指定具体的PV。

2.与PV的关系

PVC与PV之间是一种声明与提供的关系。

PVC声明了对存储资源的需求,而PV则是提供这些资源的实际载体。

当PVC被创建时,Kubernetes会尝试将其与满足其要求的PV进行绑定。

匹配的过程是根据PVC的标签选择器和PV的标签进行匹配,只有匹配成功的PV才能被绑定到PVC。

3.生命周期

PVC在绑定PV时,如果匹配到合适的PV,就与该PV进行绑定,Pod应用可以使用该PVC作为存储。

如果匹配不到合适的PV,PVC将处于Pending状态,直到有合适的PV可用为止。

4.作用

PVC使得Pod与具体的存储实现解耦,提高了可移植性。

通过PVC,开发人员不需要关心存储资源的实际位置和类型,只需要定义好存储需求即可。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NVR对接三方相机预览黑屏问题案例

一、 问题现象 【问题现象】NVR接入三方相机,通道状态显示在线,但本地、web预览显示黑屏。更换H.264&#xff0c;H.265均预览黑屏&#xff0c;且NVR侧的萤石云手机APP预览报错260025。 【现场拓扑】现场拓扑如下 &#xff08;1&#xff09; IPC使用onvif协议添加至NVR&#xff…

YOLOv5改进 | 主干网络 | 用repvgg模块替换Conv【教程+代码 】

&#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 尽管Ultralytics 推出了最新版本的 YOLOv8 模型。但YOLOv5作为一个anchor base的目标检测的算法&#xff0c;YOLOv5可能比YOLOv8的效果更好。…

IC617 虚拟机下载 RHEL6_ic617_hspice2015_spectre15

下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1kFEkq-SVkpSXcSS49THkiA?pwdtpm8 提取码&#xff1a;tpm8

tomcat学习--部署java项目

主流开发项目&#xff0c;springboot框架下&#xff0c;jar部署java传统的tomcat发布war包 一 什么是tomcat&#xff1f; 是一个用于运行java程序的软件&#xff0c;发布的时候&#xff1a;开发将源码使用maven打包&#xff0c;生产war包 二 安装tomcat tomcat是java写的&a…

磁带存储:“不老的传说”依然在继续

现在是一个数据指数增长的时代&#xff0c;根据IDC数据预测&#xff0c;2025年全世界将产生175ZB的数据。 这里面大部分数据是不需要存储的&#xff0c;在2025预计每年需要存储11ZB的数据。换算个容易理解的说法&#xff0c;1ZB是10^18Bytes, 相当于要写5556万块容量18TB的硬盘…

【介绍下运维开发】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【1.文件和目录相关(上)】

一、Linux的文件系统结构 1、Linux文件系统就是一个树形的分层组织结构。 2、文件系统层次结构标准FHS&#xff1a;用于规范文件目录命名和存放标准。 &#xff08;1&#xff09;/bin:是二进制英文缩写。 &#xff08;2&#xff09;/boot:存放的是系统启动时要用到的程序。 …

个股期权开户的准入条件

今天带你了解个股期权开户的准入条件。个股期权是一种金融行生品&#xff0c;投资者可以通过购买期权来获得在未来某个时间点以约定价格买入或卖出某只股票的权利&#xff0c;但不承担义务。 个股期权开户的准入条件 场外个股期权&#xff08;OTC股票期权&#xff09;相对于交…

【后端开发】服务开发场景之分布式(CAP,Raft,Gossip | API网关,分布式ID与锁 | RPC,Dubbo,Zookeeper)

【后端开发】服务开发场景之分布式&#xff08;CAP&#xff0c;Raft&#xff0c;Gossip | API网关&#xff0c;分布式ID与锁 | RPC&#xff0c;Dubbo&#xff0c;Zookeeper&#xff09; 文章目录 1、如何设计一个分布式系统&#xff1f;&#xff08;底层原理&#xff09;理论&a…

服务器感染了. rmallox勒索病毒,如何确保数据文件完整恢复?

导言&#xff1a; 近年来&#xff0c;随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显。其中&#xff0c;勒索病毒作为一种严重的网络威胁&#xff0c;对个人和企业数据造成了巨大的威胁。本文将重点介绍.rmallox勒索病毒的特点、传播途径以及应对策略&#xff0c;旨…

MySQL的安全性

给root用户设置密码 点击用户--下面三个账号双击--进行编辑 修改密码--修改完进行保存 关闭数据库后连接不上 重新编辑&#xff0c;设置密码 新建账号 填入信息--保存&#xff08;主机哪里要选择%&#xff09; 连接这个新的账号 点击连接--填写连接的名称&#xff0c;地址&…

如何编写高效的单片机代码?

单片机的程序比软开少一些&#xff0c;真正想编写出高效的代码&#xff0c;还是要积累很多年的。 在做研发工程师的10年里&#xff0c;我经历过几个公司&#xff0c;看过很多工程师写的代码&#xff0c;但真正能让我跪着看完的&#xff0c;极少。哪怕是大厂工程师&#xff0c;也…

【深度好文】AI企业融合联盟营销,做的好就是最大赢家!

AI工具市场正在迅速发展&#xff0c;现仍有不少企业陆续涌出&#xff0c;那么如何让你的工具受到目标群体的关注呢&#xff1f;这相比是AI工具营销人员一直在思考的问题。 即使这个市场正蓬勃发展&#xff0c;也无法保证营销就能轻易成功。AI工具虽然被越来越多人认可和接受&a…

短视频矩阵系统源码---开发BS架构B/S(Browser/Server Architecture)架构

短视频矩阵系统源头开发------- 第一款叫做筷子科技&#xff0c;这个筷子科技剪辑和发布都是没有问题的&#xff0c;但是前一段时间他的剪辑发个公告&#xff0c;每个账号只能发两条&#xff0c;另外它的唯一缺点就是它成本比较高的&#xff0c;入门门槛应该在12800左右&#…

Linux学习笔记(epoll,IO多路复用)

Linux learning note 1、epoll的使用场景2、epoll的使用方法和内部原理2.1、创建epoll2.2、使用epoll监听和处理事件 3、示例 1、epoll的使用场景 epoll的英文全称是extend poll&#xff0c;顾名思义是poll的升级版。常见的IO复用技术有select&#xff0c;poll&#xff0c;epo…

HaloDB 的 Oracle 兼容模式

↑ 关注“少安事务所”公众号&#xff0c;欢迎⭐收藏&#xff0c;不错过精彩内容~ 前倾回顾 前面介绍了“光环”数据库的基本情况和安装办法。 哈喽&#xff0c;国产数据库&#xff01;Halo DB! 三步走&#xff0c;Halo DB 安装指引 ★ HaloDB是基于原生PG打造的新一代高性能安…

海医大三院使用先进血管外科微创技术成功救治危重主动脉夹层患者

近日,上海东方肝胆外科医院血管外科周建教授团队采用主动脉弓分支型一体化移植物联合体外开窗技术,成功救治复杂危重主动脉夹层患者,为上海嘉定首例,彰显了上海东方肝胆外科医院血管外科的优势与特色。 患者谢先生,72岁,两周前突发剧烈胸背部撕裂样疼痛,休息后症状未能得到缓解…

MyBatis的坑(动态SQL会把0和空串比较相等为true)

文章目录 前言一、场景如下二、原因分析1. 源码分析2. 写代码验证 三、解决办法代码及执行结果如下 总结 前言 在开发过程中遇到MyBatis的动态SQL的if条件不生效的情况&#xff0c;但经过debuger发现并不是参数问题&#xff0c;已经拿到了参数并传给了MyBatis&#xff0c;且从表…

APP逆向之调试的开启

很基础的一个功能设置&#xff0c;大佬轻喷。 背景 在开始进行对APP逆向分析的时候&#xff0c;需要对APP打开调试模式。 打开调试的模式有多种方式可以通过直接改包方式也可以通过借助第三方工具进行打开调试模式。 下面就整理下这个打开调试模式的一些方式。 改包修改模…

计算机网络学习笔记——应用层

一、应用层概述 二、客户/服务器方式(C/S方式)和对等方式(P2P方式) 客户/服务器(Client/Server&#xff0c;C/S)方式 服务器总是处于运行状态&#xff0c;并等待客户的服务请求。服务器具有固定端口号(例如HTTP服务器的默认端口号为80)&#xff0c;而运行服务器的主机也具有固…