目录
一、GlusterFS Volume
1. Glusterfs Volume介绍
2. Glusterfs Volume类型介绍
二、Heketi使用
1. 基本安装配置
2. 导入GlusterFS信息
3. 创建Volume及管理
4. Heheti基本原理
三、基于Kubernetes的GlusterFS存储卷
1. 创建StorageClass
2. 创建PVC
Gluster volume是由多个brick组成的,每个brick实际是服务器上的一个目录
如下,volume1这个卷是由k8s-node1上的/data/brick1目录和k8s-node2上的/data/brick1组成的,往这个卷上写数据实际上就是往对应的brick目录中写数据
一个volume中的brick可以是多个服务器下的目录,也可以是一个服务器下的多个目录
如下volumetest卷就是k8s-node1服务器上的两个目录组成
Distributed:分布式卷
文件通过 hash 算法随机分布到由 bricks 组成的卷上。GlusterFS默认创建的都是分布式卷
// 创建卷 gluster volume create volume1 k8s-node1:/data/brick1 k8s-node2:/data/brick1 // 启动卷 gluster volume start volume1 // 查看卷 gluster volume info volume1卷创建完成后可以通过客户端进行使用(客户端需要安装glusterfs-fuse支持glusterfs文件系统,安装步骤略)
// 挂载glusterfs volume mount -t glusterfs 172.16.2.100:/volume1 /opt/testdata // 查看挂载目录 df -h | grep /opt/testdata 172.16.2.100:/volume1 3.6T 1.7T 1.9T 47% /opt/testdata可以往目录下创建几个文件
[root@k8s-node1 ~]# cd /opt/testdata/ [root@k8s-node1 testdata]# touch testfile{1..6} [root@k8s-node1 testdata]# ll total 0 -rw-r--r-- 1 root root 0 May 22 14:52 testfile1 -rw-r--r-- 1 root root 0 May 22 14:52 testfile2 -rw-r--r-- 1 root root 0 May 22 14:52 testfile3 -rw-r--r-- 1 root root 0 May 22 14:52 testfile4 -rw-r--r-- 1 root root 0 May 22 14:52 testfile5 -rw-r--r-- 1 root root 0 May 22 14:52 testfile6可以看到在/opt/testdata目录下创建了6个文件可以全部展示
前面说过往gluster volume中写数据实际上上往volume对应的brick中写数据,volume1对应的是k8s-node1上的/data/brick1目录和k8s-node2上的/data/brick1目录,分别查看
// k8s-node1节点 [root@k8s-node1 ~]# cd /data/brick1/ [root@k8s-node1 brick1]# ll total 0 -rw-r--r-- 2 root root 0 May 22 14:52 testfile5 // k8s-node2节点 [root@k8s-node2 ~]# cd /data/brick1/ [root@k8s-node2 brick1]# ll total 0 -rw-r--r-- 2 root root 0 May 22 14:52 testfile1 -rw-r--r-- 2 root root 0 May 22 14:52 testfile2 -rw-r--r-- 2 root root 0 May 22 14:52 testfile3 -rw-r--r-- 2 root root 0 May 22 14:52 testfile4 -rw-r--r-- 2 root root 0 May 22 14:52 testfile6可以看到6个文件分布在两个brick中(具体的分布算法略)
Replicated: 复制式卷
类似 RAID 1,replica 数必须等于 volume 中 brick 所包含的存储服务器数,可用性高。
(为了测试将之前创建的分布式的volume1删除)
// 解除挂载 [root@k8s-node1 ~]# umount /opt/testdata/ // 停止volume [root@k8s-node1 ~]# gluster volume stop volume1 Stopping volume will make its data inaccessible. Do you want to continue? (y/n) y volume stop: volume1: success // 删除volume [root@k8s-node1 ~]# gluster volume delete volume1 Deleting volume will erase all information about the volume. Do you want to continue? (y/n) y volume delete: volume1: success创建复制卷
创建Replicated卷需要指定副本数(注意,副本数需要等于brick所在的服务器数量)
// 创建卷 gluster volume create volume2 replica 2 k8s-node1:/data/brick1 k8s-node2:/data/brick1 // 启动卷 gluster volume start volume2 // 查看卷 gluster volume info volume2挂载(略)
创建文件进行测试
// 创建6个文件 [root@k8s-node1 ~]# cd /opt/testdata [root@k8s-node1 testdata]# touch testfile{1..6} [root@k8s-node1 testdata]# ll total 0 -rw-r--r-- 1 root root 0 May 22 15:06 testfile1 -rw-r--r-- 1 root root 0 May 22 15:06 testfile2 -rw-r--r-- 1 root root 0 May 22 15:06 testfile3 -rw-r--r-- 1 root root 0 May 22 15:06 testfile4 -rw-r--r-- 1 root root 0 May 22 15:06 testfile5 -rw-r--r-- 1 root root 0 May 22 15:06 testfile6查看volume对应的brick目录下的文件
// k8s-node1节点 [root@k8s-node1 ~]# cd /data/brick1/ [root@k8s-node1 brick1]# ll total 0 -rw-r--r-- 2 root root 0 May 22 15:06 testfile1 -rw-r--r-- 2 root root 0 May 22 15:06 testfile2 -rw-r--r-- 2 root root 0 May 22 15:06 testfile3 -rw-r--r-- 2 root root 0 May 22 15:06 testfile4 -rw-r--r-- 2 root root 0 May 22 15:06 testfile5 -rw-r--r-- 2 root root 0 May 22 15:06 testfile6 // k8s-node2节点 [root@k8s-node2 ~]# cd /data/brick1/ [root@k8s-node2 brick1]# ll total 0 -rw-r--r-- 2 root root 0 May 22 15:10 testfile1 -rw-r--r-- 2 root root 0 May 22 15:10 testfile2 -rw-r--r-- 2 root root 0 May 22 15:10 testfile3 -rw-r--r-- 2 root root 0 May 22 15:10 testfile4 -rw-r--r-- 2 root root 0 May 22 15:10 testfile5 -rw-r--r-- 2 root root 0 May 22 15:10 testfile6可以看到对于Replicated类型的卷,在两个brick下有相同的文件(对文件进行复制)
Striped: 条带式卷
类似 RAID 0,stripe 数必须等于 volume 中 brick 所包含的存储服务器数,文件被分成数据块,以 Round Robin 的方式存储在 bricks 中,并发粒度是数据块,大文件性能好。
gluster volume create volume3 stripe 2 k8s-node1:/data/brick1 k8s-node2:/data/brick1 gluster volume start volume3 gluster volume info volume3挂载并创建文件进行测试
条带卷主要是将文件分割存储,所以本次创建几个实际大小的文件
// 创建10M的文件 [root@k8s-node1 testdata]# dd if=/dev/zero bs=1024 count=10000 of=10M.file 10000+0 records in 10000+0 records out 10240000 bytes (10 MB) copied, 0.651303 s, 15.7 MB/s // 创建20M的文件 [root@k8s-node1 testdata]# dd if=/dev/zero bs=1024 count=20000 of=20M.file 20000+0 records in 20000+0 records out 20480000 bytes (20 MB) copied, 1.29391 s, 15.8 MB/s // 查看文件大小 [root@k8s-node1 testdata]# du -sh * 9.8M 10M.file 20M 20M.file看看volume对应的brick
// k8s-node1节点 [root@k8s-node1 ~]# cd /data/brick1/ [root@k8s-node1 brick1]# ll total 15024 -rw-r--r-- 2 root root 5128192 May 22 15:20 10M.file -rw-r--r-- 2 root root 10256384 May 22 15:20 20M.file [root@k8s-node1 brick1]# du -sh * 4.9M 10M.file 9.8M 20M.file // k8s-node2节点 [root@k8s-node2 ~]# cd /data/brick1/ [root@k8s-node2 brick1]# ll total 14976 -rw-r--r-- 2 root root 5111808 May 22 15:20 10M.file -rw-r--r-- 2 root root 10223616 May 22 15:20 20M.file [root@k8s-node2 brick1]# du -sh * 4.9M 10M.file 9.8M 20M.file可以看到同一个文件分成了几部分分别存储在不同的brick目录下
(一个本质的区别是 分布式卷和复制卷的brick中存储的都是一个完整的文件,直接从brick中拷贝文件也可以直接使用,但是条带卷的brick中存储的只是文件的一部分,一个数据块,不能直接使用,往条带卷中写文件的效率是最高的,类似于raid0,一个文件写的时候是将文件分成几块,并发的往brick中写数据)
Distributed Striped: 分布式的条带卷
volume中 brick 所包含的存储服务器数必须是 stripe 的倍数(>=2倍),兼顾分布式和条带式的功能。
Distributed Replicated: 分布式的复制卷
volume 中 brick 所包含的存储服务器数必须是 replica 的倍数(>=2倍),兼顾分布式和复制式的功能。
Glusterfs Volume是由多个brick目录组成的,volume的大小和brick目录的大小相关
但是实际场景下不可能提前准备好相关的目录,也不可能等到创建的时候再去创建相关大小的目录
Heketi (https://github.com/heketi/heketi ),是一个基于 RESTful API 的 GlusterFS 卷管理框架,可以方便的管理volume
yum安装heketi(也可以容器化部署)
yum install heketi heketi-client -y配置Heketi
{ "_port_comment": "Heketi Server Port Number", "port": "8080", // 端口 "_use_auth": "Enable JWT authorization. Please enable for deployment", "use_auth": false, "_jwt": "Private keys for access", "jwt": { "_admin": "Admin has access to all APIs", "admin": { "key": "My Secret" }, "_user": "User only has access to /volumes endpoint", "user": { "key": "My Secret" } }, "_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", // 执行方式,使用SSH连接 "_sshexec_comment": "SSH username and private key file information", "sshexec": { // 密钥信息 "keyfile": "/root/.ssh/id_rsa", "user": "root", "port": "22", "_fstab_comment": "It's vary dangerous to use the default '/etc/fstab'!", "fstab": "/etc/heketi/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": "/etc/heketi/fstab" }, "_db_comment": "Database file name", "db": "/var/lib/heketi/heketi.db", "brick_max_size_gb" : 1024, "brick_min_size_gb" : 1, "max_bricks_per_volume" : 33, "_loglevel_comment": [ "Set log level. Choices are:", " none, critical, error, warning, info, debug", "Default is warning" ], "loglevel": "warning" } }Heketi通过ssh的方式连接到Glusterfs各个节点执行操作,heketi配置文件中需要指明私钥文件,并把对应的公钥文件上传到GlusterFS各台服务器的 /root/.ssh/ 下面,并重命命名为authorized_keys,/etc/heketi/heketi.json 中 的 keyfile 指向生成的私钥文件(包含路径),总之要确保heketi节点可以无密码访问glusterfs各节点。
启动Heketi
systemctl enable heketi systemctl start heketi基本RestAPI测试
[root@k8s-node1 ~]# curl http://127.0.0.1:8080/hello Hello from Heketi通过一个json文件可以定义GlusterFs节点的信息,包括节点以及节点的磁盘信息。示例文件如下:
{ "clusters": [ { "nodes": [ { "node": { "hostnames": { "manage": [ "192.168.1.100" ], "storage": [ "192.168.1.100" ] }, "zone": 1 }, "devices": [ "/dev/sdc" ] }, { "node": { "hostnames": { "manage": [ "192.168.2.100" ], "storage": [ "192.168.2.100" ] }, "zone": 1 }, "devices": [ "/dev/sdc" ] } ] } ] } // 导入topo信息 [root@k8s-node1 heketi]# export HEKETI_CLI_SERVER=http://127.0.0.1:8083 [root@k8s-node1 heketi]# heketi-cli topology load --json=topology.json // 查看topo信息 [root@k8s-node1 heketi]# heketi-cli topology info可以看到通过heketi创建volume不再需要指定brick目录,并且可以根据需要创建指定大小的卷
我们知道GlusterFs Volume的brick是一个directory,但我们在heketi导入glusterfs集群的topologyfile中申明的是磁盘,那heketi如何使用磁盘的呢
答案很简单,当用户通过heketi-cli创建volume时, heketi会把节点上的磁盘组成vg,然后volume的每个brick对应的其实是vg上的一个lvm。heketi会负责这个流程,并最终将lvm挂载到某个目录,这个目录就成为brick。具体示例,如下面所示
heketi首先会将磁盘信息组成一个vg
// k8s-node1节点 [root@k8s-node1 ~]# pvs PV VG Fmt Attr PSize PFree /dev/sdc vg_1e121d3f725764eb55cb15cc42aa8f99 lvm2 a-- <2.73t <2.59t [root@k8s-node1 ~]# vgs VG #PV #LV #SN Attr VSize VFree vg_1e121d3f725764eb55cb15cc42aa8f99 1 38 0 wz--n- <2.73t <2.59t // k8s-node2节点 [root@k8s-node2 ~]# pvs PV VG Fmt Attr PSize PFree /dev/sdc vg_e193b95ccea9ee90b09e837e80f5c3b9 lvm2 a-- <2.73t <2.59t [root@k8s-node2 ~]# vgs VG #PV #LV #SN Attr VSize VFree vg_e193b95ccea9ee90b09e837e80f5c3b9 1 38 0 wz--n- <2.73t <2.59t通过heketi创建volume并查看volume信息
[root@k8s-node1 ~]# heketi-cli volume create --name=volumeheketi --replica=2 --size=1 Name: volumeheketi Size: 1 Volume Id: c17457b22899059d4b09b5f56cf74e7b Cluster Id: 6b6e86c292608a56f4c4065832392a10 Mount: 172.16.2.200:volumeheketi Mount Options: backup-volfile-servers=172.16.2.100 Block: false Free Size: 0 Block Volumes: [] Durability Type: replicate Distributed+Replica: 2通过Gluster直接查看volume信息
[root@k8s-node1 ~]# gluster volume info volumeheketi Volume Name: volumeheketi Type: Replicate Volume ID: 91a3764a-4ceb-4bc3-b523-65e2b847fb13 Status: Started Snapshot Count: 0 Number of Bricks: 1 x 2 = 2 Transport-type: tcp Bricks: Brick1: 192.168.1.100:/var/lib/heketi/mounts/vg_1e121d3f725764eb55cb15cc42aa8f99/brick_ad96a8bd3d00505ad0bc026f7debe146/brick Brick2: 192.168.2.100:/var/lib/heketi/mounts/vg_e193b95ccea9ee90b09e837e80f5c3b9/brick_6c64490e4130c1b4ce833377c417a19d/brick Options Reconfigured: transport.address-family: inet nfs.disable: on可以看到在glusterfs中仍然有brick信息,但是这个目录是一个由hetike自动生成的lv
[root@k8s-node1 ~]# lvdisplay /dev/vg_1e121d3f725764eb55cb15cc42aa8f99/brick_ad96a8bd3d00505ad0bc026f7debe146 --- Logical volume --- LV Path /dev/vg_1e121d3f725764eb55cb15cc42aa8f99/brick_ad96a8bd3d00505ad0bc026f7debe146 LV Name brick_ad96a8bd3d00505ad0bc026f7debe146 VG Name vg_1e121d3f725764eb55cb15cc42aa8f99 LV UUID OqGMZK-WSS0-YO1q-Af4L-lj0R-kEdc-DdJS8x LV Write Access read/write LV Creation host, time k8s-node1, 2019-05-24 14:15:19 +0800 LV Pool name tp_ad96a8bd3d00505ad0bc026f7debe146 LV Status available # open 1 LV Size 1.00 GiB // LV大小是创建时指定的volume大小 Mapped size 0.66% Current LE 256 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 253:88查看该lv的挂载信息
[root@k8s-node1 ~]# df -h| grep brick_ad96a8bd3d00505ad0bc026f7debe146 /dev/mapper/vg_1e121d3f725764eb55cb15cc42aa8f99-brick_ad96a8bd3d00505ad0bc026f7debe146 1020M 33M 987M 4% /var/lib/heketi/mounts/vg_1e121d3f725764eb55cb15cc42aa8f99/brick_ad96a8bd3d00505ad0bc026f7debe146可以看到该目录就是volume对应的brick目录
Kubernetes通过创建StorageClass来使用 Dynamic Provisioning 特性,StorageClass连接Heketi,可以根据需要自动创建GluserFS的Volume,StorageClass还是要系统管理员创建,不过StorageClass不需要每次创建,因为这个不需要很多,不同的PVC可以用同一个StorageClass。
其中clusterid可以通过heketi获取
[root@k8s-node1 ~]# heketi-cli cluster list Clusters: Id:6b6e86c292608a56f4c4065832392a10 [file][block](按照正常K8s使用Glusterfs volume的方式,还需要创建ep、pv,并且需要预先在glusterfs上创建好volume,但现在通过storageclass,这些步骤可以通通省略,只需要直接创建PVC即可)
[root@k8s-node1 ~]# cat glusterfs-pvc.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: glusterfs-test-vol1 annotations: volume.beta.kubernetes.io/storage-class: "heketi-sc" spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi [root@k8s-node1 ~]# kubectl create -f glusterfs-pvc.yaml persistentvolumeclaim "glusterfs-test-vol1" created