存储管理
存储管理
引入
创建的存储需求
- 用户数据
- 文件数据
- 配置文件
- 共享数据
- 程序数据
- 日志文件
什么是Volumes
Kubernetes的Volumes是一个对存储资源的抽象,属于Pod级别的一个配置字段。
Volumes在Pod中绑定多个、多种的数据类型,比如NFS、NAS、CEPH等,这些绑定的数据可以挂载到Pod中的一个或多个容器中,从而实现容器的数据持久化和数据共享。

使用 Volumes 直接绑定存储
Volume常见存储类型
EmptyDir:临时目录,当Pod从节点删除时,EmptyDir中的数据也会被删除,常用于临时数据存储,如缓存、中间计算结果、数据共享等HostPath:节点数据共享,HostPath可以让容器直接访问节点上的文件或目录,常用于和节点共享数据ConfigMap&Secret:用于挂载ConfigMap和Secret到容器中Downward API:元数据挂载,主要用于容器访问Pod的一些元数据,比如标签、命名空间等(不推荐使用,可以直接使用env的方式去挂载元数据)NAS&NFS:网络文件系统,主要用于挂载远程存储到容器中,实现跨主机的数据共享和持久化PVC:PV请求,K8s中的一类资源,用于配置多种不同的存储后端
EmptyDir
EmptyDir 是 Kubernetes 支持的临时存储功能,主要用于多个容器的数据共享,当 Pod 重建时,数据会被清空。EmptyDir 可以绑定主机上的 硬盘 和 内存 作为 Volume,比如把 emptyDir.medium 字段设置为 Memory,就可以让 Kubernetes 使用 tmpfs(内存支持的文件系统)。虽然 tmpfs 非常快,但是设置的大小会被计入到 Container 的内存限制当中。
磁盘类型的 EmptyDir
配置使用 emptyDir 卷非常简单,直接指定 emptyDir 为{}即可(如果不需要指定其他配置)
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: emptydir
name: emptydir
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: emptydir
template:
metadata:
labels:
app: emptydir
spec:
containers:
- image: registry.cn-beijing.aliyuncs.com/monap/nginx:1.15.12
imagePullPolicy: IfNotPresent
name: nginx
volumeMounts:
- mountPath: /opt
name: share-volume
- image: registry.cn-beijing.aliyuncs.com/monap/redis:7.2.5
imagePullPolicy: IfNotPresent
name: redis
volumeMounts:
- mountPath: /mnt
name: share-volume
volumes:
- name: share-volume
emptyDir: {}进到容器中即可查看到挂载的目录,可以发现emptyDir 磁盘类型是在宿主机上创建的临时目录,并且使用的是宿主机的根文件系统空间。这里的挂载目录/opt的size就是宿主机磁盘的大小
$ df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 39G 9.2G 30G 24% /
tmpfs tmpfs 64M 0 64M 0% /dev
/dev/mapper/rl_192-root xfs 39G 9.2G 30G 24% /opt内存类型 EmptyDir
使用内存作为 EmptyDir,只需要把 medium 改为 Memory 即可。这里medium只能为空或者Memory,为空时就是磁盘类型
volumes:
- name: share-volume
emptyDir:
medium: Memory创建 Pod,即可在 Pod 的容器内看到使用 tmpfs 挂载的/opt 目录,这里的挂载目录/opt的size就是宿主机内存的大小
$ df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 39G 7.1G 32G 19% /
tmpfs tmpfs 64M 0 64M 0% /dev
tmpfs tmpfs 3.5G 0 3.5G 0% /optEmptyDir 大小限制
两种类型的 EmptyDir 都支持限制卷的大小,只需要添加 sizeLimit 字段即可
volumes:
- name: share-volume
emptyDir:
medium: Memory
sizeLimit: 10Mi再次进入到容器中查看
$ df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 39G 7.1G 32G 19% /
tmpfs tmpfs 64M 0 64M 0% /dev
tmpfs tmpfs 3.5G 0 10M 0% /optEmptyDir 注意项
- 磁盘类型的 emptyDir,限制大小后不会显示具体限制的大小
- 磁盘类型的emptyDir超出最大限制时,Pod 将会变成 Completed 状态被驱逐不再提供服务,同时将会新创建一个 Pod
- 内存类型的 emptyDir 不会超出限制的大小,如不限制将会使用机器内存的最大值, 或容器内存限制之和的最大值
HostPath
HostPath 类型的卷可将节点上的文件或目录挂载到 Pod 上,用于容器和节点之间的数据共享。
比如使用 hostPath 类型的卷,将主机的/data 目录挂载到 Pod 的/test-pd 目录
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: registry.cn-beijing.aliyuncs.com/monap/nginx:1.15.12
imagePullPolicy: IfNotPresent
name: nginx
volumeMounts:
- mountPath: /opt
name: share-volume
- image: registry.cn-beijing.aliyuncs.com/monap/redis:7.2.5
imagePullPolicy: IfNotPresent
name: redis
volumeMounts:
- mountPath: /mnt
name: share-volume
- mountPath: /data
name: data
volumes:
- name: share-volume
emptyDir:
medium: Memory
sizeLimit: 10Mi
- name: data
hostPath:
path: /datahostPath 卷常用的 type(类型)如下:
type 为空字符串:默认选项,意味着挂载 hostPath 卷之前不会执行任何检查DirectoryOrCreate:如果给定的 path 不存在任何东西,那么将根据需要创建一个权限为 0755 的空目录,和 Kubelet 具有相同的组和权限Directory:目录必须存在于给定的路径下FileOrCreate:如果给定的路径不存储任何内容,则会根据需要创建一个空文件,权限设置为 0644,和 Kubelet 具有相同的组和所有权File:文件,必须存在于给定路径中Socket:UNIX 套接字,如某个程序的 socket 文件,必须存在于给定路径中CharDevice:字符设备,如串行端口、声卡、摄像头等,必须存在于给定路径中,且只有 Linux 支持BlockDevice:块设备,如硬盘等,必须存在于给定路径中,且只有 Linux 支持
NFS/NAS
使用远程存储介质,可以实现跨主机容器之间的数据共享,比如使用 NFS、NAS、CEPH 等。
NFS 搭建
准备一台机器用于搭建 NFS,首先安装 NFS
# CentOS、Rocky 系列
$ yum install nfs-utils rpcbind -y
# Ubuntu 系列
$ apt install nfs-kernel-server -y配置共享目录
$ mkdir /data/nfs
$ echo "/data/nfs/
192.168.181.0/24(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
# 加载 NFS 配置
$ exportfs -r启动 NFS
# CentOS、Rocky 系列
$ systemctl enable --now nfs-server rpcbind
# Ubuntu 系列
$ systemctl enable --now nfs-kernel-server客户端挂载测试
# 首先安装客户端工具
# CentOS、Rocky 系列
$ yum install nfs-utils -y
# Ubuntu 系列
$ apt install nfs-common -y
# 挂载
$ mount -t nfs 192.168.181.140:/data/nfs /mnt/
$ df -Th | grep mnt
192.168.181.140:/data/nfs nfs4 39G 9.2G 30G 24% /mnt挂载 NFS 类型的卷
直接在 volumes 上添加 NFS 的卷即可
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nfs
name: nfs
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nfs
template:
metadata:
labels:
app: nfs
spec:
containers:
- image: registry.cn-beijing.aliyuncs.com/monap/nginx:1.15.12
imagePullPolicy: IfNotPresent
name: nginx
volumeMounts:
- mountPath: /opt
name: nfs-volume
- image: registry.cn-beijing.aliyuncs.com/monap/redis:7.2.5
imagePullPolicy: IfNotPresent
name: redis
volumeMounts:
- mountPath: /mnt
name: nfs-volume
volumes:
- name: nfs-volume
nfs:
server: 192.168.181.140
path: /data/nfs/testdata进入到容器中,即可查看挂载的目录
$ df -Th
Filesystem Type Size. Used Avail Use% Mounted on
overlay overlay 39G 9.2G 30G 24% /
tmpfs tmpfs 64M. 0 64M. 0% /dev
192.168.181.140:/data/nfs/testdata nfs4 39G 9.2G 30G 24% /opt通过Kubernetes创建Pod并使用NFS类型的持久化存储(无论是直接指定NFS,还是通过PV/PVC)时,Kubelet(Kubernetes的节点代理)会在宿主机上执行实际的挂载操作,以便将远程的NFS共享目录呈现给Pod中的容器。
如果 Pod 一直处于创建中,可能是由于没有安装客户端工具导致的,可以使用 describe 查看详情
$ kubectl get po
nfs-6db79bb58b-m4vvj 0/2 ContainerCreating 0 59s
$ kubectl describe po nfs-6db79bb58b-m4vvj
Warning FailedMount 55s (x8 over 119s) kubelet
MountVolume.SetUp failed for volume "nfs-volume" : mount failed: exit status 32
Mounting command: mount
Mounting arguments: -t nfs 192.168.181.140:/data/nfs/testdata
/var/lib/kubelet/pods/faae4701-1c1d-4a2d-a16efa76c64a7ae7/volumes/kubernetes.io~nfs/nfs-volume
Output: mount: /var/lib/kubelet/pods/faae4701-1c1d-4a2d-a16efa76c64a7ae7/volumes/kubernetes.io~nfs/nfs-volume: bad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount. helper program.使用 PV 和 PVC 挂载存储
为什么需要PV和PVC
存储需求多样性,只有Volume无法满足
- 当某个数据卷不再被挂载使用时,里面的数据如何处理?
- 如果想要实现只读挂载如何处理?
- 如果想要只能一个Pod挂载如何处理?
- 如何只允许某个Pod使用10G的空间?
- 同一个应用不同副本如何使用不同的数据目录?
存储配置的复杂度,Volume不适用于所有人
- 配置参数的专业性过高,开发人员(用户)在定义 Pod 时,必须了解底层存储的细节
- 开发人员接触到了基础设施的敏感信息
代码维护复杂度,不符合云原生设计
- 配置与基础设施强耦合,导致"硬编码"
- 存储变更的连锁反应,当决定将存储后端从 NFS 迁移到 CephRBD,需要找出所有使用了该 NFS 的 Pod,逐个修改它们的 YAML 文件
- 缺乏逻辑抽象,导致代码重复
PV和PVC概念及工作原理
PersistentVolume:简称PV,是由Kubernetes管理员设置的存储,可以配置Ceph、NFS、GlusterFS等常用存储,相对于Volume配置,提供了更多的功能,比如生命周期的管理、大小的限制,同时也可以支持存储的动态分配。
PersistentVolumeClaim:简称PVC,是对存储PV的请求,表示需要什么类型的PV,并绑定该PV。如果某个服务需要挂载存储,只需要在Volumes中添加PVC类型的Volume即可,并且通常只需要指定PVC的名称即可,无需关心整个的存储配置细节。

PV和PVC使用示例

PV的访问策略
注意:单节点不是单Pod。虽然只允许一个节点(Node)挂载,但该节点上可以运行多个 Pod,这些 Pod 都可以访问该卷。
ReadWriteOnce:可以被单节点以读写模式挂载,命令行中可以被缩写为 RWOReadOnlyMany:可以被多个节点以只读模式挂载,命令行中可以被缩写为 ROXReadWriteMany:可以被多个节点以读写模式挂载,命令行中可以被缩写为 RWXReadWriteOncePod:只能被单个 Pod 以读写模式挂载,命令行中可以被缩写为 RWOP, 目前仅支持在 CSI 且 Kubernetes 1.22+中使用
常见存储支持的访问策略

PV的回收策略
如果更改回收策略,只需要通过 persistentVolumeReclaimPolicy 字段配置即可
Retain:保留,该策略允许手动回收资源,当删除 PVC 时,PV 仍然存在,PV 被视为已释放,管理员可以手动回收卷。Recycle:回收,如果 Volume 插件支持,Recycle 策略会对卷执行 rm -rf 清理该 PV,并使其可用于下一个新的 PVC,但是本策略将来会被弃用,目前只有 NFS 和 HostPath 支持该策略。Delete:删除,如果 Volume 插件支持,删除 PVC 时会同时删除 PV,动态存储默认为 Delete,目前支持 Delete 的存储后端包括 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder、Ceph 等。
PV的状态
Available:可用,没有被 PVC 绑定的空闲资源Bound:已绑定,已经被 PVC 绑定Released:已释放,PVC 被删除,但是资源还未被重新使用Failed:失败,自动回收失败
HostPath类型的PV
创建 HostPath 类型的 PV
capacity:容量配置volumeMode:卷的模式,目前支持 Filesystem(文件系统) 和 Block(块),其中 Block 类型需要后端存储支持,默认为文件系统accessModes:该 PV 的访问模式storageClassName:PV 的类,一个特定类型的 PV 只能绑定到特定类别的 PVCpersistentVolumeReclaimPolicy:回收策略
# vim hostpath-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: hostpath
volumeMode: Filesystem
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"NFS/NAS类型的PV
创建一个 NAS/NFS 类型的 PV
# vim nas-nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs-slow
nfs:
# NFS 上的共享目录
path: /data/nfs
# NFS 的 IP 地址
server: 192.168.181.140创建PVC绑定PV
比如创建一个 PVC 绑定到 NFS 的 PV 上
# vim pvc-nfs.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pvc-claim
spec:
storageClassName: nfs-slow
accessModes:
- ReadWriteMany
resources:
requests:
storage: 3Gi通过 PVC 把存储挂载到容器中
apiVersion: apps/v1
kind: Deployment
metadata:
name: pvc-test
namespace: default
labels:
app: pvc-test
spec:
replicas: 2
selector:
matchLabels:
app: pvc-test
template:
metadata:
labels:
app: pvc-test
spec:
volumes:
- name: data
persistentVolumeClaim:
claimName: task-pvc-claim
containers:
- name: pvc-test
image: nginx
imagePullPolicy: IfNotPresent
env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: C.UTF-8
volumeMounts:
- name: data
mountPath: "/usr/share/nginx/html"PVC创建和挂载失败的原因
PVC 一直 Pending 的原因:
- PVC 的空间申请大小大于 PV 的大小
- PVC 的 StorageClassName 没有和 PV 的一致
- PVC 的 accessModes 和 PV 的不一致
- 请求的 PV 已被其他的 PVC 绑定
挂载 PVC 的 Pod 一直处于 Pending:
- PVC 没有创建成功/PVC 不存在
- PVC 和 Pod 不在同一个 Namespace
动态存储
理解
什么是动态存储
PV的定义依旧很困难,前面并没有解决掉配置复杂度(各种存储参数)的问题。我们可以使用动态存储解决掉管理PV的复杂度。
动态存储可以在用户需要存储资源时自动创建和配置PV,而无需手动创建和配置PV。可以让存储资源的分配变得更加灵活,并且可以随着应用程序的需求变化而动态调整。
动态PV使用示例

工作原理
动态存储依赖 StorageClass 和 CSI(ContainerStorageInterface)实现,当我们创建一个PVC时,通过 storageClassName 指定动态存储的类,该类指向了不同的存储供应商,比如Ceph、NFS等,之后通过该类就可完成PV的自动创建。
动态存储架构图

容器存储接口 -CSI
CSI(ContainerStorageInterface)是一个标准化的存储接口,用于在容器环境中集成外部存储系统。它提供了一种统一的方式来集成各种存储系统,无论是云提供商的存储服务,还是自建的存储集群,都可以通过CSI对接到容器平台中。
在同一个Kubernetes集群中,可以同时存在多个CSI对接不同的存储平台,之后可以通过 StorageClass 的 provisioner 字段声明该Class对接哪一种存储平台。
存储类 - StorageClass
StorageClass 和 IngressClass 类似,用于定义存储资源的类别,可以使用内置的存储插件或第三方的CSI驱动程序关联存储。
在同一个Kubernetes集群中,可以同时存在多个StorageClass对接不同或相同的CSI,用于实现更多的动态存储需求场景。
多个
StorageClass对接同一个 CSI 驱动,本质上是为了通过不同的“服务等级”或“功能特性”来满足不同应用对存储的多样化需求。同一个 CSI 驱动(例如csi-aws-ebs)通常能提供多种底层存储资源(例如 AWS 上不同型号的 EBS 卷)。通过创建多个StorageClass,我们可以将这些选项“包装”成不同档次的产品,供用户按需选择。

安装 NFS/NAS CSI
通过 kubectl 方式安装
# 下载安装文件
git clone https://github.com/kubernetes-csi/csi-driver-nfs.git
# 安装 CSI
$ cd csi-driver-nfs/
$ sed -i "s#registry.k8s.io#k8s.m.daocloud.io#g" deploy/v4.12.1/*.yaml
$ ./deploy/install-driver.sh v4.12.1 local
# 查看 Pod 状态
$ kubectl -n kube-system get pod -l app=csi-nfs-controller
$ kubectl -n kube-system get pod -l app=csi-nfs-node
# 查看 CSI
$ kubectl get csidriver
NAME ATTACHREQUIRED PODINFOONMOUNT STORAGECAPACITY TOKENREQUESTS REQUIRESREPUBLISH MODES AGE
nfs.csi.k8s.io false false false false Persistent 10m创建 StorageClass
更改 StorageClass 配置
# vim deploy/v4.12.1/storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
# 主要修改这里
server: 192.168.181.140
share: /data/nfs
# csi.storage.k8s.io/provisioner-secret is only needed for providing mountOptions in DeleteVolume
# csi.storage.k8s.io/provisioner-secret-name: "mount-options"
# csi.storage.k8s.io/provisioner-secret-namespace: "default"
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true
mountOptions:
- nfsvers=4.1查看 StorageClass
$ kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 23s挂载测试
# vim deploy/example/pvc-nfs-csi-dynamic.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs-dynamic
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: nfs-csi
# 创建pvc
kubectl create -f deploy/example/pvc-nfs-csi-dynamic.yaml
# 查看pvc和pv
kubectl get pvc pvc-nfs-dynamic
kubectl get pv
# 此时会在 NFS 目录下创建一个共享目录
ls /data/nfs/挂载测试
# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-nfs
namespace: default
spec:
replicas: 3
selector:
matchLabels:
name: deployment-nfs
template:
metadata:
name: deployment-nfs
labels:
name: deployment-nfs
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: deployment-nfs
image: registry.cn-beijing.aliyuncs.com/monap/nginx:1.15.12
command:
- "/bin/bash"
- "-c"
- |
while true; do
echo $(hostname) $(date) >> /mnt/nfs/outfile;
sleep 5;
done
volumeMounts:
- name: nfs
mountPath: "/mnt/nfs"
readOnly: false
volumes:
- name: nfs
persistentVolumeClaim:
claimName: pvc-nfs-dynamic在 NFS 节点的数据目录,即可查看到来自于不同示例写入的数据
tail -f /data/nfs/pvc-80d65113-8693-4a66-9474-fef76f1b439e/outfile测试完毕后删除测试数据
# 删除测试应用
$ kubectl delete -f deployment.yaml
# 删除pvc
$ kubectl delete pvc pvc-nfs-dynamic
# 此时 PV 和数据也会被删除
$ kubectl get pv
No resources found
$ ls /data/nfs/部署 MySQL 并持久化数据
创建一个 MySQL 的 PVC
# cat mysql-pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-data
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: nfs-csi创建一个 MySQL 的 Deployment
# cat mysql-deploy.yaml
apiVersion: apps/v1
kind: Deployment
meta
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
volumes:
- name: data
persistentVolumeClaim:
claimName: mysql-data
# - name: conf
# configMap:
# name: mysqld.cnf
# defaultMode: 420
containers:
- name: mysql
image: registry.cn-beijing.aliyuncs.com/monap/mysql:8.0.20
imagePullPolicy: IfNotPresent
ports:
- name: tcp-3306
containerPort: 3306
protocol: TCP
env:
- name: MYSQL_ROOT_PASSWORD
value: "password_123"
volumeMounts:
- name: data
mountPath: /var/lib/mysql
# - name: conf
# readOnly: true
# mountPath: /etc/mysql/mysql.conf.d/
livenessProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 30
timeoutSeconds: 3
periodSeconds: 30
successThreshold: 1
failureThreshold: 2
readinessProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 30
timeoutSeconds: 3
periodSeconds: 30
successThreshold: 1
failureThreshold: 2
# lifecycle:
# postStart:
# exec:
# command: [ "sh", "-c", "rm -rf /var/lib/mysql/lost+found" ]
restartPolicy: Always
dnsPolicy: ClusterFirst
strategy:
type: Recreate创建 MySQL,并查看启动状态
$ kubectl create -f mysql-deploy.yaml
deployment.apps/mysql created
$ kubectl get po
NAME READY STATUS RESTARTS AGE
mysql-78495ddfff-2h6l9 1/1 Running 0 96sMySQL 启动后,会在数据目录初始化基础数据,此时可以在后端存储中看到
$ ls /data/nfs/pvc-01602665-4968-4a4d-b8e9-e3eb627f7f34/
auto.cnf ca.pem ib_buffer_pool '#innodb_temp' public_key.pem undo_002
binlog.000001 client-cert.pem ibdata1 mysql server-cert.pem
binlog.000002 client-key.pem ib_logfile0 mysql.ibd server-key.pem
binlog.index '#ib_16384_0.dblwr' ib_logfile1 performance_schema sys
ca-key.pem '#ib_16384_1.dblwr' ibtmp1 private_key.pem undo_001创建数据测试
$ kubectl exec -ti mysql-78495ddfff-2h6l9 -- bash
$ $ mysql -uroot -p
Enter password: 输入密码
mysql> CREATE DATABASE monap;
Query OK, 1 row affected (0.00 sec)删除 Pod 后,数据不会丢失
$ kubectl delete po mysql-78495ddfff-2h6l9
pod "mysql-78495ddfff-2h6l9" deleted
$ kubectl exec -ti mysql-78495ddfff-vh7nj -- bash
root@mysql-78495ddfff-vh7nj:/# mysql -uroot -p
Enter password:
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| monap |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+StatefulSet 配置动态存储
使用 StatefulSet 部署有状态服务时,可以使用 volumeClaimTemplates 自动为每个 Pod 生成 PVC,并挂载至容器中,大大降低了手动创建管理存储的难度和复杂度。
假设需要搭建一个三节点的 RabbitMQ 集群到 K8s 中,并且需要实现数据的持久化,此时可以通过 StatefulSet 创建三个副本,并且通过 volumeClaimTemplates 绑定存储。
首先下载部署文件:
$ git clone https://gitee.com/dukuan/k8s.git
$ cd k8s/k8s-rabbitmq-cluster/更改存储配置
# vim rabbitmq-cluster-ss.yaml
volumeMounts:
- mountPath: /etc/rabbitmq
name: config-volume
readOnly: false
- mountPath: /var/lib/rabbitmq
name: rabbitmq-storage
readOnly: false
# 可以发现volumeClaimTemplates下的结构和pvc的结构基本一致
volumeClaimTemplates:
- metadata:
name: rabbitmq-storage
spec:
accessModes:
- ReadWriteOnce
storageClassName: "nfs-csi"
resources:
requests:
storage: 4Gi创建资源
$ kubectl create ns public-service
$ kubectl create -f .查看状态
# 查看启动状态
kubectl get po -n public-service
# 查看创建的pvc
kubectl get pvc -n public-service
# 查看创建的service
kubectl get svc -n public-service
# 通过 15672 端口的 NodePort 即可访问 RabbitMQ 的管理页面