K8s存储管理——volume、pv、pvc

本文详细介绍了Kubernetes中各种存储卷的使用,包括emptyDir、hostPath和NFS。重点讲解了PersistentVolume(PV)和PersistentVolumeClaim(PVC)的概念,以及它们如何实现存储的抽象和管理。此外,还展示了如何通过NFS实现跨节点的共享存储,并通过PV和PVC的示例,演示了动态创建和绑定过程。最后,讨论了PV和PVC的生命周期以及回收策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

介绍

前言

emptyDir存储卷

hostPath存储卷(本地)

NFS共享存储卷

PV、PVC

        NFS使用pv、pvc

介绍

---------来自官方文档

存储的管理是一个与计算实例的管理完全不同的问题。PersistentVolume 子系统为用户 和管理员提供了一组 API,将存储如何供应的细节从其如何被使用中抽象出来。 为了实现这点,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。

持久卷(PersistentVolume,PV)是集群中的一块存储,可以由管理员事先供应,或者 使用存储类(Storage Class)来动态供应。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样,也是使用 卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

持久卷申领(PersistentVolumeClaim,PVC)表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)。

尽管 PersistentVolumeClaim 允许用户消耗抽象的存储资源,常见的情况是针对不同的 问题用户需要的是具有不同属性(如,性能)的 PersistentVolume 卷。 集群管理员需要能够提供不同性质的 PersistentVolume,并且这些 PV 卷之间的差别不 仅限于卷大小和访问模式,同时又不能将卷是如何实现的这些细节暴露给用户。 为了满足这类需求,就有了 存储类(StorageClass) 资源。

前言

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

emptyDir存储卷

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

自动生成yaml文件

 kubectl run nginx-text --image=nginx --dry-run=client -o yaml > nginx.test.yaml

编辑yaml文件 


apiVersion: v1
kind: Pod
metadata:
  name: pod-emptydir
spec:
  containers:
  - image: nginx
    name: myapp1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
​
  - image: nginx
    name: myapp2
    volumeMounts:
    - name: html
      mountPath: /data
    command:
    - sh
    - -c
    - while true; do echo $(data) >> /data/index.html; sleep 2; done
​
  volumes:
  - name: html
    emptyDir: {}
​

执行

[root@master01 /opt/Volumes]# kubectl apply -f demo1.yaml
pod/pod-emptydir created
[root@master01 /opt/Volumes]# kubectl get pods
NAME           READY   STATUS              RESTARTS   AGE
pod-emptydir   0/2     ContainerCreating   0          6s
[root@master01 /opt/Volumes]# kubectl get pods -w
NAME           READY   STATUS              RESTARTS   AGE
pod-emptydir   0/2     ContainerCreating   0          9s
pod-emptydir   2/2     Running             0          18s

进myapp1中

 

进myapp2中

hostPath存储卷(本地)

        hostPath卷将node节点的文件系统中的文件或目录挂载到集群中。

        hostPath可以实现持久存储,但是在node节点故障时,也会导致数据的丢失。

//在node01 /02节点上创建挂载目录

[root@node01 ~]# mkdir -p /data/pod/volumes
[root@node01 ~]# cd /data/pod/volumes/
[root@node01 /data/pod/volumes]# ls
[root@node01 /data/pod/volumes]# echo "this is node01 web" > index.html
[root@node01 /data/pod/volumes]# ls
index.html

写yaml文件

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

 

此时容器内的数据已经实现共享

[root@master01 /opt/Volumes]# kubectl exec -it pod-hostpath -c myapp1 bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pod-hostpath:/# ls
bin  boot  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@pod-hostpath:/# cd /usr/share/nginx/
root@pod-hostpath:/usr/share/nginx# ls
html
root@pod-hostpath:/usr/share/nginx# cd html/
root@pod-hostpath:/usr/share/nginx/html# ls
index.html
root@pod-hostpath:/usr/share/nginx/html# cat index.html
this is node02 web

此时在node02节点添加一条数据

[root@node02 /data/pod/volumes]# echo "this is node02 line" >> index.html
​

再次看容器

root@pod-hostpath:/usr/share/nginx/html# cat index.html
this is node02 web
this is node02 line

实现共享

NFS共享存储卷

在nfs服务器中加载可挂载目录,并输出一句话

[root@localhost ~]# mkdir -p /data/volume
[root@localhost ~]# cd /data/volume/
[root@localhost /data/volume]# chmod 777 /data/volume/
​
设置共享策略
[root@localhost /data/volume]# vim /etc/exports
[root@localhost /data/volume]# systemctl start rpcbind nfs
[root@localhost /data/volume]# showmount -e
Export list for localhost.localdomain:
/data/volume 192.168.37.0/24
​
[root@localhost /data/volume]# echo "this is nfs volume" > index.html
[root@localhost /data/volume]# ls
index.html

在其他节点上查看

[root@master01 /opt/Volumes]# showmount -e 192.168.37.108
Export list for 192.168.37.108:
/data/volume 192.168.37.0/24

编写yaml文件

apiVersion: v1
kind: Pod
metadata:
  name: pod-nfs
spec:
  containers:
  - image: nginx
    name: myapp1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
      readOnly: false
  volumes:
  - name: html
    nfs:
      path: /data/volume
      #nfs服务的地址
      server: 192.168.37.108

[root@master01 /opt/Volumes]# kubectl get pods -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-emptydir   2/2     Running   0          64m   10.244.1.16   node01   <none>           <none>
pod-hostpath   1/1     Running   0          34m   10.244.2.8    node02   <none>           <none>
pod-nfs        1/1     Running   0          42s   10.244.2.9    node02   <none>           <none>
[root@master01 /opt/Volumes]# curl http://10.244.2.9
this is nfs volume
​

