Kubernetes集群存储卷Valume介绍

目录

一、K8s 临时共享存储

1.1.emptyDir 存储卷

1.2. hostPath 存储卷

1.3. nfs 共享存储卷

二、PV 和 PVC

2.1.什么是PV 和 PVC

2.1.1 PV

2.1.2 PVC

2.2.PVC 的使用逻辑 

2.3.StorageClass

2.4. PV 和 PVC 之间相互作用

2.4.1 生命周期

2.4.2 PV 的状态 

2.4.3 PV 的创建到销毁 

2.5. 回收策略

2.5.1 概述

2.5.2 PV 相关操作

三、NFS 持久化存储使用 PV 和 PVC

3.1. NFS 静态 PV 创建

3.1.1 配置 nfs 存储

3.1.2 定义 PV

3.1.3 定义 PVC

3.1.4 测试访问

3.2.NFS 动态 PV 创建

3.2.1 安装 nfs,并配置 nfs 服务

3.2.2 创建 Service Account

3.2.3 使用 Deployment 来创建 NFS Provisioner

3.2.4 创建 StorageClass

3.2.5 创建 PVC 和 Pod 测试

四、总结

4.1. 相关概念

PV:k8s 指定的存储设备空间中创建可持续化的存储资源

4.2. 静态 PV 的使用

4.3. 动态 storage


容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume抽象就很好的解决了这些问题。Pod中的容器通过Pause容器共享Volume。
 

一、K8s 临时共享存储

emptyDir、hostPath 和 nfs 是 Kubernetes 中用于临时存储或共享存储的不同类型的卷(Volume)。

1.1.emptyDir 存储卷

是一种空目录卷,与 Pod 的生命周期绑定。当 Pod 被删除时,其中的数据也会被清除。简单地说:其作用就是做容器与容器之前的共享存储。

当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir 中的数据将被永久删除。

定义了一个 Pod,其中包含两个容器,一个是名为 "myapp" 的容器,另一个是名为 "busybox" 的容器。这两个容器共享一个名为 "html" 的空目录卷,其中 busybox 容器会周期性地向 "/data/index.html" 文件写入当前时间。

① 定义容器

[root@master01 volumes]# vim pod01.yaml
apiVersion: v1
kind: Pod
kind: Pod
metadata:
  name: pod-emptydir
  namespace: default
  labels:
    app: myapp
spec:
  containers:
  - name: myapp
    image: nginx:1.14
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    volumeMounts:                        # 挂载卷到容器中
    - name: html                         # 挂载名为 "html" 的卷
# 使用的存储卷名称,如果跟下面volume字段name值相同,则表示使用volume的这个存储卷
      mountPath: /usr/share/nginx/html/  # 将卷挂载到容器内的路径 "/usr/share/nginx/html/
  - name: busybox                        # 容器名称
    image: busybox:latest                # 镜像
    imagePullPolicy: IfNotPresent        # 镜像拉取策略为如果本地没有则拉取外网
    volumeMounts:                        # 挂载卷到容器中
    - name: html                         # 挂载名为 "html" 的卷
      mountPath: /data/                  # 将卷挂载到容器内的路径 "/data/
    command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
# 定义容器启动时执行的命令,这里是一个循环脚本,每隔 2 秒将当前时间写入到 "/data/index.html" 文件中
  volumes:         # 定义Pod中使用的卷
  - name: html     # 定义名为"html"的卷
    emptyDir: {}   
# 使用空目录作为卷,这意味着这个卷的生命周期与Pod相关联,当Pod删除时,卷中的数据也会被清除

② 启动 pod 

[root@master01 volumes]# kubectl apply -f pod01.yaml 
pod/pod-emptydir created
[root@master01 volumes]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-emptydir   2/2     Running   0          15s   10.244.2.26   node02   <none>           <none>

③ 访问页面

[root@master01 volumes]# curl 10.244.2.26
Wed May 29 08:17:52 UTC 2024
Wed May 29 08:17:54 UTC 2024
Wed May 29 08:17:56 UTC 2024
Wed May 29 08:17:58 UTC 2024

④ 进入容器查看挂载目录详情

[root@master01 volumes]# kubectl exec -it pod-emptydir -c busybox sh
# -c busybox: 指定要在哪个容器中执行命令,这里是在名为 "busybox" 的容器中执行。
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # cat /data/index.html 
Wed May 29 08:17:52 UTC 2024
Wed May 29 08:17:54 UTC 2024
Wed May 29 08:17:56 UTC 2024
Wed May 29 08:17:58 UTC 2024

