说明
Kubernetes中使用GlusterFS作为持久化存储,要提供storageClass使用需要依赖Heketi工具。Heketi是一个具有resetful接口的glusterfs管理程序,作为kubernetes的Storage存储的external provisioner。 “Heketi提供了一个RESTful管理界面,可用于管理GlusterFS卷的生命周期。借助Heketi,像OpenStack Manila,Kubernetes和OpenShift这样的云服务可以动态地配置GlusterFS卷和任何支持的持久性类型。Heketi将自动确定整个集群的brick位置,确保将brick及其副本放置在不同的故障域中。Heketi还支持任意数量的GlusterFS集群,允许云服务提供网络文件存储,而不受限于单个GlusterFS集群。
heketi:提供基于RESTful接口管理glusterfs的功能,可以方便的创建集群管理glusterfs的node,device,volume;与k8s结合可以创建动态的PV,扩展glusterfs存储的动态管理功能。主要用来管理glusterFS volume的生命周期,初始化时候就要分配好裸磁盘(未格式化)设备.
注意事项:
安装Glusterfs客户端:每个kubernetes集群的节点需要安装gulsterfs的客户端,如glusterfs-cli,glusterfs-fuse.主要用于在每个node节点挂载volume。
加载内核模块:每个kubernetes集群的节点运行modprobe dm_thin_pool,加载内核模块。
高可用(至少三个节点):至少需要节点用来部署glusterfs集群,并且这3个节点每个节点需要至少一个空余的磁盘。
基础设施要求:
正在运行的glusterfs集群,至少有三个node节点,每个节点至少有一个可用的裸块设备(如EBS卷或本地磁盘,就是没有格式化的).
用于运行GlusterFS节点必须为GlusterFS通信打开相应的端口(如果开启了防火墙的情况下,没开防火墙就不需要这些操作)。
安装GlusterFS
安装依赖及常用工具包:
查找gluster的最新软件仓库:
安装最新版本的gluster软件仓库:
安装gluster源,并安装glusterfs及相关软件包
客户端安装GlusterFS客户端软件
启动Glusterd服务
在任意一个节点上添加信任节点
查看节点状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Number of Peers: 3 Hostname: node110 Uuid: 5f13e231-25cf-475b-81ca-22122b1bfe55 State: Peer in Cluster (Connected) Other names: 10.14.151.110 Hostname: node99 Uuid: 7988f095-db67-47ee-913b-c232d1d4e954 State: Peer in Cluster (Connected) Hostname: node145 Uuid: 36e84b55-dab7-4551-9b44-490039d1bdf6 State: Peer in Cluster (Connected) Other names: 10.14.151.145 |
创建复制卷
创建分布式卷
创建分布式复制卷
启动卷
查看卷状态
客户端测试挂载卷
客户端测试卷数据存储
1 2 | ls /tmp/aaa 111 1.txt 2.txt anaconda-ks.cfg test-1 test-2 test-3 |
其他备用操作
停止卷:
删除卷:
将某个存储节点主机从信任池中删除:
安装Heketi
Heketi是由golang编写,直接静态编译运行二进制即可,也可以通过yum安装以及docker部署,主要会产生db文件存储cluster、node、device、volume等信息。
安装二进制包
创建ssh-key
我们glusterFS部署在k8s集群外,所以heketi通过ssh管理glusterFS。需要创建免秘钥登陆到所有glusterFS节点。
配置文件修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | { "_port_comment": "Heketi Server Port Number", "port": "18080", "_use_auth": "Enable JWT authorization. Please enable for deployment", "use_auth": true, "_jwt": "Private keys for access", "jwt": { "_admin": "Admin has access to all APIs", "admin": { "key": "adminkey" }, "_user": "User only has access to /volumes endpoint", "user": { "key": "userkey" } }, "_glusterfs_comment": "GlusterFS Configuration", "glusterfs": { "_executor_comment": [ "Execute plugin. Possible choices: mock, ssh", "mock: This setting is used for testing and development.", " It will not send commands to any node.", "ssh: This setting will notify Heketi to ssh to the nodes.", " It will need the values in sshexec to be configured.", "kubernetes: Communicate with GlusterFS containers over", " Kubernetes exec api." ], "executor": "ssh", "_sshexec_comment": "SSH username and private key file information", "sshexec": { "keyfile": "/opt/heketi/conf/heketi_key", "user": "root", "port": "2222", "fstab": "/etc/fstab" }, "_kubeexec_comment": "Kubernetes configuration", "kubeexec": { "host" :"https://kubernetes.host:8443", "cert" : "/path/to/crt.file", "insecure": false, "user": "kubernetes username", "password": "password for kubernetes user", "namespace": "OpenShift project or Kubernetes namespace", "fstab": "Optional: Specify fstab file on node. Default is /etc/fstab" }, "_db_comment": "Database file name", "db": "/opt/heketi/data/heketi.db", "_loglevel_comment": [ "Set log level. Choices are:", " none, critical, error, warning, info, debug", "Default is warning" ], "loglevel" : "debug" } } |
注意:
需要说明的是,heketi有三种executor,分别为mock、ssh、kubernetes,建议在测试环境使用mock,生产环境使用ssh,当glusterfs以容器的方式部署在kubernetes上时,才使用kubernetes。我们这里将glusterfs和heketi独立部署,使用ssh的方式。
使用docker部署的时候,还需将/var/lib/heketi/mounts 挂载至容器里面, heketi 会将此目录作为 gluster volume的挂载点。
systemd配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [Unit] Description=RESTful based volume management framework for GlusterFS Before=network-online.target After=network-online.target Documentation=https://github.com/heketi/heketi [Service] Type=simple LimitNOFILE=65536 ExecStart=/opt/heketi/bin/heketi --config=/opt/heketi/conf/heketi.json KillMode=process Restart=on-failure RestartSec=5 SuccessExitStatus=15 StandardOutput=syslog StandardError=syslog [Install] WantedBy=multi-user.target |
启动heketi服务
Heketi管理GlusterFS
添加cluster
1 | {"id":"bb1362c3360d80419c822b9994381608","nodes":[],"volumes":[],"block":true,"file":true,"blockvolumes":[]} |
将3个glusterfs节点作为node添加到cluster
添加节点
1 | {"zone":1,"hostnames":{"manage":["node108"],"storage":["10.14.151.108"]},"cluster":"bb1362c3360d80419c822b9994381608","id":"227fd34c519f0a2c9d5a5b7f3d048745","state":"online","devices":[]} |
1 | {"zone":1,"hostnames":{"manage":["node110"],"storage":["10.14.151.110"]},"cluster":"bb1362c3360d80419c822b9994381608","id":"5f2d7412f0c874634aa8ee18865533bf","state":"online","devices":[]} |
1 | {"zone":1,"hostnames":{"manage":["node145"],"storage":["10.14.151.145"]},"cluster":"bb1362c3360d80419c822b9994381608","id":"e20c47a9d9a31a300ed85ccc37441608","state":"online","devices":[]} |
查看节点:
1 2 3 | Id:227fd34c519f0a2c9d5a5b7f3d048745 Cluster:bb1362c3360d80419c822b9994381608 Id:5f2d7412f0c874634aa8ee18865533bf Cluster:bb1362c3360d80419c822b9994381608 Id:e20c47a9d9a31a300ed85ccc37441608 Cluster:bb1362c3360d80419c822b9994381608 |
添加device
机器只是作为gluster的运行单元,volume是基于device创建的。同时需要特别说明的是,目前heketi仅支持使用裸分区或裸磁盘(未格式化)添加为device,不支持文件系统。
注:--node参数给出的id是上一步创建node时生成的,实际配置中,要添加每一个节点的每一块用于存储的硬盘。
生产实际配置
以上ad-hoc命令均可通过配置文件创建然后导入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | { "clusters": [ { "nodes": [ { "node": { "hostnames": { "manage": [ "k8s1" ], "storage": [ "10.111.209.188" ] }, "zone": 1 }, "devices": [ "/dev/vdc1" ] }, { "node": { "hostnames": { "manage": [ "k8s2" ], "storage": [ "10.111.209.189" ] }, "zone": 1 }, "devices": [ "/dev/vdc1" ] }, { "node": { "hostnames": { "manage": [ "k8s3" ], "storage": [ "10.111.209.190" ] }, "zone": 1 }, "devices": [ "/dev/vdc1" ] } ] } ] } |
创建:
添加volume
这里仅仅是做一个测试,实际使用中,会由kubernetes自动创建pv.
创建一个大小为3G,副本为2的volume
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Name: vol_61055753aa935407b80e1137647733f6 Size: 3 Volume Id: 61055753aa935407b80e1137647733f6 Cluster Id: bb1362c3360d80419c822b9994381608 Mount: 10.14.151.108:vol_61055753aa935407b80e1137647733f6 Mount Options: backup-volfile-servers=10.14.151.110,10.14.151.145 Block: false Free Size: 0 Reserved Size: 0 Block Hosting Restriction: (none) Block Volumes: [] Durability Type: replicate Distribute Count: 1 Replica Count: 2 |
kubernetes storageclass 配置
创建storageclass
添加storageclass-glusterfs.yaml文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | apiVersion: v1 kind: Secret metadata: name: heketi-secret namespace: default data: # base64 encoded password. E.g.: echo -n "mypassword" | base64 key: YWRtaW5rZXk= type: kubernetes.io/glusterfs --- apiVersion: storage.k8s.io/v1beta1 kind: StorageClass metadata: name: glusterfs provisioner: kubernetes.io/glusterfs allowVolumeExpansion: true parameters: resturl: "http://10.14.143.111:18080" clusterid: "bb1362c3360d80419c822b9994381608" restauthenabled: "true" restuser: "admin" #secretNamespace: "default" #secretName: "heketi-secret" restuserkey: "adminkey" gidMin: "40000" gidMax: "50000" volumetype: "replicate:2" |
1 2 | secret/heketi-secret created storageclass.storage.k8s.io/glusterfs created |
1 2 3 | NAME PROVISIONER AGE csi-cephfs cephfs.csi.ceph.com 260d glusterfs kubernetes.io/glusterfs 1m |
注意:
storageclass.beta.kubernetes.io/is-default-class: "true" #表示此storageClass作为default sc,创建pvc不指定sc时,默认使用此sc.
reclaimPolicy: Retain #表示pv回收策略为保留,删除pvc时将不删除pv。
更详细的用法参考:https://kubernetes.io/docs/concepts/storage/storage-classes/#glusterfs
创建pvc
1 2 3 4 5 6 7 8 9 10 11 12 13 | kind: PersistentVolumeClaim apiVersion: v1 metadata: name: glusterfs-mysql1 namespace: default annotations: volume.beta.kubernetes.io/storage-class: "glusterfs" spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi |
1 | persistentvolumeclaim/glusterfs-mysql1 created |
1 2 | NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE 1y pvc-5ae5026d-91d2-11ea-bd25-fa157e638e00 1Gi RWX Delete Bound default/glusterfs-mysql1 glusterfs 5m |
1 2 | NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE glusterfs-mysql1 Bound pvc-5ae5026d-91d2-11ea-bd25-fa157e638e00 1Gi RWX glusterfs 4m |
创建pod,使用pvc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | --- kind: Deployment apiVersion: extensions/v1beta1 metadata: name: mysql namespace: default spec: replicas: 1 template: metadata: labels: name: mysql spec: containers: - name: mysql image: mysql:5.7 imagePullPolicy: IfNotPresent env: - name: MYSQL_ROOT_PASSWORD value: root123456 ports: - containerPort: 3306 volumeMounts: - name: gluster-mysql-data mountPath: "/var/lib/mysql" volumes: - name: gluster-mysql-data persistentVolumeClaim: claimName: glusterfs-mysql1 |
1 | deployment.extensions/mysql created |
1 2 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE mysql 1 1 1 1 4m |
1 2 | NAME READY STATUS RESTARTS AGE mysql-b75b5dcfb-cb7qm 1/1 Running 0 5m |
1 2 3 4 5 6 7 8 9 10 | Filesystem Type Size Used Avail Use% Mounted on overlay overlay 120G 22G 99G 18% / tmpfs tmpfs 64M 0 64M 0% /dev tmpfs tmpfs 16G 0 16G 0% /sys/fs/cgroup /dev/mapper/centos-root xfs 120G 22G 99G 18% /etc/hosts shm tmpfs 64M 0 64M 0% /dev/shm 10.14.151.108:vol_00de560fab819d81ade9aae98fcdd4d1 fuse.glusterfs 1016M 254M 763M 25% /var/lib/mysql tmpfs tmpfs 16G 12K 16G 1% /run/secrets/kubernetes.io/serviceaccount tmpfs tmpfs 16G 0 16G 0% /proc/scsi tmpfs tmpfs 16G 0 16G 0% /sys/firmware |
创建statefulset
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | - apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: nginx spec: selector: matchLabels: app: nginx # has to match .spec.template.metadata.labels serviceName: "nginx" replicas: 3 # by default is 1 template: metadata: labels: app: nginx # has to match .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: nginx ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "glusterfs" resources: requests: storage: 1Gi |
1 2 | service/nginx created statefulset.apps/nginx created |
1 2 3 4 5 6 7 8 9 10 11 12 | NAME READY STATUS RESTARTS AGE pod/nginx-0 1/1 Running 0 116s pod/nginx-1 1/1 Running 0 98s pod/nginx-2 1/1 Running 0 91s NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/pvc-5ac3eba9-fe12-11e8-a19e-00163e14b18f 1Gi RWO Retain Bound default/www-nginx-0 glusterfs 99s persistentvolume/pvc-65f27519-fe12-11e8-a19e-00163e14b18f 1Gi RWO Retain Bound default/www-nginx-1 glusterfs 93s persistentvolume/pvc-69b31512-fe12-11e8-a19e-00163e14b18f 1Gi RWO Retain Bound default/www-nginx-2 glusterfs 86s NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/www-nginx-0 Bound pvc-5ac3eba9-fe12-11e8-a19e-00163e14b18f 1Gi RWO glusterfs 116s persistentvolumeclaim/www-nginx-1 Bound pvc-65f27519-fe12-11e8-a19e-00163e14b18f 1Gi RWO glusterfs 98s persistentvolumeclaim/www-nginx-2 Bound pvc-69b31512-fe12-11e8-a19e-00163e14b18f 1Gi RWO glusterfs 91s |
我们可以看到RECLAIM POLICY: Retain ,经过测试
删除pvc,pv status会变成Released状态,且不会被删除
删除pv, 通过heketi-cli volume list查看,volume不会被删除
kubernetes pv和gluster volume不一致时,可使用heketi来统一管理volume.此文档heketi和glusterfs都在kubernetes集群外部署。对于支持AWS EBS的磁盘,可通过EBS storageClass方式将glusterFS heketi部署在容器中管理.参考https://github.com/gluster/gluster-kubernetes
参考文档
https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
https://kubernetes.io/docs/concepts/storage/storage-classes/#glusterfs
https://github.com/heketi/heketi/blob/master/docs/admin/readme.md
https://www.cnblogs.com/breezey/p/8849466.html
https://www.cnblogs.com/breezey/p/8849466.html)
验证测试:

图片17.png
进容器看挂载的是10.14.151.108的volume,

图片18.png
关闭10.14.151.108的gluster服务,模拟故障

图片19.png
进容器后写数据:

图片20.png

图片21.png
说明挂掉一个节点是不影响用户使用的。