在 Kubernetes 中使用 GlusterFS 构建可扩展的分布式持久化存储【免费下载链接】kubernetes-handbookKubernetes 架构与生态从云原生到 AI 原生基础设施的构建指南项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbookGlusterFS 是 Scale-Out 存储解决方案 Gluster 的核心组件一个开源的分布式文件系统凭借强大的横向扩展能力可支撑 PB 级存储容量与数千客户端并发访问。本文以该概念为主线结合 kubernetes-handbook 仓库中完整的安装部署、卷配置、Kubernetes 集成Endpoints / Service / PV / PVC / Heketi 动态供给实践与清单文件为你梳理一条从裸机搭建 GlusterFS 集群到在 Kubernetes 中落地持久化存储的完整技术路径。读完本文你将掌握 GlusterFS 各类卷模式的选型、命令行配置与调优方法以及通过静态 PV 和 StorageClass 动态供给两种方式为工作负载挂载分布式存储的实战方案。GlusterFS 核心概念与设计要点GlusterFS 借助 TCP/IP 或 InfiniBand RDMA 网络将物理上分散分布的存储资源聚集在一起并使用单一全局命名空间统一管理数据。它具有以下设计特点横向扩展Scale-Out通过向存储池中添加节点即可线性扩展容量与性能能够支持数 PB 存储容量和处理数千客户端。可堆叠的用户空间设计GlusterFS 基于可堆叠的用户空间架构翻译器Translator以堆叠方式组合可为不同的数据负载提供优异的性能也便于针对特定场景裁剪功能。全局统一命名空间客户端挂载后看到的是一棵统一的目录树物理节点位置对使用者透明。多网络支持既可使用普通的 TCP/IP 网络也可使用 InfiniBand RDMA 高速网络以适应不同性能诉求。与 GlusterFS 配套的GlusterD是 Gluster 的分布式管理引擎详见仓库中的 glusterd-2.0.md。GlusterD-2.0 是针对大规模部署的架构重写它提供一组用于卷和成员操作的 ReSTful 界面便于将 DevOps 实践用于基础架构自动化集成了嵌入式 etcd 库为可信任存储池中的状态管理提供更高的一致性并提供更灵活的插件框架方便开发人员添加更多指标。在 Kubernetes 集成方面借助动态配置工具Heketi管理 GlusterFS 卷的生命周期Heketi 的最新版本支持配置基于 Gluster 块的持久卷、扩展持久卷、为持久卷自定义卷名称、Gluster 卷的 Prometheus 指标集以及更强的设备管理能力。GlusterFS 卷模式从分布到多模式组合GlusterFS 中 volume 的模式多种多样仓库实践文档 using-glusterfs-for-persistent-storage.md 给出了完整的模式清单模式创建参数说明最少节点数分布卷DHT默认模式不加额外参数将文件以 hash 算法随机分布到一台服务器节点中存储1复制模式AFRreplica x将文件复制到replica x个节点中2条带模式Stripedstripe x将文件切割成数据块分别存储到stripe x个节点中类似 RAID 02分布式条带模式stripe 2 serverDHT 与 Striped 的组合型4分布式复制模式replica 2 serverDHT 与 AFR 的组合型4条带复制卷模式stripe 2 replica 2Striped 与 AFR 的组合型4三种模式混合stripe 2 replica 2每 4 个节点一组综合组合8注意分布卷虽然是最易上手的默认模式但文件只会哈希分布到某一个节点上节点故障即造成数据丢失。原文档明确警告——请勿在生产环境上使用该模式。生产环境至少应使用复制模式如replica 2/replica 3或分布式复制模式来保证数据冗余。裸机部署在三台主机上搭建 GlusterFS 集群以下是仓库实践文档中基于 CentOS 的完整部署流程复用 Kubernetes 的三台主机搭建存储1. 安装 GlusterFS# 先安装 gluster 源 $ yum install centos-release-gluster -y # 安装 glusterfs 组件 $ yum install -y glusterfs glusterfs-server glusterfs-fuse glusterfs-rdma glusterfs-geo-replication glusterfs-devel # 创建 glusterfs 目录 $ mkdir /opt/glusterd # 修改 glusterd 数据目录将默认 /var/lib 替换为 /opt $ sed -i s/var\/lib/opt/g /etc/glusterfs/glusterd.vol # 启动 glusterfs 并设置开机自启 $ systemctl start glusterd.service $ systemctl enable glusterd.service # 查看状态 $ systemctl status glusterd.service2. 配置集群成员与端口# 配置 hosts三台主机相互解析 $ vi /etc/hosts 172.20.0.113 test-001.jimmysong.io 172.20.0.114 test-002.jimmysong.io 172.20.0.115 test-003.jimmysong.io # 开放 glusterd 管理端口默认 24007 $ iptables -I INPUT -p tcp --dport 24007 -j ACCEPT # 创建存储目录作为 brick 目录 $ mkdir /opt/gfs_data3. 组建可信任存储池# 在 test-001 上执行执行操作的本机不需要 probe 本机 $ gluster peer probe test-002.jimmysong.io $ gluster peer probe test-003.jimmysong.io # 查看集群状态 $ gluster peer status Number of Peers: 2 Hostname: test-002.jimmysong.io Uuid: f25546cc-2011-457d-ba24-342554b51317 State: Peer in Cluster (Connected) Hostname: test-003.jimmysong.io Uuid: 42b6cad1-aa01-46d0-bbba-f7ec6821d66d State: Peer in Cluster (Connected)4. 创建并启动卷由于示例环境只有三台主机实践文档使用默认的分布卷模式仅为演示生产环境务必使用复制模式# 创建分布卷 $ gluster volume create k8s-volume transport tcp \ test-001.jimmysong.io:/opt/gfs_data \ test-002.jimmysong.io:/opt/gfs_data \ test-003.jimmysong.io:/opt/gfs_data force # 查看 volume 状态 $ gluster volume info Volume Name: k8s-volume Type: Distribute Volume ID: 9a3b0710-4565-4eb7-abae-1d5c8ed625ac Status: Created Snapshot Count: 0 Number of Bricks: 3 Transport-type: tcp Bricks: Brick1: test-001.jimmysong.io:/opt/gfs_data Brick2: test-002.jimmysong.io:/opt/gfs_data Brick3: test-003.jimmysong.io:/opt/gfs_data Options Reconfigured: transport.address-family: inet nfs.disable: on # 启动分布卷 $ gluster volume start k8s-volume命令中各参数含义transport tcp指定传输协议每个节点:/brick目录定义一块 brick末尾的force用于在 brick 目录位于根分区等场景下强制执行创建。GlusterFS 卷调优卷启动后可通过gluster volume set volname option value按需调整性能与容量参数仓库实践文档给出了如下关键调优项# 开启指定 volume 的配额 $ gluster volume quota k8s-volume enable # 限制指定 volume 的配额为 1TB $ gluster volume quota k8s-volume limit-usage / 1TB # 设置 cache 大小默认 32MB $ gluster volume set k8s-volume performance.cache-size 4GB # 设置 IO 线程数注意太大会导致进程崩溃 $ gluster volume set k8s-volume performance.io-thread-count 16 # 设置网络检测时间默认 42s $ gluster volume set k8s-volume network.ping-timeout 10 # 设置写缓冲区大小默认 1M $ gluster volume set k8s-volume performance.write-behind-window-size 1024MBKubernetes 集成从 Endpoints 到 PV/PVC以下用到的所有 YAML 和 JSON 配置文件均可在仓库的 manifests/glusterfs 目录中找到注意替换其中私有镜像地址为你自己的镜像地址。1. 安装 Kubernetes 节点客户端# 在所有 k8s node 中安装 glusterfs 客户端 $ yum install -y glusterfs glusterfs-fuse # 配置 hosts与存储集群主机名解析保持一致 $ vi /etc/hosts 172.20.0.113 test-001.jimmysong.io 172.20.0.114 test-002.jimmysong.io 172.20.0.115 test-003.jimmysong.io本例中 GlusterFS 与 Kubernetes 集群复用主机因此该步骤可省略若两者分离此步骤必不可少——kubelet 挂载 GlusterFS 卷时依赖本地的 FUSE 客户端glusterfs-fuse。2. 配置 EndpointsKubernetes 中的 GlusterFS 卷通过Endpoints 对象定位存储集群节点而不是直接写死 IP。仓库中的 glusterfs-endpoints.json 内容如下{ kind: Endpoints, apiVersion: v1, metadata: { name: glusterfs-cluster }, subsets: [ { addresses: [ { ip: 172.20.0.113 } ], ports: [ { port: 1990 } ] } ] }导入并查看$ kubectl apply -f glusterfs-endpoints.json $ kubectl get ep说明每一个addresses为一个 IP 组可加入存储集群的全部节点 IP便于 kubelet 从中任选一个进行挂载port为 gluster 服务端口官方示例默认 1实践中改成了 1990需与 Service 中的端口保持一致。3. 配置 ServiceService 的作用是让 Endpoints 的端口能被集群内解析到仓库中的 glusterfs-service.json 内容如下——它查找的是 Endpoints 的名称与端口{ kind: Service, apiVersion: v1, metadata: { name: glusterfs-cluster }, spec: { ports: [ {port: 1990} ] } }$ kubectl apply -f glusterfs-service.json $ kubectl get svc4. 创建测试 Pod 验证挂载仓库中的 glusterfs-pod.json 以glusterfs卷类型直接引用上面创建的 Endpoints 与卷路径{ apiVersion: v1, kind: Pod, metadata: { name: glusterfs }, spec: { containers: [ { name: glusterfs, image: harbor-001.jimmysong.io/library/pause-amd64:3.0, volumeMounts: [ { mountPath: /mnt/glusterfs, name: glusterfsvol } ] } ], volumes: [ { name: glusterfsvol, glusterfs: { endpoints: glusterfs-cluster, path: k8s-volume, readOnly: true } } ] } }# 导入测试 Pod注意修改 volumes 下 path 为上面创建的卷名称 $ kubectl apply -f glusterfs-pod.json # 查看 pods 状态与所在 node $ kubectl get pods NAME READY STATUS RESTARTS AGE glusterfs 1/1 Running 0 1m $ kubectl describe pods/glusterfs # 在 node 物理机上使用 df 查看挂载目录 $ df -h 172.20.0.113:k8s-volume 1.0T 0 1.0T 0% /var/lib/kubelet/pods/3de9fc69-30b7-11e7-bfbd-8af1e3a7c5bd/volumes/kubernetes.io~glusterfs/glusterfsvol可以看到 kubelet 已通过172.20.0.113:k8s-volume挂载了 GlusterFS 卷这说明 Endpoints → Service → kubelet FUSE 挂载的链路完全打通。5. 配置 PersistentVolumePVPersistentVolumePV与 PersistentVolumeClaimPVC是 Kubernetes 提供的两种 API 资源用于抽象存储细节管理员关注如何通过 PV 提供存储无需关心用户如何使用用户只需把 PVC 挂载进容器无需关心底层存储卷的技术实现。PVC 和 PV 的关系类似 Pod 和 Node——前者消耗后者的资源。PV 的关键属性storage 容量卷的总容量。读写属性accessModesReadWriteOnce单个节点读写、ReadOnlyMany多节点只读、ReadWriteMany多节点读写。仓库中的 glusterfs-pv.yaml 内容如下apiVersion: v1 kind: PersistentVolume metadata: name: gluster-dev-volume spec: capacity: storage: 8Gi accessModes: - ReadWriteMany glusterfs: endpoints: glusterfs-cluster path: k8s-volume readOnly: false# 导入 PV $ kubectl apply -f glusterfs-pv.yaml # 查看 pv $ kubectl get pv NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE gluster-dev-volume 8Gi RWX Retain Available 3sPV 的glusterfs字段中endpoints指向第 2 步创建的 Endpoints 对象名path指向 GlusterFS 卷名readOnly: false表示可写。6. 配置 PersistentVolumeClaimPVCPVC 的属性访问模式与 PV 相同容量需满足申请容量 PV 总容量。仓库中的 glusterfs-pvc.yaml 内容如下kind: PersistentVolumeClaim apiVersion: v1 metadata: name: glusterfs-nginx spec: accessModes: - ReadWriteMany resources: requests: storage: 8Gi# 导入 pvc $ kubectl apply -f glusterfs-pvc.yaml # 查看绑定结果 $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE glusterfs-nginx Bound gluster-dev-volume 8Gi RWX 4sPVC 成功Bound到 PVgluster-dev-volume容量 8Gi、访问模式 RWX多节点读写与 PV 完全匹配。7. 创建 Deployment 挂载卷并验证读写仓库中的 nginx-deployment.yaml 展示了一个 2 副本 nginx Deployment 通过 PVC 挂载 GlusterFS 卷的完整示例apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-dm spec: replicas: 2 template: metadata: labels: name: nginx spec: containers: - name: nginx image: harbor-001.jimmysong.io/library/nginx:1.9 imagePullPolicy: IfNotPresent ports: - containerPort: 80 volumeMounts: - name: gluster-dev-volume mountPath: /usr/share/nginx/html volumes: - name: gluster-dev-volume persistentVolumeClaim: claimName: glusterfs-nginx# 导入 deployment $ kubectl apply -f nginx-deployment.yaml # 查看 deployment 对应的 pod $ kubectl get pods | grep nginx-dm nginx-dm-3698525684-g0mvt 1/1 Running 0 6s nginx-dm-3698525684-hbzq1 1/1 Running 0 6s # 进入容器查看挂载 $ kubectl exec -it nginx-dm-3698525684-g0mvt -- df -h | grep k8s-volume 172.20.0.113:k8s-volume 1.0T 0 1.0T 0% /usr/share/nginx/html # 写入文件测试 $ kubectl exec -it nginx-dm-3698525684-g0mvt -- touch /usr/share/nginx/html/index.html $ kubectl exec -it nginx-dm-3698525684-g0mvt -- ls -lt /usr/share/nginx/html/index.html -rw-r--r-- 1 root root 0 May 4 11:36 /usr/share/nginx/html/index.html # 验证文件落到 glusterfs 物理节点上 # 因为本例使用分布卷文件按 hash 随机落到某个节点故只能看到某一台节点上有文件 [roottest-001 ~] ls /opt/gfs_data/ [roottest-002 ~] ls /opt/gfs_data/ index.html [roottest-003 ~] ls /opt/gfs_data/以上验证清晰展示了“容器内写入 → FUSE 挂载 → 数据落到物理 brick”的完整闭环也再次印证了分布卷“文件只存在一个节点”的行为特征——这正是生产环境应避免使用它的原因。进阶用 Heketi 实现 GlusterFS 动态供给StorageClass上述方式属于静态供给管理员预先创建 PVPVC 再与之绑定。若要实现按需动态创建卷则需引入 Heketi。仓库文档 using-heketi-gluster-for-persistent-storage.md 完整翻译了 Heketi 官方指南并给出了实战示例。Heketi 是一个具有 RESTful 接口的 GlusterFS 管理程序作为 Kubernetes 存储的external provisioner它自动确定整个集群的 brick 位置确保 brick 及其副本放置在不同的故障域中支持任意数量的 GlusterFS 集群。部署前提与注意事项客户端每个 Kubernetes 节点需安装 glusterfs 客户端如 Ubuntu 执行apt-get install glusterfs-client。内核模块每个节点执行modprobe dm_thin_pool加载内核模块。节点规模至少 3 个 slave 节点且每个节点至少有一块空闲磁盘。防火墙端口如开启防火墙放行24007、24008、2222以及49152:49251端口段。部署要点部署 GlusterFS DaemonSetglusterfs-daemonset.json并给目标节点打标签使其在指定节点运行$ kubectl create -f glusterfs-daemonset.json $ kubectl label node node storagenodeglusterfs创建 Heketi 的 ServiceAccount 与 ClusterRoleBinding使其具备管理 GlusterFS Pod 的权限$ kubectl create -f heketi-service-account.json $ kubectl create clusterrolebinding heketi-gluster-admin \ --clusterroleedit --serviceaccountdefault:heketi-service-account创建保存 Heketi 配置的 Secret配置文件的执行程序须设置为kubernetes再部署 bootstrap Pod 与服务通过kubectl port-forward暴露 8080 端口用curl http://localhost:8080/hello验证并设置环境变量$ kubectl create secret generic heketi-config-secret --from-file./heketi.json $ kubectl create -f heketi-bootstrap.json $ kubectl port-forward deploy-heketi-pod 8080:8080 $ export HEKETI_CLI_SERVERhttp://localhost:8080通过拓扑文件向 Heketi 提供集群信息节点主机名、存储 IP、块设备并加载$ heketi-client/bin/heketi-cli topology load --jsontopology-sample.json拓扑文件示例3 节点每节点 2 块磁盘/dev/sdb、/dev/sdc{ clusters: [ { nodes: [ { node: { hostnames: { manage: [ubuntu-1], storage: [192.168.5.191] }, zone: 1 }, devices: [/dev/sdb, /dev/sdc] } ] } ] }注意hostnames/manage必须与kubectl get nodes得到的主机名完全一致hostnames/storage是存储网络的 IP且必须使用与 Heketi 服务器版本匹配的 heketi-cli 加载拓扑否则可能出现“无空间”类错误。为 Heketi 自身的数据库创建存储卷setup-openshift-heketi-storage生成heketi-storage.json然后删除 bootstrap 实例创建长期使用的 Heketi Deployment使 heketi 数据库持久化在 GlusterFS 卷上Pod 重启不丢数据。StorageClass 与 PVC 动态供给示例apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: slow # StorageClass 的名字 provisioner: kubernetes.io/glusterfs parameters: resturl: http://10.103.98.75:8080 # heketi service 的 cluster ip 和端口 restuser: admin # 未启用鉴权时可随便填写 gidMin: 40000 gidMax: 50000 volumetype: replicate:3 # 默认申请 3 副本模式kind: PersistentVolumeClaim apiVersion: v1 metadata: name: myclaim annotations: volume.beta.kubernetes.io/storage-class: slow # 需与 StorageClass 名字一致 spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi提交后可见 PVC 自动Bound到由 Heketi 动态创建的 PV回收策略为Delete$ kubectl get pvc | grep myclaim myclaim Bound pvc-e98e9117-3ed7-11e8-b61d-08002795cb26 1Gi RWO slow 28s $ kubectl get pv | grep myclaim pvc-e98e9117-3ed7-11e8-b61d-08002795cb26 1Gi RWO Delete Bound default/myclaim slow 1m还可以将slow设置为默认 StorageClass使平台分配存储时自动从 GlusterFS 集群分配 PV$ kubectl patch storageclass slow -p {metadata: {annotations:{storageclass.kubernetes.io/is-default-class:true}}} $ kubectl get sc NAME PROVISIONER AGE default fuseim.pri/ifs 1d slow (default) kubernetes.io/glusterfs 6h容量限额验证文档中以 Helm 部署的 mysql2 实例2Gi PVC做了容量限额测试写入dd if/dev/zero oftest.img bs8M count300后文件写至约 1.88GB 时报Read-only file system/Input/output error文档指出该报错信息为 GlusterFS 与 Docker 配合时的显示 bug实际是空间已满df -h显示卷容量 2.0G 且 Used 100%、du -h确认目录总大小 2.0G验证了 Heketi GlusterFS 的容量限额真实生效。需要说明该文档明确指出Heketi GlusterFS 与 Kubernetes 的这套集成方案仅适合测试验证环境并不适合生产环境。相关仓库资源导航围绕 GlusterFS 与 Kubernetes 持久化存储可在本仓库继续深入阅读主概念文档practice/glusterfs.md裸机部署与静态供给全流程practice/using-glusterfs-for-persistent-storage.mdHeketi 动态供给StorageClass实战practice/using-heketi-gluster-for-persistent-storage.mdGluster 管理引擎架构practice/glusterd-2.0.md存储管理总览practice/storage.md全套清单文件manifests/glusterfsEndpoints / Service / 测试 Pod / PV / PVC / nginx Deployment其他持久化存储方案可作为选型对照practice/using-nfs-for-persistent-storage.md、practice/using-ceph-for-persistent-storage.md、practice/using-openebs-for-persistent-storage.mdGlusterFS 与 Kubernetes 的结合提供了“横向可扩展 全局统一命名空间 卷生命周期自动化”的存储能力小型实验环境可直接用静态 PV 快速接入需要动态按需供给时引入 Heketi 作为 external provisioner生产环境则务必基于复制卷模式规划故障域并根据负载特征调优 cache、IO 线程与写缓冲等参数方能获得稳定可靠的分布式持久化存储底座。【免费下载链接】kubernetes-handbookKubernetes 架构与生态从云原生到 AI 原生基础设施的构建指南项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