小结:emptyDir 存储卷可以实现 pod 中的容器之间共享、存储数据,但是不能做持久化,会随着 pod 生命周期结束而删除。

1.2. hostPath 存储卷

允许将主机节点上的文件系统目录直接挂载到容器中,不需要网络存储。这种卷类型不具备跨节点或持久性。

hostPath 卷将 node 节点的文件系统中的文件或目录挂载到集群中;hostPath 可以实现持久存储,但是在 node 节点故障时,也会导致数据的丢失。

即在多节点集群中,某一个节点故障,数据会有缺省。保存自己的数据在当前磁盘中,并不能保证拥有所有的数据。

① 在 node01、node02 节点上创建挂载目录

[root@node01 volumes]# pwd
/data/volumes
[root@node01 volumes]# echo "node01.com" > index.html
 
[root@node02 volumes]# echo "node02.com" > index.html

② 创建 Pod 资源

[root@master01 volumes]# vim pod02.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-hostpath
  namespace: default
spec:
  containers:
  - name: myapp
    image: nginx:1.14
    volumeMounts:# 定义容器挂载内容
    - name: html # 使用的存储卷名称,如果跟下面volume字段name值相同,则表示使用volume的这个存储卷
      mountPath: /usr/share/nginx/html # 挂载至容器中哪个目录
      readOnly: false # 读写挂载方式,默认为读写模式false,这里表示可读可写
  volumes:
# volumes字段定义了paues容器关联的宿主机或分布式文件系统存储卷
    - name: html  # 存储卷名称
      hostPath:   # 路径,为宿主机存储路径
        path: /data/volumes  # 在宿主机上目录的路径
        type: DirectoryOrCreate  # 定义类型,这表示如果宿主机没有此目录则会自动创建

③ 创建 pod

[root@master01 volumes]# kubectl apply -f pod02.yaml
pod/pod-hostpath created
[root@master01 volumes]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-hostpath   1/1     Running   0          6s    10.244.2.27   node02   <none>           <none>

④ 访问页面

[root@master01 volumes]# curl 10.244.2.27
node02.com

⑤ 删除 pod,再重建,验证是否依旧可以访问原来的内容 

[root@master01 volumes]# kubectl delete -f pod02.yaml
pod "pod-hostpath" deleted
[root@master01 volumes]# kubectl apply -f pod02.yaml
pod/pod-hostpath created
[root@master01 volumes]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-hostpath   1/1     Running   0          8s    10.244.2.28   node02   <none>           <none>
[root@master01 volumes]# curl 10.244.2.28
node02.com
# node节点存储数据,pod故障重新建立后依然可以访问到原来的数据

小结:可以实现持久化存储,使用 node 节点的目录或文件挂载到容器。但是存储空间会受到 node 单机限制,node 节点故障数据会丢失,pod 跨节点不能共享数据。

1.3. nfs 共享存储卷

允许将 NFS(Network File System)挂载到 Pod 中,提供跨节点的共享存储功能。是一个共享存储服务,而不是一个真正意义上的存储。

① 设置共享目录

[root@localhost ~]# mkdir /data/volumes -p;chmod 777 /data/volumes
[root@localhost ~]# vim /etc/exports
/data/volumes 192.168.190.0/24(rw,no_root_squash)
 
# /data/volumes: 这是要共享的目录路径,即将在网络上共享的目录
# 192.168.190.0/24: 这是被授权访问该共享目录的 IP 地址范围
# rw: 表示该共享目录是可读写的,允许客户端对共享目录进行读写操作
# no_root_squash: 这是一种权限配置,表示当 root 用户(UID为0)从客户端访问共享目录时,其权限不会被限制,仍然拥有root权限
# 表示将 /data/volumes 目录共享给 192.168.190.0/24 子网范围内的设备,允许读写操作,并且不限制 root 用户的权限

② 启动远程连接和 NFS 服务

[root@localhost ~]# systemctl start rpcbind
[root@localhost ~]# systemctl start nfs
[root@localhost ~]# hostnamectl set-hostname nfs
[root@localhost ~]# bash
[root@nfs ~]# showmount -e
Export list for nfs:
/data/volumes 192.168.190.0/24
 
