K8s数据持久化
一、为什么需要持久化
为了解决pod里面的容器被删除后数据不丢失,则引入了存储类型,类似于docker中的数据卷。
在kubernetes集群中,其是支持多种存储类型,包括但不限于emptyDir,HostPath,NFS等。
二、数据卷概述
1、为什么需要数据卷
容器部署过程中一般有以下三种数据:
(1)启动时需要的初始数据,例如配置文件;
(2)启动过程中产生的临时数据,该临时数据需要多个容器间共享,例如类似于Redis的数据库;
(3)启动容器过程中产生的持久化数据,例如MySQL的数据目录(datadir);
如下图所示,我们可以基于数据卷的方式实现数据的共享。
2、数据卷的分类
数据卷:
(1)kubernetes中的Volume提供了在容器中挂载外部存储的能力;
(2)Pod需要设置卷来源(po.spec.volumes)和挂载点(po.spec.containers.volumeMounts)两个信息后才可以使用相应的volume;
按类型分类:
本地数据卷: hostPath,emptyDir等
网络数据卷: NFS,Ceph,GlusterFS等
公有云: AWS,EBS等
K8S资源: configmap,secret等
三、emptyDir存储类型
1、emptyDir概述
emptyDir数据卷是一个临时存储卷,与Pod生命周期绑定在一起,如果Pod删除了,这意味着数据卷也会被删除。
作用:
(1)可以实现持久化的功能;
(2)多个Pod之间不能通信数据,但是同一个Pod的多个容器是可以实现数据共享的;
(3)随着Pod的生命周期而存在,当我们删除Pod时,其数据也会被随之删除。
应用场景(同一个Pod中各个容器之间数据的共享):
(1)缓存空间,例如基于磁盘的归并排序;
(2)为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行;
(3)存储Web服务器的访问日志及错误日志等信息;
📌温馨提示:使用emptyDir持久化数据时,删除容器并不会删除数据,因为容器删除并不能说明Pod被删除哟。
2、创建Pod并使用emptyDir案例
#创建一个命名空间和pod
[root@172-16-121-211 ~]# cat 01-volumes-emptydir-demo.yml
apiVersion: v1
kind: Namespace
metadata:
name: emptydir-volume
---
apiVersion: v1
kind: Pod
metadata:
name: hongmi-pod-emptydir
namespace: emptydir-volume
spec:
# 定义数据卷的来源
volumes:
- name: data
emptyDir: {}
# 我们无需为emptyDir指定任何参数,通常写个"{}"即可,表示创建的是一个空目录。
- name: log
emptyDir: {}
containers:
# 创建一个负责写入数据的容器
- name: linux-producer
image: alpine:latest
# 启动容器后执行的命令,模拟生产数据即可
command: ["sh","-c","for i in `seq 1000`;do echo $i >> /mydata/topic;sleep 1;done"]
# 挂载数据卷
volumeMounts:
- name: data # 注意哈,该名称必须在上面的"volumes"的name字段中存在哟~
mountPath: /mydata # 指定挂载到容器的位置
# 创建一个负责读取数据的容器
- name: linux-consumer
image: alpine:latest
# 启动容器后执行的命令,模拟消费数据即可
command: ["sh","-c","tail -f /mydata2021/topic"]
# 挂载数据卷
volumeMounts:
- name: data # 注意哈,该名称必须在上面的"volumes"的name字段中存在哟~
mountPath: /mydata2021
- name: hongmi-linux
image: alpine:latest
command: ["sh","-c","tail -f /etc/hosts"]
volumeMounts:
- name: log
mountPath: /hongmi
[root@172-16-121-211 ~]# kubectl apply -f 01-volumes-emptydir-demo.yml
[root@172-16-121-211 ~]# kubectl get pods -n emptydir-volume -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hongmi-pod-emptydir 3/3 Running 0 3m17s 10.244.1.5 172-16-121-88 <none> <none>
查看数据存储情况:
📌 注意:删除Pod则持久化到本地的数据同时将被删除
四、HostPath存储类型
1、概述:
可以解决同一个Node节点的多个Pod数据共享哟,但多个Pod不在同一个Node节点时则无法通过HostPath来查找数据
2、hostPath数据卷:
挂载Node文件系统(Pod所在节点)上文件或者目录到Pod中的容器。
如果Pod删除了,宿主机的数据并不会被删除,这一点是否感觉和咱们的数据卷有异曲同工之妙呢?
3、应用场景:
Pod中容器需要访问宿主机文件。
[root@172-16-121-211 hostpath]# ls
00-wordpress-namespace.yaml 01-wordpress-mysql.yaml 02-wordpress-mysql-svc.yml 03-wordpress-web.yaml 04-wordpress-svc.yml
[root@172-16-121-211 hostpath]# pwd
/root/hostpath
[root@172-16-121-211 hostpath]#
[root@172-16-121-211 hostpath]# ls
00-wordpress-namespace.yaml 01-wordpress-mysql.yaml 02-wordpress-mysql-svc.yml 03-wordpress-web.yaml 04-wordpress-svc.yml
[root@172-16-121-211 hostpath]# free -h
total used free shared buff/cache available
Mem: 3.7G 1.1G 148M 162M 2.4G 2.2G
Swap: 0B 0B 0B
[root@172-16-121-211 hostpath]#
[root@172-16-121-211 hostpath]#
[root@172-16-121-211 hostpath]# LS
-bash: LS: command not found
[root@172-16-121-211 hostpath]#
[root@172-16-121-211 hostpath]# ls
00-wordpress-namespace.yaml 01-wordpress-mysql.yaml 02-wordpress-mysql-svc.yml 03-wordpress-web.yaml 04-wordpress-svc.yml
[root@172-16-121-211 hostpath]# cat *
00-wordpress-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: hongmi-wordpress
01-wordpress-mysql.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hongmi-wordpress-mysql
namespace: hongmi-wordpress
spec:
replicas: 1
selector:
matchLabels:
app: hongmi-wordpress-mysql
template:
metadata:
labels:
app: hongmi-wordpress-mysql
spec:
containers:
- name: mysql
image: mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: somewordpress
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_USER
value: wordpress
- name: MYSQL_PASSWORD
value: wordpress
#02-wordpress-mysql-svc.yml
apiVersion: v1
kind: Service
metadata:
name: hongmi-mysql
namespace: hongmi-wordpress
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: hongmi-wordpress-mysql
#03-wordpress-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
namespace: hongmi-wordpress
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
volumes:
- name: wordpress-code
hostPath:
path: /data/wordpress-code
#nodeName: k8s102.oldboyedu.com
containers:
- name: wordpress
image: wordpress:latest
ports:
- containerPort: 80
volumeMounts:
- mountPath: /var/www/html
name: wordpress-code
env:
- name: WORDPRESS_DB_HOST
value: hongmi-mysql # 注意哈,这里我写的是暴露MySQL服务的service名称哟~
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_PASSWORD
value: wordpress
#04-wordpress-svc.yml
apiVersion: v1
kind: Service
metadata:
name: wordpress
namespace: hongmi-wordpress
spec:
type: NodePort
ports:
- port: 80
nodePort: 32020
targetPort: 80
selector:
app: wordpress
五、NFS存储类型
1、概述
适合不同的node节点的Pod共享存储,但存在单点故障
NFS数据卷:提供对NFS挂载支持,可以自动将NFS共享路径挂载到Pod中。
NFS:英文全称为"Network File System"(网络文件系统),是由SUN公司研制的UNIX表示层协议(presentation layer protocol),能使使用者访问网络上别处的文件就像在使用自己的计算机一样。
NFS是一个主流的文件共享服务器,但存在单点故障,我们需要对数据进行备份,如果有必要可以使用分布式文件系统哈。
2、安装NFS环境并测试
(1)在所有节点上都安装"nfs-utils"软件包,安装该软件包不仅仅会包含NFS服务端软件,还会包含其客户端软件
yum -y install nfs-utils
(2)将"master"设置为NFS服务端,配置共享"/data/kubernetes"目录
# vim /etc/exports
#cat /etc/exports
/backup/kubernetes *(rw,no_root_squash)
# mkdir -pv /backup/kubernetes
# ll /backup/kubernetes
总用量 0
# systemctl start nfs && systemctl enable nfs #启动nfs
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
# exportfs # 查看NFS的挂载信息
/backup/kubernetes
<world>
# touch /backup/kubernetes/nfs.log # 创建测试文件,便于客户端挂载测试验证
(3)客户端验证NFS的可用性
mount -t nfs master:/backup/kubernetes /mnt/ # 手动挂载NFS的服务端进行测试
(4)手动卸载NFS
# umount /mnt # 手动卸载NFS
(5)所有节点
systemctl start nfs && systemctl enable nfs
showmount -e 172.16.104.15
📌温馨提示: 建议在Kubernetes的每个工作节点都安装nfs-utils软件包,如果只在NFS服务端安装,客户端未安装的话,可能客户端在使用mount命令手动挂在时会挂在不上哟~
3、测试案例
[root@k8s101.oldboyedu.com ~]# cat 03-volumes-nfs-demo.yaml
apiVersion: v1
kind: Namespace
metadata:
name: hongmi-volume
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mynginx-deploy
namespace: hongmi-volume
spec:
selector:
matchLabels:
app: nginx-nfs
replicas: 3
template:
metadata:
labels:
app: nginx-nfs
spec:
# 配置NFS的数据源
volumes:
- name: hongmi-nfs
nfs:
server: master #指定NFS的服务器的地址,如果指定主机名请确保可以正常进行解析哟~
path: /data/kubernetes #指定NFS的挂载路径
containers:
- name: my-nginx
image: nginx:1.18
# 在容器中挂载数据卷
volumeMounts:
- name: hongmi-nfs
mountPath: /usr/share/nginx/html
ports:
- containerPort: 80
[root@172-16-104-15 ~]# kubectl apply -f 03-volumes-nfs-demo.yaml
namespace "hongmi-volume" created
deployment "mynginx-deploy" created
[root@172-16-104-15 ~]# kubectl get pods -n hongmi-volume
NAME READY STATUS RESTARTS AGE
mynginx-deploy-1210620599-0tqll 1/1 Running 0 6s
mynginx-deploy-1210620599-kp0p8 1/1 Running 0 6s
mynginx-deploy-1210620599-rb8z5 1/1 Running 0 6s
六、PV和PVC的基本使用
1、概述
什么是pv:
全称为:"persistent volume",属于k8s集群的全局资源,因此并不支持名称空间(namespace)。
该资源对象本身并不负责数据的真实存储,而是负责和后端存储进行关联,每个pv都有提前定义好的存储能力。
持久卷是对存储资源数据卷(volume)创建和使用的抽象,使得存储作为集群中的资源管理。
这样我们就可以对数据卷的使用空间,读写权限做一个基本的权限管控,而不是放任Pod使用所有的数据卷资源。
pv的作用:
PV解决了企业对于存储的依赖问题,比如A公司使用的是nfs作为存储,而B公司使用的是cephfs作为存储,对于运维人员而言可能需要手动维护不同的组件,而一旦使用pv对存储资源进行抽象后,在迁移服务时就无需关心集群底层存储使用的资源,而是直接使用pv即可。
简而言之,就是实现了以下三大特性:
1、后端存储的权限管控(rw,ro);
2、存储能力(比如使用多大的存储空间);
3、后端存储卷(volumes)存储类型的应用解耦。
什么是PVC: 全称为:"persistent volume claim", 属于k8s集群某一个namespace的局部资源。该资源对象本身并不负责数据的真实存储,而是显式声明需要使用的存储资源需求。
PVC的作用:
让用户不需要关心具体的Volume实现细节。pvc的一个最重要的作用就是去关联符合条件的pv,从而实现对存储资源的使用。
推荐阅读:
温馨提示:
(1)全局资源指的是所有的namespace都能看到该资源,很明显是全局唯一的。
(2)局部资源指的是该资源只属于某个namespace哟。
(3)PV和PVC均属于k8s资源,而k8s的所有资源通常都支持打标签的哟。
2、创建PV资源
(1)创建pv的存储目录,注意该目录是NFS的挂载目录哟~
mkdir -pv /data/kubernetes/pv0{1,2,3}
(2)编写pv的资源清单
# cd /oldboyedu/persistentVolume
# cat 01-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01
labels:
type: ssd
spec:
capacity: # 定义PV存储容量的大小
storage: 10Gi
accessModes: # 指定访问模式
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle # 指定PV的回收策略
nfs: # 指定PV后端的支持存储设备类型
path: "/data/kubernetes/pv01"
server: 172.200.1.101 #改为nfs的服务器ip
readOnly: false
# cat 02-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv02
labels:
type: ssd
spec:
capacity: # 定义PV存储容量的大小
storage: 30Gi
accessModes: # 指定访问模式
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle # 指定PV的回收策略
nfs: # 指定PV后端的支持存储设备类型
path: "/data/kubernetes/pv02"
server: 172.200.1.101。#改为nfs的服务器ip
readOnly: false
# cat 03-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv03
labels:
type: ssd
spec:
capacity: # 定义PV存储容量的大小
storage: 50Gi
accessModes: # 指定访问模式
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle # 指定PV的回收策略
nfs: # 指定PV后端的支持存储设备类型
path: "/data/kubernetes/pv03"
server: 172.200.1.101 #改为nfs的服务端ip
readOnly: false
(3)创建pv资源
# kubectl apply -f .
persistentvolume "pv01" created
persistentvolume "pv02" created
persistentvolume "pv03" created
常用的字段如下:
NAME: 有关PV资源的名称。
CAPACITY: 该PV资源的容量大小。
ACCESSMODES(访问模式): 是用来对PV进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括以下几种方式:
ReadWriteOnce(RWO): 读写权限,但是只能被单个节点挂载。
ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载。
ReadWriteMany(RWX): 读写权限,可以被多个节点挂载。
ReadWriteOncePod: 卷可以由单个Pod以读写方式挂载。这仅支持CSI卷和Kubernetes 1.22+版
RECLAIMPOLICY(回收策略):
目前新版本中PV支持的策略有三种:
Retain(保留): 保留数据,需要管理员手工清理数据,这是默认策略哟。
Recycle(回收): 清除PV中的数据,效果相当于执行"rm -rf /data/kubernetes/ *"。
Delete(删除): 与PV相连的后端存储同时删除。
STATUS(状态): 一个PV的生命周期中,可能会处于四种不同的阶段:
Available(可用): 表示可用状态,还未被任何PVC绑定。
Bound(已绑定): 表示PV已经被PVC绑定。
Released(已释放): PVC被删除,但是资源还未被集群重新声明。
Failed(失败): 表示该PV的自动回收失败。
CLAIM: 被那个pvc声明使用
3、创建PVC
(1)创建namespace,以便于将PVC放入该名称空间
# cat ns-hongmi-tomcat.yaml
apiVersion: v1
kind: Namespace
metadata:
name: hongmi-tomcat
# kubectl apply -f ns-hongmi-tomcat.yaml
(2)创建PVC
# cat 01-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: tomcat-mysql-pvc
namespace: hongmi-tomcat
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 35Gi
温馨提示:
(1)当我们创建的PVC申请的存储大小要小于PV现有存储大小时,K8S会自动评估PVC和与哪一个后端PV进行绑定(Bound),如果PVC找不到合适的PV则pvc始终会停留在"Pending"状态
(2)如下图所示,本案例PVC仅申请了35G内存,但实际上PVC会自动去关联全局资源,匹配最合适的PV,这个过程是由K8s集群自动实现的,无需运维人员手动绑定,绑定成功请注意观察PV和PVC的状态均为"Bound"。
(3)如下图所示,如果将PVC申请的数量过大(本案例是32GB),就会导致PVC无法自动关联全局PV资源,因此PVC的状态始终为"Pending",因为此时并没有一个PV的存储能力能够满足该PVC
4、PV和PVC生命周期
PV是群集中的资源。PVC是对这些资源的请求,并且还充当对资源的检查。
PV和PVC之间的相互作用遵循以下生命周期:
Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling
供应准备—Provisioning---通过集群外的存储系统或者云平台来提供存储持久化支持。
- 静态提供Static:集群管理员创建多个PV。 它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费
- 动态提供Dynamic:当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,集群可能会尝试为PVC动态配置卷。 此配置基于StorageClasses:PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置。
绑定—Binding---用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态。
使用—Using---用户可在pod中像volume一样使用pvc。
释放—Releasing---用户删除pvc来回收存储资源,pv将变成“released”状态。由于还保留着之前的数据,这些数据需要根据不同的策略来处理,否则这些存储资源无法被其他pvc使用。
回收—Recycling---pv可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)。
- 保留策略:允许人工处理保留的数据。
- 删除策略:将删除pv和外部关联的存储资源,需要插件支持。
- 回收策略:将执行清除操作,之后可以被新的pvc使用,需要插件支持
5、新建一个mysql实例进行测试
[root@172-16-121-211 ~]# cat mysql-deploy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: hongmi-tomcat
spec:
replicas: 1
selector:
matchLabels:
app: hongmi-mysql
template:
metadata:
labels:
app: hongmi-mysql
spec:
volumes:
- name: datadir
persistentVolumeClaim:
claimName: tomcat-mysql-pvc # 指定PVC的名称,注意要创建的Pod的名称空间中必须存在该PVC哟~
readOnly: false # PVC是否只读,默认值就为false,如果想要只读请设置为"true"
- name: logbin # 我们可以定义多个存储卷,但下面若不挂载,则始终不会应用它哟!
emptyDir: {}
containers:
- name: mysql
image: mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: '123456'
volumeMounts:
- name: datadir
mountPath: /var/lib/mysql
结果展示
6、标签选择器
(1)创建一个pv04,标签为hdd [root@172-16-121-211 ~]# cat 04-pv.yml apiVersion: v1 kind: PersistentVolume metadata: name: pv04 labels: type: hdd spec: capacity: # 定义PV存储容量的大小 storage: 50Gi accessModes: # 指定访问模式 - ReadWriteMany persistentVolumeReclaimPolicy: Recycle # 指定PV的回收策略 nfs: # 指定PV后端的支持存储设备类型 path: "/backup/kubernetes/pv04" server: 172.16.104.15 readOnly: false (2)创建一个pvc,标签选择器为hdd [root@172-16-121-211 ~]# cat 04-pvc.yml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: tomcat-mysql-pvc2 namespace: hongmi-tomcat spec: selector: matchLabels: type: hdd accessModes: - ReadWriteMany resources: requests: storage: 25Gi
结果展示: