Kubernetes + GlusterFS + Heketi 动态卷管理实践 !
Kubernetes动态存储供给是云原生架构的关键挑战。
本文详解如何通过Heketi实现GlusterFS自动化管理,涵盖部署实践与问题处理,提供经生产验证的配置方案,助力构建高可用、弹性扩展的Kubernetes存储体系。
1. 安装要求
在开始之前,搭建GlusterFS集群需要满足以下几个条件:
-
完成 kubernetes 集群搭建
-
支持外网访问,并配置相关容器镜像加速地址
-
每台宿主机预留有裸磁盘
-
每台宿主机支持并加载相关模块
2. 学习目标
-
完成 GlusterFS 集群部署搭建
-
完成创建 Heketi 服务部署
-
通过Heketi 管理 GlusterFS集群
-
SC ,PV ,PVC 创建验证
3. 准备工作
1、在各个节点都安装上GFS客户端
yum install glusterfs glusterfs-fuse -y2、给需要安装GFS管理服务的节点打上标签
kubectl label nodes k8s-master01 storagenode=glusterfs
kubectl label nodes k8s-node02 storagenode=glusterfs
kubectl label nodes k8s-node03 storagenode=glusterfs3、所有节点加载对应模块
modprobe dm_snapshot
modprobe dm_mirror
modprobe dm_thin_pool4、检查 modprobe 是否加载成功
lsmod | egrep '(dm_snapshot|dm_mirror|dm_thin_pool)'[root@k8s-node03 ~]# lsmod | egrep '(dm_snapshot|dm_mirror|dm_thin_pool)'
dm_thin_pool 70389 0
dm_persistent_data 75275 1 dm_thin_pool
dm_bio_prison 18209 1 dm_thin_pool
dm_mirror 22289 0
dm_region_hash 20813 1 dm_mirror
dm_log 18411 2 dm_region_hash,dm_mirror
dm_mod 124501 4 dm_log,dm_mirror,dm_bufio,dm_thin_pool
4. 创建GlusterFS管理服务容器集群
4.1 部署GlusterFS 集群:
yaml 文件如下:
vim glusterfs-daemonset.yamlapiVersion: apps/v1
kind: DaemonSet
metadata:name: glusterfslabels:glusterfs: daemonsettannotations:description: GlusterFS DaemonSettags: glusterfs
spec:selector:matchLabels:glusterfs-node: podtemplate:metadata:name: glusterfslabels:glusterfs-node: podspec:nodeSelector:storagenode: glusterfs # 节点标签glusterfshostNetwork: truecontainers:- image: gluster/gluster-centos:latestname: glusterfsvolumeMounts:- name: glusterfs-heketimountPath: "/var/lib/heketi"- name: glusterfs-runmountPath: "/run"- name: glusterfs-lvmmountPath: "/run/lvm"- name: glusterfs-etcmountPath: "/etc/glusterfs"- name: glusterfs-logsmountPath: "/var/log/glusterfs"- name: glusterfs-configmountPath: "/var/lib/glusterd"- name: glusterfs-devmountPath: "/dev"- name: glusterfs-miscmountPath: "/var/lib/misc/glusterfsd"- name: glusterfs-cgroupmountPath: "/sys/fs/cgroup"readOnly: true- name: glusterfs-sslmountPath: "/etc/ssl"readOnly: truesecurityContext:capabilities: {}privileged: true # 特权模式readinessProbe:timeoutSeconds: 3initialDelaySeconds: 60exec:command:- "/bin/bash"- "-c"- systemctl status glusterd.servicelivenessProbe:timeoutSeconds: 3initialDelaySeconds: 60exec:command:- "/bin/bash"- "-c"- systemctl status glusterd.servicevolumes:- name: glusterfs-heketihostPath:path: "/var/lib/heketi"- name: glusterfs-run- name: glusterfs-lvmhostPath:path: "/run/lvm"- name: glusterfs-etchostPath:path: "/etc/glusterfs"- name: glusterfs-logshostPath:path: "/var/log/glusterfs"- name: glusterfs-confighostPath:path: "/var/lib/glusterd"- name: glusterfs-devhostPath:path: "/dev"- name: glusterfs-mischostPath:path: "/var/lib/misc/glusterfsd"- name: glusterfs-cgrouphostPath:path: "/sys/fs/cgroup"- name: glusterfs-sslhostPath:path: "/etc/ssl"创建 glusterfs-deamonset
[root@k8s-master01 glusterfs-heketi]# kubectl apply -f glusterfs-daemonset.yaml
daemonset.apps/glusterfs created
4.2 验证部署结果
我们可以看到:Master 节点没有跑 glusterfs 服务 。这是因为 Kubernetes 默认会阻止 DaemonSet 在 master 节点上运行工作负载。
[root@k8s-master01 glusterfs-heketi]# kubectl get pod -l glusterfs-node=pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
glusterfs-cdtrk 1/1 Running 0 51s 192.168.234.132 k8s-node02 <none> <none>
glusterfs-kqcgs 1/1 Running 0 51s 192.168.234.133 k8s-node03 <none> <none>
查看 Master 节点污点。
[root@k8s-master01 glusterfs-heketi]# kubectl describe nodes k8s-master01 |grep Taint
Taints: node-role.kubernetes.io/control-plane:NoSchedule
如果想允许 DaemonSet 在 master 节点运行,执行如下命令 移除 master 节点的污点,或者在上述 glusterfs-daemonset.yaml 文件添加容忍(tolerations)也可,这里不做过多赘述。
kubectl taint nodes k8s-master01 node-role.kubernetes.io/control-plane:NoSchedule-
5.创建Heketi服务
5.1 创建一个ServiceAccount、Role、RoleBinding
vim heketi-rbac.yamlapiVersion: v1
kind: ServiceAccount
metadata:name: heketi-service-account
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:name: heketinamespace: default
rules:
- apiGroups: [""] # 空字符串,表示 Core API Groupresources: ["pods","services","endpoints"] # 这个Role只可以操作Pod\svc\ep,操作方式在下面的verbs[]verbs: ["get","watch","list"]
- apiGroups: [""] # 空字符串,表示 Core API Groupresources: ["pods/exec"]verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: heketi namespace: default # 权限仅在该ns下起作用
subjects:
- kind: ServiceAccount # 类型是sa,说明这个sa有role为heketi的权限name: heketi-service-account
roleRef: # 角色绑定信息kind: Role # 绑定的对象是角色,也可以是集群角色name: heketi # 绑定的Role nameapiGroup: rbac.authorization.k8s.io # 默认
[root@k8s-master01 glusterfs-heketi]# kubectl apply -f heketi-rbac.yaml
serviceaccount/heketi-service-account created
role.rbac.authorization.k8s.io/heketi created
rolebinding.rbac.authorization.k8s.io/heketi created
5.2 部署Heketi服务
vim heketi-deployment-svc.yamlapiVersion: apps/v1
kind: Deployment
metadata:name: deploy-heketilabels:glusterfs: heketi-deploymentdeploy-heketi: heket-deploymentannotations:description: Defines how to deploy Heketi
spec:selector:matchLabels:glusterfs: heketi-podreplicas: 1template:metadata:name: deploy-heketilabels:glusterfs: heketi-podname: deploy-heketispec:serviceAccountName: heketi-service-accountcontainers:- image: heketi/heketiimagePullPolicy: IfNotPresentname: deploy-heketienv:- name: HEKETI_EXECUTORvalue: kubernetes- name: HEKETI_FSTABvalue: "/var/lib/heketi/fstab"- name: HEKETI_SNAPSHOT_LIMITvalue: '14'- name: HEKETI_KUBE_GLUSTER_DAEMONSETvalue: "y"- name: HEKETI_ADMIN_KEY # 设置 Heketi服务密钥value: "admin@123" # 密钥值ports:- containerPort: 8080volumeMounts:- name: dbmountPath: "/var/lib/heketi"readinessProbe:timeoutSeconds: 3initialDelaySeconds: 3httpGet:path: "/hello"port: 8080livenessProbe:timeoutSeconds: 3initialDelaySeconds: 30httpGet:path: "/hello"port: 8080volumes:- name: dbhostPath:path: "/heketi-data"
---
kind: Service
apiVersion: v1
metadata:name: deploy-heketilabels:glusterfs: heketi-servicedeploy-heketi: supportannotations:description: Exposes Heketi Service
spec:selector:name: deploy-heketiports:- name: deploy-heketiport: 8080targetPort: 8080
【注意】Heketi 的 DB 数据需要持久化保存,建议使用hostPath 或其他共享存储进行保存:
[root@k8s-master01 glusterfs-heketi]# kubectl apply -f heketi-deployment-svc.yaml
deployment.apps/deploy-heketi created
service/deploy-heketi created
5.3 验证 pod 和 service
[root@k8s-master01 glusterfs-heketi]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deploy-heketi-59555bcd98-jd9mt 1/1 Running 0 85s[root@k8s-master01 glusterfs-heketi]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
deploy-heketi ClusterIP 10.1.206.52 <none> 8080/TCP 90s
6. 通过Heketi 创建GFS集群
在 Heketi 能够管理 GlusterFS 集群之前,首先要为其设置 GlusterFS 集群的信息。可以用一个 topology.json 配置文件来完成各个 GlusterFS 节点和设备的定义。Heketi 要求在一个 GlusterFS 集群中至少有 3 个节点。在 topology.json 配置文件 hostname 字段的 manage 上填写主机名,在 storage 上填写 IP 地址, devices 要求是未创建文件系统的裸设备(可以有多块盘)。topology.json 内容如下:
{"clusters": [{"nodes": [{"node": {"hostnames": {"manage": ["k8s-master01"],"storage": ["192.168.234.131"]},"zone": 1},"devices": ["/dev/sdb"]},{"node": {"hostnames": {"manage": ["k8s-node02"],"storage": ["192.168.234.132"]},"zone": 1},"devices": ["/dev/sdb"]},{"node": {"hostnames": {"manage": ["k8s-node03"],"storage": ["192.168.234.133"]},"zone": 1},"devices": ["/dev/sdb"]}]}]
}
进入Heketi 容器,使用命令行工具 heketi-cli 完成 GlusterFS 集群构建(http://10.1.206.52:8080 是 heketi 服务 ip 和 端口)
# export HEKETI_CLI_SERVER=http://10.1.206.52:8080
# heketi-cli -s $HEKETI_CLI_SERVER --user admin --secret admin@123 topology load --json=/root/topology.json
Creating cluster ... ID: 8cc1a0f8174e2fd04f517e01a1166ad0Allowing file volumes on cluster.Allowing block volumes on cluster.Creating node k8s-master01 ... ID: e0798f5083772ecd434492db152369f2Adding device /dev/sdb ... OKFound node k8s-node02 on cluster b3248f93d7e48e225ec22a19bfcf7896Adding device /dev/sdb ... OKFound node k8s-node03 on cluster b3248f93d7e48e225ec22a19bfcf7896Adding device /dev/sdb ... OK
经过上述操作,我们已经完成通过 Heketi 对 GlusterFS 集群进行创建,结果是在 GlusterFS 集群各个节点的 /dev/sdb 盘上成功创建了 PV 和 VG 。
执行如下命令(容器里运行),可查看 Heketi 的 topology 信息,包括 Node 和 Device 的详细信息,磁盘空间的剩余空间。
# heketi-cli -s $HEKETI_CLI_SERVER --user admin --secret admin@123 topology info
7. 测试验证
7.1 创建 StrongerClass
storageclass-glusterfs-heketi.yaml 配置文件如下:
vim storageclass-glusterfs-heketi.yaml apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: gluster-heketi
provisioner: kubernetes.io/glusterfs # GlusterFS 存储驱动,Kubernetes v1.13+ 版本以后开始被标记弃用,更高版本已经完全弃用
reclaimPolicy: Retain
parameters:resturl: "http://10.1.206.52:8080" # Heketi 服务地址restauthenabled: "true"restuser: "admin"restuserkey: "admin@123"gidMin: "40000"gidMax: "50000"volumetype: "replicate:3"
allowVolumeExpansion: true[root@k8s-master01 glusterfs-heketi]# kubectl apply -f storageclass-glusterfs-heketi.yaml
storageclass.storage.k8s.io/gluster-heketi created
7.2 创建 PVC
如下yaml 文件,申请了 1 GiB 空间的存储资源,设置 StorageClass 为 “gluster-heketi" ,同时未设置 Selector ,表示使用动态资源供应模式:
vim pvc-gluster-heketi.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc-gluster-heketi
spec:accessModes: - ReadWriteOncestorageClassName: gluster-heketi # StorageClass 名称resources:requests:storage: 5Gi[root@k8s-master01 glusterfs-heketi]# kubectl apply -f pvc-gluster-heketi.yaml
persistentvolumeclaim/pvc-gluster-heketi created
PVC 的定义一旦生成,系统便将触发 Heketi 进行相应的操作,主要为在 GulsterFS 集群中创建 brick ,再创建并启动一个 Volume。也会自动创建 PV ,查看 PVC 的详情,确认其状态为 Bound(已绑定)。
【问题】:创建 pvc 之后 ,若出现 pvc 状态为 Pending ,没有看到自动创建的 pv,describe 查看 pvc 的 pod 显示如下信息。
Events:Type Reason Age From Message---- ------ ---- ---- -------Warning ProvisioningFailed 3m29s (x441 over 113m) persistentvolume-controller no volume plugin matched name: kubernetes.io/glusterfs
这是因为 Kubernetes 自从1.13 版本开始,一些内置 Provisioner (in-tree) 已被标记为弃用,到更高版本可能已经完全弃用。上述报错说明,此 Kubernetes 版本的 GlusterFS 存储插件: kubernetes.io/glusterfs
已经完全不能使用 。在 Kubernetes 1.28 版本中,存储供应器(Provisioner)的生态已经全面转向 CSI(Container Storage Interface) 标准 。GlusterFS CSI 驱动:gluster.org/glusterfs
(需安装)。关于 GlusterFS CSI 驱动安装,这里就不做过多赘述,后续有时间再给大家更新。可以参考 GitHub 仓库地址:https://github.com/gluster/gluster-csi-driver
。
7.3 创建 Pod 使用 PVC 的存储资源
解决完 GlusterFS 存储插件问题之后,创建 pod 对 pvc 存储资源进行使用。
vim pod-use-pvc.yaml apiVersion: v1
kind: Pod
metadata:name: pod-use-pvc
spec:containers:- name: pod-use-pvcimage: busyboxcommand:- sleep- "3600"volumeMounts:- name: gluster-volumemountPath: "/pv-data"readOnly: falsevolumes:- name: gluster-volumepersistentVolumeClaim:claimName: pvc-gluster-heketi # pvc 名称
至此,使用 Kubernetes 动态存储供应模式,配合 StorageClass 和 Heketi 共同搭建基于 GlusterFS 的共享存储所有实验已经完成啦 ~