node节点添加地址映射:
echo 192.168.190.104 nfs >> /etc/hosts

③ master 节点定义 pod 容器 yaml

[root@master01 volumes]# vim pod-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nfs
  namespace: default
spec:
  containers:
  - name: myapp
    image: nginx:1.14
    volumeMounts:           # 挂载卷到容器中
    - name: html            # 定义了要挂载的卷的名称为"html"
      mountPath: /usr/share/nginx/html # 将卷挂载到容器中的路径为"/usr/share/nginx/html"
  volumes:                  # 卷部分,定义了Pod中使用的卷的配置
    - name: html            # 卷的名称
      nfs:                  # NFS类型的卷
        path: /data/volumes # NFS服务器上共享目录的路径
        server: nfs         # 指定了NFS服务器的地址为nfs,也可写ip地址

④ 启动 pod

[root@master01 volumes]# kubectl apply -f pod-nfs.yaml
[root@master01 volumes]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
pod-nfs   1/1     Running   0          2m19s   10.244.1.189   node01   <none>           <none>

⑤ 在 nfs 服务器上创建 index.html

[root@nfs ~]# cd /data/volumes/
[root@nfs volumes]# echo "hello nfs" > index.html

⑥ master 节点访问页面

[root@master01 volumes]# curl 10.244.1.189
hello nfs

⑦ 删除 nfs 相关 pod,再重新创建,可以得到数据的持久化存储

[root@master01 volumes]# kubectl apply -f pod-nfs.yaml 
pod/pod-nfs created
[root@master01 volumes]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-nfs   1/1     Running   0          3s    10.244.2.29   node02   <none>           <none>
[root@master01 volumes]# curl 10.244.2.29
hello nfs

小结:由此可以实现持久化存储,使用 nfs 将存储设备空间挂载到容器中,pod 可以跨 node 节点共享数据。

二、PV 和 PVC

PV 是集群中的资源。 PVC 是对这些资源的请求,也是对资源的索引检查。

2.1.什么是PV 和 PVC

2.1.1 PV

PV 全称叫做 Persistent Volume,持久化存储卷。它是用来描述或者说用来定义一个存储卷的,这个通常都是由运维工程师来定义。可以理解为磁盘分区。

2.1.2 PVC

PVC 的全称是 Persistent Volume Claim,是持久化存储的请求。它是用来描述希望使用什么样的或者说是满足什么条件的 PV 存储。可以理解为磁盘的请求。

① 在 Pod 配置中定义使用 PVC 类型的卷并挂载到容器中

② 用户或者开发人员定义一个 PVC 类型的卷(空间大小和访问模式)

③ 运维人员会从存储设备中创建 N 多个 PV 资源(空间大小和访问模式)形成 PV 池

④ Pod 就会通过 PVC 向 PV 池中请求符合条件的 PV 存储资源供容器使用

2.2.PVC 的使用逻辑 

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

PV 就是把多个存储集合在一起,然后进行分区,最后给逻辑分区 PVC 使用。类似于 LV 逻辑卷底层有多个磁盘组成的一个卷组进行分区。

PVC 主要用于请求硬盘上的数据,并将这些数据挂载到Pod中的容器中。

2.3.StorageClass

StorageClass 是 Kubernetes 中用来定义动态存储卷的对象。它允许管理员定义不同类型的存储,以及如何动态地提供这些存储。通过 StorageClass,用户可以根据自己的需求请求不同类型的存储,并且 Kubernetes 会根据 StorageClass 的定义动态地创建 PersistentVolume 来满足这些请求。

上面介绍的 PV 和 PVC 模式是需要运维人员先创建好 PV,然后开发人员定义好 PVC 进行一对一的 Bond,但是如果 PVC 请求成千上万,那么就需要创建成千上万的 PV,对于运维人员来说维护成本很高,Kubernetes 提供一种自动创建 PV 的机制,叫 StorageClass,它的作用就是创建 PV 的模板。

创建 StorageClass 需要定义 PV 的属性,比如存储类型、大小等;另外创建这种 PV 需要用到的存储插件,比如 GFS、Ceph(插件)等。 有了这两部分信息,Kubernetes 就能够根据用户提交的 PVC,找到对应的 StorageClass,然后 Kubernetes 就会调用 StorageClass 声明的存储插件,自动创建需要的 PV 并进行绑定。

2.4. PV 和 PVC 之间相互作用

2.4.1 生命周期

5 个阶段:

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 以便下次使用,也可以直接从云存储中删除

2.4.2 PV 的状态 

根据这 5 个阶段,PV 的状态有以下 4 种:

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

2.4.3 PV 的创建到销毁 

① 一个 PV 创建完后状态会变成 Available,等待被 PVC 绑定

② 一旦被 PVC 邦定,PV 的状态会变成 Bound,就可以被定义了相应 PVC 的 Pod 使用

③ Pod 使用完后会释放 PV,PV 的状态变成 Released

④ 变成 Released 的 PV 会根据定义的回收策略做相应的回收工作。有三种回收策略,Retain、Delete 和 Recycle

2.5. 回收策略

2.5.1 概述

PV 是 Kubernetes 中用于表示持久化存储资源的对象。它可以与 Pod 绑定,使 Pod 能够访问和使用持久化存储。在创建 PV 时,可以指定回收策略来定义当 PV 不再使用时如何处理。

目前,Kubernetes 提供了三种 PV 回收策略:

  • Retain(保留):当 PV 不再使用时,保留 PV 的状态和数据,不进行自动删除。管理员需要手动清理 PV 中的数据;
  • Delete(删除):当 PV 不再使用时,自动删除 PV 对象及其关联的存储资源,包括 PV 中的数据;
  • Recycle(回收):已被弃用,不再推荐使用。该策略在 PV 不再使用时会尝试清理 PV 中的数据,但不会删除 PV 对象本身。

2.5.2 PV 相关操作

① 查看 pv 的定义方式 

kubectl explain pv
metadata:  
#由于PV是集群级别的资源,即PV可以跨namespace使用,所以PV的metadata中不用配置namespace

② 查看 pv 定义的规格

kubectl explain pv.spec
spce:
  nfs:(定义存储类型)
    path:(定义挂载卷路径)
    server:(定义服(定义访问模型,务器名称)
  accessModes:有以下三种访问模型,以列表的方式存在,也就是说可以定义多个访问模式) * * *
    - ReadWriteOnce          #(RWO)存储可读可写,但只支持被单个 Pod 挂载
	- ReadOnlyMany           #(ROX)存储可以以只读的方式被多个 Pod 挂载
	- ReadWriteMany          #(RWX)存储可以以读写的方式被多个 Pod 共享
# nfs 支持全部三种;iSCSI 不支持 ReadWriteMany(iSCSI 就是在 IP 网络上运行 SCSI 协议的一种网络存储技术)
# HostPath 不支持 ReadOnlyMany 和 ReadWriteMany。

③ 相关属性

  capacity:(定义存储能力,一般用于设置存储空间)
    storage: 2Gi (指定大小)
  storageClassName: (自定义存储类名称,此配置用于绑定具有相同类别的PVC和PV)
  persistentVolumeReclaimPolicy: Retain   

④ PV 和 PVC 中的 spec 关键字段要匹配

比如存储(storage)大小、访问模式(accessModes)、存储类名称(storageClassName)

kubectl explain pvc.spec
spec:
  accessModes: (定义访问模式,必须是PV的访问模式的子集)
  resources:
    requests:
      storage: (定义申请资源的大小)
  storageClassName: (定义存储类名称,此配置用于绑定具有相同类别的PVC和PV)

三、NFS 持久化存储使用 PV 和 PVC

3.1. NFS 静态 PV 创建

静态PV是提前创建的PV对象,它代表了一个具体的存储卷,并与NFS服务器上的实际存储位置相对应。

3.1.1 配置 nfs 存储

nfs节点操作:
[root@nfs ~]# cd /data/volumes/
[root@nfs volumes]# mkdir v{1,2,3,4,5}
[root@nfs volumes]# vim /etc/exports
/data/volumes/v1 192.168.190.0/24(rw,no_root_squash)
/data/volumes/v2 192.168.190.0/24(rw,no_root_squash)
/data/volumes/v3 192.168.190.0/24(rw,no_root_squash)
/data/volumes/v4 192.168.190.0/24(rw,no_root_squash)
/data/volumes/v5 192.168.190.0/24(rw,no_root_squash)
 
