Docker&Kubernetes ❀ Kubernetes集群数据存储(PVPVCNFSiSCSI等)
Posted 无糖可乐没有灵魂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker&Kubernetes ❀ Kubernetes集群数据存储(PVPVCNFSiSCSI等)相关的知识,希望对你有一定的参考价值。
文章目录
1、数据存储
当容器的生命周期很短时,会频繁被创建和销毁,那么在容器被销毁时,保存在容器中的数据也会被清除,这种结果对用户来说是非常不适应的,为了持久化的保存容器内数据,Kubernetes引入了Volume数据卷的概念(Docker中也具有Volume概念,其主要作用也是用于映射存储关系,数据保护作用,Kubernetes利用此关系可以直接应用Volume进行数据保护);
Volume是Pod中能够被多个容器访问的共享目录,被定义在Pod上,然后被Pod里的多个容器挂载到具体的文件目录下,Kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储;Volume的生命容器不与Pod中单个容器的生命周期相关,当容器停止或重启时,Volume中的数据也不会丢失,在Kubernetes中的Volume支持多种类型,比较常见的有如下类型:
- 简单存储:EmptyDir、HostPath、NFS、iSCSI;
- 高级存储:PV、PVC;
- 配置存储:ConfigMap、Secret;
[root@master ~]# kubectl explain pod.spec.volumes
KIND: Pod
VERSION: v1
RESOURCE: volumes <[]Object>
FIELDS:
awsElasticBlockStore <Object>
azureDisk <Object>
azureFile <Object>
cephfs <Object>
cinder <Object>
configMap <Object>
csi <Object>
downwardAPI <Object>
emptyDir <Object>
ephemeral <Object>
fc <Object>
flexVolume <Object>
flocker <Object>
gcePersistentDisk <Object>
gitRepo <Object>
glusterfs <Object>
hostPath <Object>
iscsi <Object>
name <string> -required-
nfs <Object>
persistentVolumeClaim <Object>
photonPersistentDisk <Object>
portworxVolume <Object>
projected <Object>
quobyte <Object>
rbd <Object>
scaleIO <Object>
secret <Object>
storageos <Object>
vsphereVolume <Object>
2、基本存储
基本存储方式常见类型为三种:EmptyDir、HostPath、NFS;
2.1 EmptyDir
EmptyDir是最基础的Volume类型,一个EmptyDir就是主机上的一个空目录;EmptyDir是在Pod上被分配到Node时创建的,初始内容为空白,并且无须指定宿主机上对应的目录文件,因为Kubernetes会自动分配一个目录给Pod使用,当Pod被销毁时,EmptyDir中的数据也会被永久删除,因此EmptyDir无法永久性存储Pod内数据;其主要用途如下:
- 临时空间,用于某些应用程序运行时所需要的临时目录,且无需永久保存数据;
- 一个容器需要从另一个容器中获取数据的目录,如多容器共享目录;
#创建YAML文件
[root@master ~]# cat volume-emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-emptydir
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx
containerPort: 80
volumeMounts: #将logs-volume挂载到容器nginx的/var/log/nginx目录
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/access.log"]
volumeMounts: #将logs-volume挂载到容器busybox的/logs目录
- name: logs-volume
mountPath: /logs
volumes: #数据卷配置
- name: logs-volume
emptyDir: #数据卷类型
#调用YAML文件
[root@master ~]# kubectl apply -f volume-emptydir.yaml
pod/volume-emptydir created
#查看Pod相关IP地址
[root@master ~]# kubectl get pod -n dev -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-emptydir 2/2 Running 0 23s 10.244.166.186 node2.k8s <none> <none>
#访问目标服务,并开启第二终端
[root@master ~]# curl http://10.244.166.186:80
#第二终端查看相关日志信息;
[root@master ~]# kubectl logs -f volume-emptydir -n dev -c busybox
10.244.125.128 - - [24/Jan/2022:02:34:02 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.61.1" "-"
10.244.125.128 - - [24/Jan/2022:02:34:04 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.61.1" "-"
#删除
[root@master ~]# kubectl delete -f volume-emptydir.yaml
pod "volume-emptydir" deleted
2.2 HostPath
由于EmptyDir无法对容器数据永久化,因此Kubernetes设计出了HostPath,将Node主机中的一个实际目录挂载到Pod中,以供容器使用,当Pod被销毁时,数据仍然存在与Node的相关目录中;
HostPath的类型:
- DirectoryOrCreate:目录存在就直接使用,不存在就先创建后使用;
- Directory:目录必须存在;
- FileOrCreate:文件存在就使用,不存在就先创建后使用;
- File:文件必须存在;
- Socket:套接字必须存在;
- CharDevice:字符设备必须存在;
- BlockDevice:块设备必须存在;
#创建YAML文件
[root@master ~]# cat volume-hostpath.yaml
~
volumes: #数据卷配置
- name: logs-volume
hostPath: #数据卷类型
path: /root/logs
type: DirectoryOrCreate #目录存在直接使用,若不存在创建后使用
#调用YAML文件
[root@master ~]# kubectl apply -f volume-hostpath.yaml
pod/volume-hostpath created
#查看Pod相关IP地址与所在Node节点
[root@master ~]# kubectl get pod -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-emptydir 2/2 Running 0 40s 10.244.166.187 node2.k8s <none> <none>
#访问对应服务
[root@master ~]# curl http://10.244.166.187:80
#在Node2上查看对应日志信息
[root@node2 ~]# cat /root/logs/access.log
10.244.125.128 - - [24/Jan/2022:03:23:47 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.61.1" "-"
10.244.125.128 - - [24/Jan/2022:03:24:59 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.61.1" "-"
#删除
[root@master ~]# kubectl delete -f volume-hostpath.yaml
pod "volume-hostpath" deleted
2.3 NFS
HostPath虽然解决了数据持久化的问题,但是Node节点故障则无法避免数据丢失问题,因此Kubernetes引入了NFS、iSCSI、CIFS等外部存储技术;NFS服务需要外部搭建一个NFS服务器,然后将Pod中的存储直接连接到NFS系统上,无论Pod如何在节点上转移或删除,只要Node节点与NFS的网络通信无故障则数据正常保存;跳转查看NFS参数详解
2.3.1 搭建NFS服务器
#安装NFS服务,Master与Node均需要安装
[root@master ~]# yum install -y nfs-utils rpcbind
#确认安装服务包版本,部分系统默认安装nfs-utils,不安装rpcbind,取决于系统版本
[root@master ~]# rpm -qa nfs-utils rpcbind
nfs-utils-2.3.3-31.el8.x86_64
rpcbind-1.2.5-7.el8.x86_64
#创建共享目录,注意目录权限
[root@master ~]# mkdir /root/nfs -pv
mkdir: created directory '/root/nfs'
#由于后面会使用nginx容器修改此目录内容,因此需要other具有x权限,默认umask为022,创建新文件权限不足,需要加权
[root@master ~]# umask
0022
[root@master ~]# chmod o=rwx -R /root/nfs/
#配置NFS服务, 共享相关目录,共享权限为rw可读可写,其他配置参数详见CSDN
[root@master ~]# cat /etc/exports
/root/nfs 10.81.20.0/24(rw)
#重启服务(只在Master上启动NFS服务)
[root@master ~]# systemctl restart nfs-server rpcbind
#若节点操作了重启需要关闭
[root@master ~]# systemctl stop nfs-server rpcbind
#测试共享目录是否可使用
[root@master ~]# showmount -e 10.81.20.170
Export list for 10.81.20.170:
/root/nfs 10.81.20.0/24
2.3.2 创建Pod调用NFS
#创建YAML文件
[root@master ~]# cat volume-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-nfs
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
volumeMounts: #将logs-volume挂载到容器nginx的/var/log/nginx目录
- name: logs-volume
mountPath: /var/log/nginx
- name: centos
image: centos:latest #此处采用centos镜像替换busybox,原理完全一致
command: ["/bin/sh", "-c","tail -f /logs/access.log"]
volumeMounts: #将logs-volume挂载到容器busybox的/logs目录
- name: logs-volume
mountPath: /logs
volumes: #数据卷配置
- name: logs-volume
nfs: #数据卷类型
server: 10.81.20.170 #NFS服务器IP地址
path: /root/nfs #共享文件目录路径
[root@master ~]# kubectl apply -f volume-nfs.yaml
pod/volume-nfs created
#查看Pod相关IP地址
[root@master ~]# kubectl get pod -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
volume-nfs 2/2 Running 0 6m40s 10.244.166.140 node2.k8s <none> <none>
#访问对应服务
[root@master ~]# curl http://10.244.166.140:80
#查看本地NFS共享目录下的日志信息
[root@master ~]# cat /root/nfs/access.log
10.244.125.128 - - [25/Jan/2022:02:54:30 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.61.1" "-"
10.244.125.128 - - [25/Jan/2022:02:54:38 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.61.1" "-"
#删除
[root@master ~]# kubectl delete -f volume-nfs.yaml
pod "volume-nfs" deleted
3、高级存储
由于Kubernetes支持的存储系统非常多,要求全部掌握没有太大必要,一次你为了用户使用,Kubernetes引入了PV与PVC两个资源概念,应用与存储配置;
3.1 PV和PVC基本概念
- PV(Persistent Volume)持久化卷组:对底层共享存储的一种概念,默认情况下PV由KUbernetes管理员进行配置与创建,与底层的共享技术相关,并通过插件完成与共享存储的对接;
- PVC(Persistent Volume Claim)持久化卷组声明:用户对于存储需要的一种声明使用,PVC是用户向Kubernetes申请存储资源的一种请求;
3.2 PV详解
PV是存储资源的抽象(PV为系统存储资源,不需要分配到具体的名称空间),下面为资源配置清单:
[root@master ~]# kubectl explain PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
nfs: #存储类型,标识系统底层存储方式或服务
capacity: #存储能力,目前只支持空间大小设置
storage: 1Gi
accessModes: #访问模式
storageClassName: #存储类别
persistentVolumeReclaimPolicy: #回收策略
3.2.1 参数详解
存储类型
标识系统底层存储方式与服务,常见为NFS、iSCSi、CIFS等;
存储能力
目前Kubernetes仅支持设置存储大小,后续会加入IOPS、吞吐量等其他参数;
访问模式
用于描述用户应对存储资源的访问权限,访问权限主要有下面几种方式:
- ReadWriteOnce(RWO):读写权限,只能被单个节点挂载;
- ReadOnlyMany(ROX):只读权限,可以被多个节点挂载;
- ReadWriteMany(RWX):读写权限,可以被多个节点挂载;
不同的存储类型可能支持的访问模式不同;
回收策略
当PV不再被使用时,对其的处理方式,主要有下面几种方式:
- Retain 保留:保留数据,需要管理员手工删除;
- Recycle 回收:清除PV中保存的数据,相当于执行命令 rm -rf /the_volume_name/*
- Delete 删除:与PV相连接的后端存储完成volume的删除操作;
不同的存储类型可能支持的回收策略不同;
存储类别
PV可以通过资源清单配置指定存储类别;
- 具有特定类别的PV只能与请求了此类别的PVC进行绑定;
- 未设置类别的PV只能与不请求任何类别的PVC进行绑定;
当前状态
PV从创建到删除,其生命周期分为四个阶段:
- Available 可用:可使用状态,未被PVC绑定;
- Bound 绑定:PV目前已经被PVC绑定;
- Released 释放:PVC删除,资源未被集群重新声明;
- Failed 失败:PV自动回收失败;
3.2.2 案例演示
#准备NFS服务环境,创建对应共享目录(此处可参考2.3章节)
[root@master ~]# mkdir /root/nfs/pv1,pv2,pv3
#配置NFS服务,共享相关目录
[root@master ~]# cat /etc/exports
/root/nfs/pv1 10.81.20.0/24(rw)
/root/nfs/pv2 10.81.20.0/24(rw)
/root/nfs/pv3 10.81.20.0/24(rw)
#重启NFS服务
[root@master ~]# systemctl restart nfs-server
#检测共享目录是否可用
[root@master ~]# showmount -e 10.81.20.170
Export list for 10.81.20.170:
/root/nfs/pv3 10.81.20.0/24
/root/nfs/pv2 10.81.20.0/24
/root/nfs/pv1 10.81.20.0/24
#创建YAML文件
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
nfs:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/nfs/pv1
server: 10.81.20.170
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv2
spec:
nfs:
capacity:
storage: 2Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/nfs/pv2
server: 10.81.20.170
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv3
spec:
nfs:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /root/nfs/pv3
server: 10.81.20.170
#调用YAML文件
[root@master ~]# kubectl apply -f pv.yaml
persistentvolume/pv1 created
persistentvolume/pv2 created
persistentvolume/pv3 created
#查看PV信息
[root@master ~]# kubectl get pv -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
pv1 1Gi RWX Retain Available 42s Filesystem
pv2 2Gi RWX Retain Available 42s Filesystem
pv3 3Gi RWX Retain Available 42s Filesystem
#查看PV详细信息
[root@master ~]# kubectl describe pv pv1
Name: pv1
Labels: <none>
Annotations: <none>
Finalizers: [kubernetes.io/pv-protection]
StorageClass:
Status: Available
Claim:
Reclaim Policy: Retain
Access Modes: RWX
VolumeMode: Filesystem
Capacity: 1Gi
Node Affinity: <none>
Message:
Source:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 10.81.20.170
Path: /root/nfs/pv1
ReadOnly: false
Events: <none>
3.3 PVC详解
PVC是存储资源的调用申请(PVC为系统存储资源的调用申请,需要分配到具体的名称空间),下面为资源配置清单:
[root@master ~]# kubectl explain PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv1
namespace: dev
spec:
accessModes: #访问模式
selector: #采用标签选择方式选择具体的PV
storageClassName: #存储类别
resources: #请求存储资源空间大小
requests:
storage: 1Gi
3.3.1 参数详解
访问模式
用于描述用户应对存储资源的访问方式;
选择条件
通过标签设置,可以使得选择标签即选择相对应的PV资源;
存储类别
PVC定义时可以设定需要的后端存储类别进而选择相对应的PV资源,只有设置了此Class的PV资源会被选择;
资源请求
对资源请求空间大小的描述;
3.3.2 案例演示
#创建YAML文件
[root@master ~]# cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc1
namespace: dev
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc2
namespace: dev
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc3
namespace: dev
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
#调用YAML文件
[root@master ~]# kubectl apply -f pvc.yaml
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
persistentvolumeclaim/pvc3 created
#查看PV与PVC绑定信息
[root@master ~]# kubectl get pvc -n dev -o wide
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
pvc1 Bound pv3 3Gi RWX 43s Filesystem
pvc2 Pending 43s Filesystem
pvc3 Pending 43s Filesystem
[root@master ~]# kubectl get pv -owide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
pv1 1Gi RWX Retain Released dev/pvc1 28m Filesystem
pv2 2Gi RWX Retain Released dev/pvc2 28m Filesystem
pv3 3Gi RWX Retain Bound dev/pvc1 28m Filesystem
#创建一个Pod,调用PVC1
[root@master ~]# cat pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-test
namespace: dev
spec:
containers:
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 30; done;"]
volumeMounts:
- name: volume
mountPath: /root
volumes:
- name: volume
persistentVolumeClaim:
claimName: pvc1
readOnly: false
[root@master ~]# kubectl apply -f pod-test.yaml
pod/pod-test created
#文件权限需要添加,如果已经添加则直接忽略
[root@master ~]# chmod o=rwx -R /root/nfs/
#查看Pod信息
[root@master ~]# kubectl get pod -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-test 1/1 Running 0 28s 10.244.166.142 node2.k8s <none> <none>
#测试Pod内数据是否可存储
[root@master nfs]# kubectl exec -it pod-test -n dev /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
bash-4.4# cat /root/out.txt
pod1
pod1
pod1
bash-4.4# ^C
bash-4.4# exit
exit
command terminated with exit code 130
#删除名称空间
[root@master nfs]# kubectl delete ns dev
namespace "dev" deleted
#PV状态改变为回收状态
[root@master nfs]# kubectl get pv -o wide -w
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
pv1 1Gi RWX Retain Released dev/pvc1 63m Filesystem
pv2 2Gi RWX Retain Released dev/pvc2 63m Filesystem
pv3 3Gi RWX Retain Released dev/pvc1 63m Filesystem
3.4 生命周期
PV和PVC是互相对应的,PV和PVC之间的相互作用遵循以下生命周期:
资源供应
管理员手动创建底层存储服务与PV资源;
资源绑定
用户创建PVC,Kubernetes负责根据PVC互联对应的PV,并进行绑定,当用户定义好PVC后,系统会根据PVC对资源的请求参数在已经存在的PV资源中选择一个满足条件的;
- 当匹配到对应的PV后就会将PV与PVC绑定;
- 当匹配不到PV时,PVC一直处于pending状态,直到管理员创建一个符合要求的PV进行绑定;
资源使用
用户可以在Pod中像Volume一样使用对应的PV;将其挂载到对应目录下即可存储数据;
资源释放
当存储资源使用结束后,用户可以删除PVC,与其绑定的PV将会被标记为Released 释放状态,但是不能立刻与其他的PVC进行绑定,通过之前的PVC写入的数据可能仍然存储在设备上,因此只有清除后的PV才可以被再次使用;
资源回收
管理员可以设置PV的回收策略,用于设置与之绑定的PVC释放资源后如何处理遗留数据问题,因此PV的存储空间回收完成才可以被新的PVC绑定和使用;
3.5 案例展示(iSCSI)
实验环境为虚拟机,由于当前系统创建时只有一块磁盘,分区占用所有空间,因此为完成实验需要额外添加一块硬盘,进行磁盘分区,并且格式化为ext4;
3.5.1 构建新磁盘分区
#查看当前已存在的磁盘分区
[root@master ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 200G 0 disk
├─sda1 8:1 0 600M 0 part /boot/efi
├─sda2 8:2 0 1G 0 part /boot
└─sda3 8:3 0 48.4G 0 part
├─rhel-root 253:0 0 46.4G 0 lvm /
└─rhel-swap 253:1 0 2.1G 0 lvm
sdb 8:16 0 20G 0 disk #不同的系统版本与磁盘类型会导致名称不同
└─sdb1 8:17 0 1G 0 part #环境目前存在sdb1,因此后面新创建分区名称为sdb2
sr0 11:0 1 7.9G 0 rom
#创建新分区
[root@master ~]# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.32.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): n #添加分区
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p): p #添加主分区
Partition number (2-4, default 2): 2 #分区数字为2
First sector (2099200-41943039, default 2099200): #分区开始部分,此处回车,保持默认即可
Last sector, +sectors or +sizeK,M,G,T,P (2099200-41943039, default 41943039): +1G #设置分区大小,按照所需大小进行设置,此处分区设置为1G,支持单位K M G T P
Created a new partition 2 of type 'Linux' and of size 1 GiB.
Command (m for help): w #保存并退出
The partition table has been altered.
Syncing disks.
#查看新分区是否创建成功
[root@master ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 200G 0 disk
├─sda1 8:1 0 600M 0 part /boot/efi
├─sda2 8:2 0 1G 0 part /boot
└─sda3 8:3 0 48.4G 0 part
├─rhel-root 253:0 0 46.4G 0 lvm /
└─rhel-swap 253:1 0 2.1G 0 lvm
sdb 8:16 0 20G 0 disk
├─sdb1 8:17 0 1G 0 part
└─sdb2 8:18 0 1G 0 part #新增sdb2分区,大小为1G
sr0 11:0 1 7.9G 0 rom
#另一种查询方法
[root@master ~]# fdisk -l
3.5.2 格式化新磁盘分区
#默认Linux系统构建新分区需要重启系统识别,此命令可以在不重启系统下识别新分区
[root@master ~]# partprobe
Warning: Unable to open /dev/sr0 read-write (Read-only file system). /dev/sr0 has been opened read-only.
以上是关于Docker&Kubernetes ❀ Kubernetes集群数据存储(PVPVCNFSiSCSI等)的主要内容,如果未能解决你的问题,请参考以下文章
Docker&Kubernetes ❀ Kubernetes集群安装部署过程与常见的错误解决方法
Docker&Kubernetes ❀ Kubernetes集群安装部署过程与常见的错误解决方法
Docker&Kubernetes ❀ Kubernetes集群实践与部署笔记知识点梳理
Docker&Kubernetes ❀ Docker 容器技术笔记链接梳理