kubernetes存储入门
目录
一.volume的概念
二.volume的类型
三.通过emptydir共享数据
1.编写emptydir的deployment文件
2.部署deployment,和查看部署结果
3.登录pod中第一个容器
4.登录到pod中第二个容器查看/mnt下的文件
5.删除pod
四.使用hostpath挂载缩主机文件
2.创建pod,加查看结果
3.测试挂载情况
4.删除
五.挂载nfs至容器
1.安装nfs
2.设置共享目录在nfs服务器
3.开启nfs
4.编写deployment文件,挂载nfs
5.部署pod,加查看部署结果
6.登录容器查看挂载结果
六.persistenvolume(pv持久卷)
1:PV回收策略
2:PV访问策略
3:PV的配置方式
(1)静态配置
(2)动态配置
4.基于host path的pv
(1)在master节点创建主机目录
(2)编辑hostpath的yaml文件
4.基于nfs的pv
(1)创建一个基于nfs的pv
七.persistentvolumeclaim(pv持久卷声明)
1.pv的创建
(1)为hostpath类型的pv创建pvc
(2)为nfs类型的pv创建pvc
2.pvc的使用
(1)创建pod,绑定hostpath的PV
(2)创建pod,绑定nfs的pv
一.volume概念
对于大多数的项目而言,数据文件的存储是非常常见的需求,比如存储用户上传的头像、文件以及数据库的数据。在Kubernetes中,由于应用的部署具有高度的可扩展性和编排能力(不像传统架构部署在固定的位置),因此把数据存放在容器中是非常不可取的,这样也无法保障数据的安全。
我们应该把有状态的应用变成无状态的应用,意思是指把数据从应用中剥离出来,把产生的数据文件或者缓存的信息都放在云端,比如常用的NFS(生产环境中不建议使用,因为存在单点故障,推荐使用分布式的存储或者公有云的NAS服务)、Ceph、GlusterFS、Minio等。
在传统的架构中,如果要使用这些存储,需要提前在宿主机挂载,然后程序才能访问,在实际使用时,经常碰到新加节点忘记挂载存储导致的一系列问题。而Kubernetes在设计之初就考虑了这些问题,并抽象出Volume的概念用于解决数据存储的问题。
在容器中的磁盘文件是短暂的,当容器崩溃时,Kubect1会重新启动容器,但是容器运行时产生的数据文件都会丢失,之后容器会以干净的状态启动。另外,当一个Pod运行多个容器时,各个容器可能需要共享一些文件,诸如此类的需求都可以使用Volume解决。
Docker 也有卷的概念,但是在Docker中,卷只是磁盘上或另一个容器中的目录,其生命周期不受管理。虽然Docker已经提供了卷驱动程序,但是功能非常有限,例如从Docker1.7版本开始,每个容器只允许一个卷驱动程序,并且无法将一些特殊的参数传递给后端存储。
另一方面,Kubernetes 卷具有明确的生命周期,与使用他的Pod相同,因此在Kubernetes中的卷可以比Pod中运行的任何容器的生命周期都长,并且可以在容器重启或者销毁之后保留数据。Kubernetes支持多种类型的卷,并且Pod可以同时使用任意数量的卷。
从本质上讲,和虚拟机或者物理机一样,卷被挂载后,在容器中也只是一个目录,可能包含一些数据,Pod中的容器也可以对其进行增删改查操作,使用方式和裸机挂载几乎没有区别。要使用卷也非常简单,和其他参数类似,Pod只需要通过.spec.volumes 字段指定为Pod提供的卷,然后在容器中配置块,使用.spec.containers.volumeMounts 字段指定卷的挂载目录即可。
二.volume的类型
在传统架构中,企业内可能有自己的存储平台,比如NFS、Ceph、GlusterFS、Minio等。如果所在的环境在公有云,也可以使用公有云提供的NAS、对象存储等。在Kubernetes中,Volume 也支持配置这些存储,用于挂载到Pod中实现数据的持久化。Kubernetes Volume支持的卷的类型有很多。以下为常见的卷:
>CephFS
>GlusterFS
>ISCSI
>Cinder
>NFS
>RBD
>HostPath
当然也支持一些Kubernetes 独有的类型:
>ConfigMap:用于存储配置文件
>Secret:用于存储敏感数据
> EmptyDir:用于一个Pod内多个容器的数据共享
>PersistentVolumeClaim:对PersistentVolume 的申请
三.通过emptydir共享数据
emptyDir是一个特殊的Volume类型,与上述Volume不同的是,如果删除Pod,EmptyDir 卷中的数据也将被删除,所以一般emptyDir用于Pod中不同容器共享数据,比如一个Pod存在两个容器A和容器B,容器A需要使用容器B产生的数据,此时可以采用emptyDir共享数据,类似的使用如Filebeat收集容器内程序产生的日志。
使用emptyDir卷时,直接指定emptyDir为{}即可
1.编写emptydir的deployment文件
vim nginx-empty.yaml
备注:
>volumeMounts:
-> mountPath: /mnt
>name:share-volume##容器定义部分的卷挂载名称,此处的名称引用了volumes对应的名称
>volumes:
-> name: share-volume ##共享存储卷的名称
此案例会将nginx01中/opt中的数据,共享给nginx02中的/mnt目录此部署文件创建一个Deployment,采用spec.volume字段配置了一个名字为share-volume、类型为emptyDir的volume,同时里面包含两个容器nginx01和nginx02,并将该volume挂载到了/opt和/mnt 目录下,此时/opt和/mnt目录的数据就实现了共享。
默认情况下,emptyDir支持节点上的任何介质,可以使SSD、磁盘或是网络存储,具体取决于自身环境。可以将emptyDir.medium字段设置为Memory,让Kubernetes 使用tmpfs(内存支持的文件系统),虽然tmpfs非常快,但是在节点重启时,数据同样会被清除,并且设置的大小会被记入Container的内存限制中。
2.部署deployment,和查看部署结果
kubectl create -f nginx-empty.yaml
deployment.apps/nginx createdkubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-8f8dcfd8c-2wdzs 2/2 Running 0 13s
3.登录pod中第一个容器
kubectl exec -it nginx-8f8dcfd8c-2wdzs -c nginx01 -- bash
root@nginx-8f8dcfd8c-2wdzs:/# cd /opt/
root@nginx-8f8dcfd8c-2wdzs:/opt# touch aaa
root@nginx-8f8dcfd8c-2wdzs:/opt# touch bbb
root@nginx-8f8dcfd8c-2wdzs:/opt# ls
aaa bbb
root@nginx-8f8dcfd8c-2wdzs:/opt# exit
exit
4.登录到pod中第二个容器查看/mnt下的文件
kubectl exec -it nginx-8f8dcfd8c-2wdzs -c nginx02 -- bash
root@nginx-8f8dcfd8c-2wdzs:/# cd /mnt/
root@nginx-8f8dcfd8c-2wdzs:/mnt# ls
aaa bbb
5.删除pod
kubectl delete -f nginx-empty.yaml
deployment.apps "nginx" deleted
四.使用hostpath挂载缩主机文件
HostPath 卷可以将节点上的文件或目录挂载到Pod上,用于实现Pod和宿主机之间的数据共享,常用的示例有挂载宿主机的时区至Pod,或者将Pod的日志文件挂载到宿主机等。
1:编写Deployment文件,实现HostPath挂载
以下为使用HostPath卷的示例,实现将主机的/etc/localtime文件挂载到Pod的/etc/localtime
vim nginx-hostPath.yaml
2.创建pod,加查看结果
kubectl create -f nginx-hostPath.yaml
deployment.apps/nginx createdkubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-59f95c99b5-s5zsp 1/1 Running 0 10s
3.测试挂载情况
kubectl exec -it nginx-59f95c99b5-s5zsp -c nginx -- bash
root@nginx-59f95c99b5-s5zsp:/# date
Wed Jul 9 09:38:57 CST 2025
root@nginx-59f95c99b5-s5zsp:/# ls -l /etc/localtime
-rw-r--r--. 4 root root 561 Dec 11 2024 /etc/localtime
root@nginx-59f95c99b5-s5zsp:/# exit
exit
4.删除
kubectl delete -f nginx-hostPath.yaml
deployment.apps "nginx" deleted
五.挂载nfs至容器
1.安装nfs
dnf -y install nfs-utils
Waiting for process with pid 13206 to finish.Last metadata expiration check: 0:00:02 ago on 2025年07月09日 星期三 09时55分49秒.
Dependencies resolved.
========================================================Package Arch Version Repo Size
========================================================
Installing:nfs-utils x86_64 2:2.6.3-3.oe2403sp1 OS 311 k
Installing dependencies:gssproxy x86_64 0.9.2-2.oe2403sp1 OS 95 kkeyutils x86_64 1.6.3-5.oe2403sp1 OS 52 kkrb5 x86_64 1.21.2-14.oe2403sp1 update 78 kquota x86_64 1:4.06-8.oe2403sp1 OS 225 krpcbind x86_64 1.2.6-8.oe2403sp1 OS 44 k
Installing weak dependencies:nfs-utils-help x86_64 2:2.6.3-3.oe2403sp1 OS 98 k
.........等
2.设置共享目录在nfs服务器
mkdir /opt/wwwrootecho "zhe shi wo de di yi ge wen jian">/opt/wwwroot/index.htmlvim /etc/exports
/opt/wwwroot 192.168.10.0/24(rw,sync,no_root_squash)
3.开启nfs
systemctl start nfssystemctl start rpcbind
4.编写deployment文件,挂载nfs
vim nginx-nfsVolume.yaml
5.部署pod,加查看部署结果
kubectl create -f nginx-nfsVolume.yaml
deployment.apps/nginx createdkubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-7bf6df4679-lkklk 1/1 Running 0 8s
6.登录容器查看挂载结果
kubectl exec -it nginx-7bf6df4679-lkklk -c nginx -- bashcurl 10.244.58.198
zhe shi wo de di yi ge wen jian
六.persistenvolume(pv持久卷)
虽然volume已经可以接入大部分存储后端,但是实际使用时还有诸多的问题。比如:
> 当某个数据卷不再被挂载使用时,里面的数据如何处理?
> 如果想要实现只读挂载,要如何处理?
> 如果想要只能有一个Pod挂载,要如何处理?
如上所述,对于很多复杂的需求,volume可能难以实现,并且无法对存储的生命周期进行管理。另一个很大的问题是,在企业内使用kubernetes的不仅仅是kubernetes管理员,可能还有开发人员、测试人员以及初学kubernetes的技术人员,对于kubernetes的volume或者相关存储平台的配置参数并不了解,所以无法自行完成存储的配置。
为此,kubernetes引入了两个新的API资源:PersistentVolume(持久卷,简称PV)和PersistentVolumeClaim(持久卷声明,简称PVC)。
PV是kubernetes 管理员设置的存储,PVC是对PV的请求,标识需要什么类型的PV。他们同样是集群中的一类资源,但其生命周期比较独立,管理员可以单独对PV进行增删改查,不受Pod的影响,生命周期可能比挂载它的其他资源还要长。如果一个kubernetes集群的使用者并非只有kubernetes管理员,那么可以通过提前创建PV,用以解决对存储概念不是很了解的技术人员对存储的需求。和单独配置volume类似,PV也可以使用NFS、GFS、CEPH等常见的存储后端,并且可以提供更为高级的配置,比如访问模式、空间大小以及回收策略等。目前PV的提供方式有两种:静态或动态。静态PV由管理员提前创建,动态PV无需提前创建。
1:PV回收策略
当用户使用完卷时,可以从API中删除PVC对象,从而允许回收资源。回收策略会告诉PV如何处理改卷。目前回收策略可以设置为Retain、Recycle和Delete。静态PV默认的为Retain,动态PV默认为Delete。
>Retain:保留,该策略允许手动回收资源,当删除PVC时,PV仍然存在,PV中的数据也存在。volume被视为已释放,管理员可以手动回收卷。
>Recycle:回收,如果volume插件支持,Recycle策略会对卷执行rm-rf清理该PV,卷中的数据已经没了,但卷还在,使其可用于下一个新的PVC,但是本策略将会被弃用,目前只有NFS和HostPath支持该策略。
>Delete:删除,如果volume插件支持,删除PVC时会同时删除PV,PV中的数据自然也就没了。动态卷默认为Delete,目前支持Delete的存储后端包括 AWS EBS、GCE PD、Azure Disk、OpenStackCinder 等。
2:PV访问策略
在实际使用PV时,可能针对不同的应用会有不同的访问策略,比如某类Pod可以读写,某类Pod只能读,或者需要配置是否可以被多个不同的Pod同时读写等,此时可以使用PV的访问策略进行简单控制,目前支持的访问策略如下:
>ReadWriteOnce:单路可读可写,可以被单节点以读写模式挂载,命令行中可以被缩写橙RWO。
>ReadOnlyMany:多路只读,可以被多节点以只读模式挂载,命令行中可以被缩写为ROX。
>ReadWriteMany:多路可读可写,可以被多个节点以读写模式挂载,命令行中可以被缩写为RWX。
>ReadwriteOncePod:单节点只读(1.22+),只能被一个Pod以读写的模式挂载,命令行中可以被缩写为RWOP。
虽然PV在创建时可以指定不同的访问策略,但是也要后端的存储支持才行。比如一般情况下,大部分块存储是不支持ReadWriteMany的。
在企业内,可能存储很多不同类型的存储,比如NFS、Ceph、GlusterFS等,针对不同类型的后端存储具有不同的配置方式,这也是对集群管理员的一种挑战,因为集群管理员需要对每种存储都要有了解
3:PV的配置方式
(1)静态配置
静态配置是手动创建PV并定义其属性,例如容量、访问模式、存储后端等。在这种情况下,Kubernetes管理员负责管理和配置PV,然后应用程序可以使用这些PV。静态配置通常用于一些固定的存储后端,如NFS
(2)动态配置
动态配置允许Kubernetes集群根据PVC的需求自动创建PV,在这种情况下,管理员只需为存储后端配置 StorageClass,然后应用程序就可以通过PVC请求存储。Kubernetes将自动创建与PVC匹配的PV,并将其绑定到PVC上。这种方法使得存储管理更加灵活和可扩展,允许管理员在集群中动态添加、删除、和管理存储资源
4.基于host path的pv
(1)在master节点创建主机目录
mkdir /mnt/data
(2)编辑hostpath的yaml文件
vim hostpath-pv.yaml
备注:
>hostPath:宿主机的路径,使用hostPath类型需要固定Pod所在的节点,防止Pod 漂移造成数据丢失。
>storageClassName 是一个用于标识StorageClass 对象名称的标签。当你创建或配置PersistentVolumeClaim(PVC)时,可以指定storageClassName 来告诉Kubernetes 你希望使用哪个StorageClass来配置存储。
bectl create -f hostpath-pv.yamlpersistentvolume/mypv-hostpath createdkubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv-hostpath 10Gi RWO Retain Available pv-hostpath 11s
4.基于nfs的pv
(1)创建一个基于nfs的pv
vim nfs-pv.yaml
备注:
>capacity:容量配置
>volumeMode:卷的模式,目前支持Filesystem(文件系统)和Block(块),其中Block类型常要后端存储支持,默认为文件系统。
>accessModes:该PV的访问模式
>storageClassName:PV的类,一个特定类型的PV只能绑定到特定类别的PVC。
>persistentVolumeReclaimPolicy:回收策略
>mountOption:非必要,新版本中已经弃用
>nfs:NFS服务配置,包括以下两个选项
>path:NFS上的共享目录
>server: NFS 的IP地址
创建pv,加查看pv结果
kubectl create -f nfs-pv.yaml persistentvolume/mypv-nfs createdkubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv-hostpath 10Gi RWO Retain Available pv-hostpath 3m53s
mypv-nfs 5Gi RWO Recycle Available pvc-nfs 8s
七.persistentvolumeclaim(pv持久卷声明)
当 kubernetes 管理员提前创建好了PV,我们又应该如何使用它呢?
这里介绍kubernetes 的另一个概念PersistentVolumeClaim(简称PVC)。PVC是其他技术人员在kubernetes 上对存储的申请,他可以标明一个程序需要用到什么样的后端存储、多大的空间以及什么访问模式进行挂载。这一点和Pod的QoS配置类似,Pod 消耗节点资源,PVC消耗PV资源,Pod可以请求特定级别的资源(CPU和内存),PVC可以请求特定的大小和访问模式的PV。例如申请一个大小为5G且只能被一个Pod只读访问的存储。
在实际使用时,虽然用户通过PVC获取存储支持,但是用户可能需要具有不同性质的PV来解决不同的问题,比如使用SSD硬盘来提高性能。所以集群管理员需要根据不同的存储后端来提供各种PV,而不仅仅是大小和访问模式的区别,并且无须让用户了解这些卷的具体实现方式和存储类型,打扫了存储的解耦,降低了存储使用的复杂度。
接下来我们来看看如何让PVC和前面创建的PV绑定。PVC和PV进行绑定的前提条件是一些参数必须匹配,比如accessModes、storageClassName、volumeMode 都需要相同,并且PVC的storage需要小于等于PV的storage 配置。
1.pv的创建
(1)为hostpath类型的pv创建pvc
vim pvc-hostpath.yaml
注意:
storageClassName:存储类名称需要和对应的PV中的名称一致,PV和PVC进行绑定并非是名字相同,而是StorageClassName相同且其他参数一致才可以进行绑定
ubectl create -f pvc-hostpath.yaml persistentvolumeclaim/mypvc-hostpath createdkubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc-hostpath Bound mypv-hostpath 10Gi RWO pv-hostpath 10s
(2)为nfs类型的pv创建pvc
vim pvc-nfs.yaml
kubectl create -f pvc-nfs.yaml persistentvolumeclaim/mypvc-nfs createdkubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc-hostpath Bound mypv-hostpath 10Gi RWO pv-hostpath 6m5s
mypvc-nfs Bound mypv-nfs 5Gi RWO pvc-nfs 10s
从上述两个简单的例子可以看出,PVC的定义和后端存储并没有关系。对于有存储需求的技术人员,直接定义PVC即可绑定一块PV,之后就可以供Pod使用,而不用去关心具体的实现细节,大大降低了存储的复杂度。接下来我们看一下PVC如何提供给Pod使用。
2.pvc的使用
上述创建了PV,并使用PVC与其绑定,现在还差一步就能让程序使用这块存储,那就是将PVC挂载到Pod。和之前的挂载方式类似,PVC的挂载也是通过volumes 字段进行配置的,只不过之前需要根据不同的存储后端填写很多复杂的参数’而使用PVC进行挂载时,只填写PVC的名字即可,不需要再关心任何的存储细节,这样即使不是Kubemetes管理员,不懂存储的其他技术人员想要使用存储,也可以非常简单地进行配置和使用。比如我们将之前创建的hostPath类型的PVC挂载到Pod中,可以看到只需要配置一个PersistentVolumeClaim类型的volumes,claimName 配置为PVC的名称即可:
(1)创建pod,绑定hostpath的PV
vim pvc-pv-pod-hostpath.yaml
kubectl create -f pvc-pv-pod-hostpath.yaml pod/hostpath-pv-pod createdkubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hostpath-pv-pod 1/1 Running 0 13s 10.244.58.199 k8s-node02 <none> <none>
nginx-7bf6df4679-k5qdp 1/1 Running 0 37m 10.244.58.198 k8s-node02 <none>
kubectl exec -it hostpath-pv-pod -- bashroot@hostpath-pv-pod:/# ls /usr/share/nginx/html/aaa.txt
(2)创建pod,绑定nfs的pv
vim pvc-pv-pod-nfs.yaml
kubectl create -f pvc-pv-pod-nfs.yaml pod/pvc-nfs createdkubectl get pod
NAME READY STATUS RESTARTS AGE
hostpath-pv-pod 1/1 Running 0 99s
nginx-7bf6df4679-k5qdp 1/1 Running 0 47m
pvc-nfs 1/1 Running 0 23s
kubectl exec -it pvc-nfs -- bashroot@pvc-nfs:/# ls /usr/share/nginx/html/index.htmlroot@pvc-nfs:/# exit