[root@nfs volumes]# exportfs -arv
exporting 192.168.190.0/24:/data/volumes/v5
exporting 192.168.190.0/24:/data/volumes/v4
exporting 192.168.190.0/24:/data/volumes/v3
exporting 192.168.190.0/24:/data/volumes/v2
exporting 192.168.190.0/24:/data/volumes/v1
# 重新导出所有在/etc/exports文件中定义的共享目录,并显示详细的导出信息
# -a:导出所有已经在/etc/exports文件中定义的共享目录。
# -r:重新导出所有已经在/etc/exports文件中定义的共享目录,即使它们已经在之前导出过了。
# -v:显示详细的导出信息,包括导出的目录、客户端IP地址和访问权限等。
 
[root@nfs volumes]# showmount -e
Export list for nfs:
/data/volumes/v5 192.168.190.0/24
/data/volumes/v4 192.168.190.0/24
/data/volumes/v3 192.168.190.0/24
/data/volumes/v2 192.168.190.0/24
/data/volumes/v1 192.168.190.0/24
# 列出NFS服务器上已经导出的共享目录列表

3.1.2 定义 PV

这里定义5个 PV,并且定义挂载的路径以及访问模式,还有 PV 划分的大小。

① 定义 PV yaml

[root@nfs volumes]# vim pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
spec:
  nfs:                     # 使用NFS作为存储后端
    path: /data/volumes/v1 # NFS服务器上的共享路径    
    server: nfs            # NFS服务器的地址                                                                                                                                                                                     
  accessModes: ["ReadWriteMany","ReadWriteOnce"] # 定义访问模式为多次读写和单次读写
  capacity:                # 容量部分开始
    storage: 1Gi           # 指定存储容量为1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels:
    name: pv002
spec:
  nfs:
    path: /data/volumes/v2
    server: stor01
  accessModes: ["ReadWriteOnce"] # 定义访问模式为单次读写
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels:
    name: pv003
spec:
  nfs:
    path: /data/volumes/v3
    server: stor01
  accessModes: ["ReadWriteMany","ReadWriteOnce"] # 定义访问模式为多次读写和单次读写
  capacity:
    storage: 3Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
  labels:
    name: pv004
spec:
  nfs:
    path: /data/volumes/v4
    server: stor01
  accessModes: ["ReadWriteMany","ReadWriteOnce"] # 定义访问模式为多次读写和单次读写
  capacity:
    storage: 4Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
  labels:
    name: pv005
spec:
  nfs:
    path: /data/volumes/v5
    server: stor01
  accessModes: ["ReadWriteMany","ReadWriteOnce"] # 定义访问模式为多次读写和单次读写
  capacity:
    storage: 5Gi

② 启动 PV,查看 PV 信息

[root@master01 volumes]# kubectl apply -f pv-demo.yaml
 
[root@master01 volumes]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv001   1Gi        RWO,RWX        Retain           Available                                   7s
pv002   2Gi        RWO            Retain           Available                                   7s
pv003   3Gi        RWO,RWX        Retain           Available                                   7s
pv004   4Gi        RWO,RWX        Retain           Available                                   7s
pv005   5Gi        RWO,RWX        Retain           Available                                   7s

3.1.3 定义 PVC

这里定义了 pvc 的访问模式为多路读写,该访问模式必须在前面 pv 定义的访问模式之中。定义 PVC 申请的大小为 2Gi,此时 PVC 会自动去匹配多路读写且大小为 2Gi 的 PV,匹配成功获取 PVC 的状态即为 Bound。

① 定义 PVC yaml

[root@master01 volumes]# vim pod-vol-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim       # 定义资源类型为 PersistentVolumeClaim
metadata:
  name: mypvc
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]  # 定义访问模式为多次读写
  resources:                      # 资源部分开始
    requests:                     # 请求部分开始
      storage: 2Gi                # 请求 2Gi 存储容量
---
apiVersion: v1
kind: Pod                         # 定义资源类型为 Pod
metadata:
  name: pod-vol-pvc
  namespace: default
spec:
  containers: 
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:                 # 挂载部分开始
    - name: html                  # 挂载的名称为 html
      mountPath: /usr/share/nginx/html # 挂载到容器中的路径为 /usr/share/nginx/html
  volumes:                        # 卷部分开始
    - name: html                  # 卷的名称为 html
      persistentVolumeClaim:      # 持久卷声明部分开始
        claimName: mypvc          # 使用名称为 mypvc 的持久卷声明

② 启动 PV,查看 PV、PVC 信息