查看详细信息

[root@master01 /opt/Volumes]# kubectl describe pod pod-nfs

 

在容器中添加数据

[root@master01 /opt/Volumes]# kubectl exec -it pod-nfs -c myapp1 bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pod-nfs:/# cd /usr/share/nginx/html/
root@pod-nfs:/usr/share/nginx/html# ls
index.html
root@pod-nfs:/usr/share/nginx/html# cat index.html
this is nfs volume
root@pod-nfs:/usr/share/nginx/html# echo "this is one nfs!" >>index.html
 

在nfs服务器查看

[root@localhost /data/volume]# cat index.html
this is nfs volume
this is one nfs!

以上三种是解决无状态应用共享存储卷

PV、PVC

 

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

        PVC的全称是 Persistent Volume claim,是持久化存储的请求。它是用来描述希望使用什么样的或者说是满足什么条件的PV存储。

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

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

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

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

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

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

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

2)Bound(已绑定):表示PV己经绑定到PVC

3)Released(己释放):表示PVC被删掉,但是资源尚未被集群回收

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

//一个PV从创建到销毁的具体流程如下:

1、一个PV创建完后状态会变成Available,等待被PPV绑定。

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

3、 Pod使用完后会释放PV,Pv的状态变成Released。

4、变成Released的 PVC会根据定义的回收策略做相应的回收工作。有三种回收策略,Retain、Delete和Recycle。Retain就是保留现场,K8S集群什么也不做,等待用户手动去处理PV里的数据,处理完后,再手动删除PV。Delete策略,K0S会自动删除该PV及里面的数据。Recycle方式,K8s会将PV里的数据删除,然后把PV的状态变成Available,又可以被新的PVC绑定使用。

spec
  nfs: (定义存储类型)
    path: (定义挂载卷路径)
    server: (定义服务器名称)
  accessModes: (定义访问模型,有以下三种访问模型,以列表的方式存在,也就是说可以定义多个访问模式)
    - Readwriteonce         #(RWO)存储可读可写,但只支持被单个 Pod挂载
    - ReadonlyMany          #(ROX)存储可以以只读的方式被多个Pod 挂载
    - ReadwriteMany         #(RWX)存储可以以读写的方式被多个Pod 共享
    #nfs支持全部三种; isCSI 不支持ReadwiriteMany (iscsI就是在IP 网络上运行scsI协议的一种网络存储技术) HostPath不支持 ReadonlyMany和ReadwriteMany。
    
   capacity: (定义存储能力,一般用于设置存储空间)
     storage: 2Gi(指定大小)
   StorageClassName:  (自定义存储类名称,此配置用于绑定具有相同类别的PvC和pv)
   PersistentvolumeReclaimPolicy: Retain #回收策略((Retain/Delete/Recycle)
​
#Retain(保留):当删除与之绑定的PVC时候,这个PV被标记为released (PVC与PV解绑但还没有执行回收策略)且之前的数据依然保存在该PV 上,但是该PV不可用,需要手动来处理这些数据并删除该PV。
​
#Delete(删除):删除与PV相连的后端存储资源(只有 AWS EBS,GCE PD,Azure Disk 和 Cinder 支持)
​
#Recycle(回收):删除数据,效果相当于执行了rm -rf /thevolume/*(只有NES 和HostPath支持)

        NFS使用pv、pvc

 

重新设置NFS共享策略

[root@localhost /data/volumes]# vim /etc/exports
/data/volume 192.168.37.0/24(rw,sync,no_root_squash)
/data/volumes/v1 192.168.37.0/24(rw,sync,no_root_squash)
/data/volumes/v2 192.168.37.0/24(rw,sync,no_root_squash)
/data/volumes/v3 192.168.37.0/24(rw,sync,no_root_squash)
/data/volumes/v4 192.168.37.0/24(rw,sync,no_root_squash)
/data/volumes/v5 192.168.37.0/24(rw,sync,no_root_squash)
​
#不重启生效

exportfs -ar

再看别的主机

[root@master01 /opt/Volumes]# showmount -e 192.168.37.108
Export list for 192.168.37.108:
/data/volumes/v5 192.168.37.0/24
/data/volumes/v4 192.168.37.0/24
/data/volumes/v3 192.168.37.0/24
/data/volumes/v2 192.168.37.0/24
/data/volumes/v1 192.168.37.0/24
/data/volume     192.168.37.0/24


创建pv 

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels: 
    type: pv001
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  nfs:
    path: /data/volumes/v1
    server: 192.168.37.108
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels: 
    type: pv002
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /data/volumes/v2
    server: 192.168.37.108
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels: 
    type: pv003
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  nfs:
    path: /data/volumes/v3
    server: 192.168.37.108
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
  labels: 
    type: pv004
spec:
  capacity:
    storage: 4Gi
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  nfs:
    path: /data/volumes/v4
    server: 192.168.37.108
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
  labels: 
    type: pv005
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  nfs:
    path: /data/volumes/v5
    server: 192.168.37.108
​

执行

[root@master01 /opt/Volumes]# kubectl apply -f pv.yaml

查看pv

 

创建pvc

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 2Gi
​

执行,查看pv、pvc

[root@master01 /opt/Volumes]# kubectl apply -f pvc.yaml

 

访问

demo4-pv.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-pv
spec:
  containers:
  - image: nginx
    name: myapp1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html
    persistentVolumeClaim:
      claimName: mypvc

执行

[root@master01 /opt/Volumes]# kubectl apply -f demo4-pv.yaml
pod/pod-pv created

在pv003输入一条数据,访问

[root@master01 /opt/Volumes]# kubectl apply -f demo4-pv.yaml
pod/pod-pv created

pvc会根据pv的属性来匹配,直到匹配不上为止。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小柏ぁ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值