目录
引言
在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.217.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.217.55
Export list for 192.168.217.55:
/nfs/volumes/ 192.168.217.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: ngi