[root@master01 volumes]# kubectl apply -f pod-vol-pvc.yaml
[root@master01 volumes]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLASS   REASON   AGE
pv001   1Gi        RWO,RWX        Retain           Available                                           6m30s
pv002   2Gi        RWO            Retain           Available                                           6m30s
pv003   3Gi        RWO,RWX        Retain           Bound       default/mypvc                           6m30s
pv004   4Gi        RWO,RWX        Retain           Available                                           6m30s
pv005   5Gi        RWO,RWX        Retain           Available                                           6m30s
[root@master01 volumes]# kubectl get pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv003    3Gi        RWO,RWX                       20s

3.1.4 测试访问

在存储服务器上创建 index.html,并写入数据,通过访问 Pod 进行查看,可以获取到相应的页面。

① nfs 节点创建页面

[root@nfs volumes]# cd /data/volumes/v3/
[root@nfs v3]# echo "welcome to use pv3" > index.html

② master 节点查看 pvc 详情,访问 ip

[root@master01 volumes]# kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
pod-nfs       1/1     Running   0          5h32m   10.244.2.29    node02   <none>           <none>
pod-vol-pvc   1/1     Running   0          2m10s   10.244.1.190   node01   <none>           <none>
[root@master01 volumes]# curl 10.244.1.190
welcome to use pv3

3.2.NFS 动态 PV 创建

搭建 StorageClass + NFS,实现 NFS 的动态 PV 创建。Kubernetes 本身支持的动态 PV 创建不包括 NFS,所以需要使用外部存储卷插件分配PV。

在 Kubernetes 中,卷插件是用于管理卷的插件,而 Provisioner 是用于指定 Volume 插件的类型的组件。卷插件可以分为内置插件和外部插件两种类型。内置插件是 Kubernetes 自带的插件,例如 kubernetes.io/aws-ebs。而外部插件则是由第三方提供的插件,例如 ceph.com/cephfs。

NFS 是一种外部插件,它使用的是 nfs-client。外部插件可以使用已经配置好的存储服务器来创建卷,这样可以方便地将 Kubernetes 集群与现有的存储系统集成起来。例如,ceph.com/cephfs 就是一个由 Ceph 提供的外部插件,可以将 Kubernetes 集群与 Ceph 存储系统集成起来,从而实现高可用性和可扩展性。

PV(Persistent Volume)是 Kubernetes 中的持久卷,它是一种独立于 Pod 的存储资源。外部 PV 是一种由集群外部的存储系统提供的持久卷,它可以通过 Provisioner 自动创建。例如,NFS 就是一种外部 PV,它可以使用已经配置好的 NFS 服务器来创建持久卷。

3.2.1 安装 nfs,并配置 nfs 服务

在nfs节点上:
[root@nfs ~]# mkdir /opt/k8s
[root@nfs ~]# chmod 777 /opt/k8s/
[root@nfs ~]# vim /etc/exports
/opt/k8s 192.168.190.0/24(rw,no_root_squash,sync)
# 允许192.168.190.0/24网段的主机以读写模式挂载/opt/k8s目录,并且不进行root权限转换(norootsquash),并同步写入(sync)
[root@nfs ~]# systemctl restart nfs

3.2.2 创建 Service Account

创建 Service Account,用来管理 NFS Provisioner 在 k8s 集群中运行的权限,设置 nfs-client 对 PV,PVC,StorageClass 等的规则。

Service Account 是 Kubernetes 中用于身份验证和授权的实体。它是一个用于标识和验证 Pod 或其他资源的身份的对象。每个 Pod 都可以关联一个 Service Account,用于在集群内部进行身份验证和授权操作。

① 创建 Service Account 账户,用来管理 NFS Provisioner 在 k8s 集群中运行的权限

[root@master01 volumes]# vim nfs-client-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
---
#创建集群角色
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-client-provisioner-clusterrole # 指定了ServiceAccount的名称
rules:
  - apiGroups: [""]                        # 指定了API组为空,表示操作核心API
    resources: ["persistentvolumes"]                    # 可操作的资源类型
    verbs: ["get", "list", "watch", "create", "delete"] # 允许的操作
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
---
#集群角色绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: nfs-client-provisioner-clusterrolebinding #指定了ClusterRoleBinding的名称
subjects:                            #定义了与ClusterRoleBinding关联的主体
- kind: ServiceAccount                     # 主体的类型
  name: nfs-client-provisioner             # 主体的名称
  namespace: default                       # 主体所在的命名空间
roleRef:                                   # 定义了与ClusterRoleBinding关联的角色引用
  kind: ClusterRole                        # 指定了角色引用的类型为ClusterRole
  name: nfs-client-provisioner-clusterrole # 角色引用的名称
  apiGroup: rbac.authorization.k8s.io      # 角色引用的 API 组

② 执行 yaml

[root@master01 volumes]# kubectl apply -f nfs-client-rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-clusterrole created
clusterrolebinding.rbac.authorization.k8s.io/nfs-client-provisioner-clusterrolebinding created
# 该配置文件中定义了一个ServiceAccount、一个ClusterRole和一个ClusterRoleBinding,并将它们关联起来

3.2.3 使用 Deployment 来创建 NFS Provisioner

NFS Provisione(即 nfs-client),有两个功能:一个是在 NFS 共享目录下创建挂载点(volume),另一个则是将 PV 与 NFS 的挂载点建立关联。

NFS Provisioner 是 Kubernetes 中的一个动态卷配置器(Dynamic Provisioner),它可以自动创建和管理 NFS 存储卷。它是一个 Kubernetes 插件,可以在 Kubernetes 集群中使用,以便在需要时自动创建和管理 NFS 存储卷。

由于 1.20 版本启用了 selfLink,所以 k8s 1.20+ 版本通过 nfs provisioner 动态生成pv会报错,解决方法如下:

spec:
  containers:
  - command:
    - kube-apiserver
    - --feature-gates=RemoveSelfLink=false # 添加这一行
    - --advertise-address=192.168.190.100
……
 
[root@master01 volumes]# kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
pod/kube-apiserver created
# 更新kube-apiserver.yaml
 
[root@master01 volumes]# kubectl delete pods kube-apiserver -n kube-system 
pod "kube-apiserver" deleted
# 删除kube-apiserver的Pod以便更改生效
 
[root@master01 volumes]# kubectl get pods -n kube-system | grep apiserver
kube-apiserver-master01            1/1     Running   0          13d
# 检查kube-apiserver的Pod是否重新启动

① 创建 NFS Provisioner

[root@master01 volumes]# vim nfs-client-provisioner.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner # 指定Service Account账户
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: nfs-storage       
# 配置provisioner的Name,确保该名称与StorageClass资源中的provisioner名称保持一致
            - name: NFS_SERVER
              value: nfs               # 配置绑定的nfs服务器
            - name: NFS_PATH
              value: /opt/k8s          # 配置绑定的nfs服务器目录
      volumes:                         # 申明nfs数据卷
        - name: nfs-client-root
          nfs:
            server: nfs
            path: /opt/k8s

② node 节点导入镜像

[root@node01 ~]# docker load -i nfs-client-provisioner.tar
[root@node02 ~]# docker load -i nfs-client-provisioner.tar

③ 执行 yaml

[root@master01 volumes]# kubectl apply -f nfs-client-provisioner.yaml 
deployment.apps/nfs-client-provisioner created
[root@master01 volumes]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-5f7484cd44-ls45v   1/1     Running   0          9s
pod-nfs                                   1/1     Running   0          6h29m
pod-vol-pvc                               1/1     Running   0          59m

3.2.4 创建 StorageClass

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

在 Kubernetes 中,StorageClass 是一种资源对象,用于定义动态存储卷的类型和属性。它允许管理员为不同的存储需求定义不同的存储类别,并将这些存储类别分配给不同的应用程序或命名空间。

① 创建 yaml

 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client-storageclass
provisioner: nfs-storage     
# 这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
parameters:
  archiveOnDelete: "false"  
# false表示在删除PVC时不会对数据进行存档,即删除数据

② 执行 yaml

[root@master01 volumes]# kubectl apply -f nfs-client-storageclass.yaml
storageclass.storage.k8s.io/nfs-client-storageclass created
[root@master01 volumes]# kubectl get storageclass
NAME                      PROVISIONER   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client-storageclass   nfs-storage   Delete          Immediate           false                  8s

3.2.5 创建 PVC 和 Pod 测试

① 创建 PVC yaml

[root@master01 volumes]# vim test-pvc-pod.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs-client-storageclass    #关联StorageClass对象
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: test-storageclass-pod
spec:
  containers:
  - name: busybox
    image: busybox:latest
    imagePullPolicy: IfNotPresent
    command:
    - "/bin/sh"
    - "-c"
    args:
    - "sleep 3600"
    volumeMounts:
    - name: nfs-pvc
      mountPath: /mnt
  restartPolicy: Never
  volumes:
  - name: nfs-pvc
    persistentVolumeClaim:
      claimName: test-nfs-pvc      #与PVC名称保持一致

② 启动 pvc ymal

[root@master01 volumes]# kubectl apply -f test-pvc-pod.yaml
persistentvolumeclaim/test-nfs-pvc created
pod/test-storageclass-pod configured

③ PVC 通过 StorageClass 自动申请到空间

[root@master01 volumes]# kubectl get pvc
NAME           STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS              AGE
mypvc          Bound    pv003                                      3Gi        RWO,RWX                                  97m
test-nfs-pvc   Bound    pvc-4b6ef65e-f9d8-4054-b148-f5be744f7fcb   2Gi        RWX            nfs-client-storageclass   3s

④ 查看 NFS 服务器上是否生成对应的目录,自动创建的 PV 会以 ${namespace}-${pvcName}-${pvName} 的目录格式放到 NFS 服务器上

[root@nfs ~]# ls /opt/k8s/
default-test-nfs-pvc-pvc-4b6ef65e-f9d8-4054-b148-f5be744f7fcb

⑤ 进入 Pod 在挂载目录 /mnt 下写一个文件,然后查看 NFS 服务器上是否存在该文件

[root@master01 volumes]# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
nfs-client-provisioner-5f7484cd44-ls45v   1/1     Running   0          46m     10.244.2.30    node02   <none>           <none>
pod-nfs                                   1/1     Running   0          7h15m   10.244.2.29    node02   <none>           <none>
pod-vol-pvc                               1/1     Running   0          105m    10.244.1.190   node01   <none>           <none>
test-storageclass-pod                     1/1     Running   0          8m19s   10.244.1.191   node01   <none>           <none>
[root@master01 volumes]# kubectl exec -it test-storageclass-pod sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # echo "welcome" > /mnt/1.txt
 
[root@nfs ~]# cd /opt/k8s/
[root@nfs k8s]# ls
default-test-nfs-pvc-pvc-4b6ef65e-f9d8-4054-b148-f5be744f7fcb
[root@nfs k8s]# cd default-test-nfs-pvc-pvc-4b6ef65e-f9d8-4054-b148-f5be744f7fcb/
[root@nfs default-test-nfs-pvc-pvc-4b6ef65e-f9d8-4054-b148-f5be744f7fcb]# ls
1.txt
[root@nfs default-test-nfs-pvc-pvc-4b6ef65e-f9d8-4054-b148-f5be744f7fcb]# cat 1.txt 
welcome

发现 NFS 服务器上存在,说明验证成功。

四、总结

4.1. 相关概念

PV:k8s 指定的存储设备空间中创建可持续化的存储资源

PVC:是对 PV 存储资源请求和绑定

StorageClass:可简称 sc 类型(存储类型)联动存储插件动态创建 pv 资源

4.2. 静态 PV 的使用

① 准备存储设备和共享目录

② 创建 pv资源,配置存储类型、访问模式、存储的能力大小

③ 创建 pvc 资源,并且配置请求 pv 资源的访问模式和存储大小,绑定 pv,pvc 和 pv 是一对一的绑定关系

pv 访问模式中必须支持 pvc 请求访问模式:

请求的存储空间优先选择相等存储大小的 pv 资源 ,如果没有会选择大于请求的存储大小 pv 资源

④ 创建 Pod 资源 存储类设置 persistentVolumeClaim 在容器配置存储挂载

4.3. 动态 storage

① 准备 NFS 共享服务器和共享目录

② 创建 sa 服务账号 进行 RBAC 资源操作权限的授权

③ 创建 nfs-client-provistioner 存储插件(以pod形式运行的) 配置中关联 sa 服务账号,使存储插件获得相关资源的操作权限

④ 创建 storageclass 资源,配置中关联存储插件的名称配置

以上过程一劳永逸,以后只需要创建 pvc 资源就可以动态生成相关 pv 资源

⑤ 创建 pvc 资源,配置中关联 storageClass 资源的名称,此时会在 NFS 服务器上生成相关的 pv 共享目录,目目名 ${namespace}${pvcname}${pvname}格式命名

⑥ 创建 pod 资源存储类型设置成 PersistentVolumeclaim ,在容器中配置存储挂载即可

  • 10
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值