k8s中應用GlusterFS類型StorageClass
- 2022 年 5 月 12 日
- 筆記
- glusterfs, Kubernetes
GlusterFS在Kubernetes中的應用
GlusterFS服務簡介
GlusterFS是一個可擴展,分散式文件系統,集成來自多台伺服器上的磁碟存儲資源到單一全局命名空間,以提供共享文件存儲。
特點:
- 可以擴展到幾PB容量
- 支援處理數千個客戶端
- 兼容POSIX介面
- 使用通用硬體,普通伺服器即可構建
- 能夠使用支援擴展屬性的文件系統,例如ext4,XFS
- 支援工業標準的協議,例如NFS,SMB
- 提供很多高級功能,例如副本,配額,跨地域複製,快照以及bitrot檢測
- 支援根據不同工作負載進行調優
GFS存儲的一些術語:
- Brick:GlusterFS中的存儲單元,通常是一個受信存儲池中的伺服器的一個目錄。可以通過主機名和目錄名來標識,如’SERVER:EXPORT’。
- Node:一個擁有若干brick的設備。
- Volume:一組bricks的邏輯集合。
- Client:掛載了GlusterFS卷的設備。
- GFID:GlusterFS卷中的每個文件或目錄都有一個唯一的128位的數據相關聯,其用於模擬inode
Namespace:每個Gluster卷都導出單個ns作為POSIX的掛載點。 - RDMA:遠程直接記憶體訪問,支援不通過雙方的OS進行直接記憶體訪問。
- RRDNS:round robin DNS是一種通過DNS輪轉返回不同的設備以進行負載均衡的方法
- Self-heal:用於後台運行檢測複本卷中文件和目錄的不一致性並解決這些不一致。
- Split-brain:腦裂
- Volfile:Glusterfs進程的配置文件,通常位於/var/lib/glusterd/vols/volname
GFS卷(volume)的模式:
Volume是一組Brick的組合,一個gfs集群中可以有多個volume,可以供客戶端掛載、存儲數據等,它有很多種模式供選擇:
- 分散式卷(默認模式):即DHT,文件通過hash演算法分布存在不同的brick里,單個brick失效會帶來數據丟失,無需額外元數據伺服器。
- 條帶卷:即Striped,文件切分成一個個的chunk,存放於不同的brick上,只建議在非常大的文件時使用。
- 複製卷:即AFR,同一份數據會同步在多個Brick中,單一節點故障時保持數據高可用,事務性操作,保持一致性。
- 分散式複製卷:即AFR和DHT的組合,最少需要4台伺服器才能創建,讀操作可以做到負載均衡。
- 條帶複製卷:Striped與AFR 的組合,最少需要4台伺服器才能創建。
- 分散式條帶複製卷:至少需要8台伺服器才能創建,每四台伺服器一組。
GlusterFS服務搭建及進程解析
主機名 | ip地址 | 角色 |
---|---|---|
master | 192.168.72.100 | k8s-master、glusterfs、heketi |
node1 | 192.168.72.101 | k8s-work節點 |
node2 | 192.168.72.102 | k8s-work節點 |
-
獲取gluster rpm包,我這裡是7.5版本的,需要下載以下幾個rpm包:
# ls glusterfs-7.5-1.el7.x86_64.rpm glusterfs-libs-7.5-1.el7.x86_64.rpm glusterfs-api-7.5-1.el7.x86_64.rpm glusterfs-server-7.5-1.el7.x86_64.rpm glusterfs-api-devel-7.5-1.el7.x86_64.rpm psmisc-22.20-15.el7.x86_64.rpm glusterfs-cli-7.5-1.el7.x86_64.rpm userspace-rcu-0.10.0-3.el7.x86_64.rpm glusterfs-client-xlators-7.5-1.el7.x86_64.rpm userspace-rcu-0.7.16-1.el7.x86_64.rpm glusterfs-fuse-7.5-1.el7.x86_64.rpm
地址://buildlogs.centos.org/centos/7/storage/x86_64/gluster-9/Packages/;如果有外網可以直接配置yum源安裝需要的版本。
-
安裝rpm包
## 先安裝依賴的環境包 yum -y install attr psmisc rpcbind ## 安裝glusterfs rpm -ivh glusterfs-libs-7.5-1.el7.x86_64.rpm rpm -ivh glusterfs-7.5-1.el7.x86_64.rpm rpm -ivh glusterfs-api-7.5-1.el7.x86_64.rpm glusterfs-cli-7.5-1.el7.x86_64.rpm glusterfs-client-xlators-7.5-1.el7.x86_64.rpm rpm -ivh glusterfs-fuse-7.5-1.el7.x86_64.rpm rpm -ivh userspace-rcu-0.10.0-3.el7.x86_64.rpm rpm -ivh glusterfs-server-7.5-1.el7.x86_64.rpm rpm -ivh glusterfs-api-devel-7.5-1.el7.x86_64.rpm
因為包之間會有依賴關係,按照以上順序可以順利安裝,如果不想這麼麻煩,可強制安裝–force –nodeps。
-
啟動服務
## 需要啟動兩個服務glusterd和glusterfsd systemctl start glusterd glusterfsd
-
glusterd和glusterfsd兩個服務的區別,以及gluster和glusterfs命令
glusterd是其服務的守護進程,是一個管理模組,處理gluster發過來的命令,處理集群管理、存儲池管理、brick管理、負載均衡、快照管理等,默認埠24007:
# ss -tnlp | grep 24007 LISTEN 0 128 *:24007 *:* users:(("glusterd",pid=7873,fd=10)) ## 進程 # ps -ef | grep gluster root 7873 1 0 Mar28 ? 00:00:41 /usr/sbin/glusterd -p /var/run/glusterd.pid --log-level INFO
glusterfsd是服務端模組,存儲池中的每個brick(卷組)都會啟動一個glusterfsd進程。此模組主要是處理客戶端的讀寫請求,默認埠是從49152開始,後續埠都+1。我這裡啟動了兩個卷組:
# ss -tnlp | grep gluster LISTEN 0 128 *:49152 *:* users:(("glusterfsd",pid=7898,fd=11)) LISTEN 0 128 *:49153 *:* users:(("glusterfsd",pid=44275,fd=11)) ## 進程 # ps -ef | grep gluster root 7898 1 0 Mar28 ? 00:04:46 /usr/sbin/glusterfsd -s 192.168.72.100 --volfile-id xtest-fs.192.168.72.100.data-text-mind -p /var/run/gluster/vols/xtest-fs/192.168.72.100-data-text-mind.pid -S /var/run/gluster/3b5c03678c749dfd.socket --brick-name /data/text-mind -l /var/log/glusterfs/bricks/data-text-mind.log --xlator-option *-posix.glusterd-uuid=46bfd5ab-07be-4a97-993f-1ddab13e0ee9 --process-name brick --brick-port 49152 --xlator-option xtest-fs-server.listen-port=49152
glusterfs命令是一個客戶端模組,負責通過mount掛載集群中某台伺服器的存儲池,以目錄的形式呈現給用戶。用戶mount幾個卷組,就是出現幾個glusterfs的進程,如下:
# ps -ef | grep -w glusterfs | grep -v glusterfsd root 31496 1 0 Mar25 ? 00:02:46 /usr/sbin/glusterfs --process-name fuse --volfile-server=yq01-aip-aikefu10.yq01.baidu.com --volfile-id=xtest-fs /data/mnt
gluster命令就是客戶端請求命令,負責發起請求,比如創建、查看當前卷組等:
# gluster volume create xtest-fs 192.168.72.100:/data/xtest-fs/brick force # gluster volume list
-
如果是多台gfs構成集群,在服務安裝完畢之後,要進行一個添加的動作
## 添加 # gluster peer probe node1 # gluster peer probe node2 ## 查看當前集群 # gluster pool list
heketi服務搭建以及管理GFS
heketi提供一個RESTful管理節點介面,可以用來管理GlusterFS卷的生命周期,通過heketi,就可以像使用Opentack Manila,kubernete和openShift一樣申請可以動態配置GlusterFS卷,Heketi會動態在集群內選擇bricks構建所需的volumes,這樣以確保數據的副本會分散到集群不同的故障域內。
-
安裝heketi服務,有源可以直接yum安裝,沒有可以單獨下載rpm包安裝,或者通過docker、k8s安裝
# yum -y install heketi heketi-client # heketi --version Heketi 9.0.0 # systemctl start heketi.service
-
配置ssh秘鑰,使heketi節點可以免密訪問glusterfs節點
# ssh-keygen -f /etc/heketi/heketi_key -t rsa -N '' # ssh-copy-id -i /etc/heketi/heketi_key.pub master # chown heketi:heketi /etc/heketi/
-
編輯heketi的配置文件/etc/heketi/heketi.json
heketi有三種執行方式,分別為mock,ssh,kubernetes,官方建議在測試和開發環境使用mock,生產使用ssh,如果glusterfs是部署在k8s上,則使用kubernetes方式。
下邊對配置部分做出解釋:
{ ## heketi服務的默認埠,可以更改。 "_port_comment": "Heketi Server Port Number", "port": "8080", ## 是否開啟認證,一般選是。 "_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": "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." ], ## 選擇操作gfs的方式,這裡選擇ssh。 "executor": "ssh", ## 配置ssh秘鑰 "_sshexec_comment": "SSH username and private key file information", "sshexec": { "keyfile": "/etc/heketi/heketi_key", "user": "root", "port": "22", "fstab": "/etc/fstab" }, ## 配置k8s證書 "_kubeexec_comment": "Kubernetes configuration", "kubeexec": { "host" :"//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", ## heketi的數據存儲位置 "db": "/var/lib/heketi/heketi.db", "_loglevel_comment": [ "Set log level. Choices are:", " none, critical, error, warning, info, debug", "Default is warning" ], ## heketi的日誌級別 "loglevel" : "debug" } }
-
啟動heketi服務,設置開啟自啟,測試訪問
# systemctl start heketi # systemctl enable heketi # curl //master:8080/hello Hello from Heketi
-
配置heketi連接gfs服務
(1) 在集群的主節點設置環境變數,注意埠根據實際情況修改
# export HEKETI_CLI_SERVER=//master:8080
(2) 在集群的主節點修改/usr/share/heketi/topology-sample.json配置文件,執行添加節點和添加device的操作:
{ "clusters": [ { "nodes": [ { "node": { "hostnames": { "manage": [ "master" ], "storage": [ "192.168.72.100" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdb", "destroydata": false } ] } ] } ] }
manage指定gfs主機域名,storage指定gfs主機ip,devices下指定要存儲gfs數據的數據盤,此盤應該是一塊未分區的乾淨盤,分區應該也可以,我這裡沒有試。
可以添加多個主機和多塊盤,具體格式如下:
{ "clusters": [ { "nodes": [ { "node": { "hostnames": { "manage": [ "192.168.10.100" ], "storage": [ "192.168.10.100" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdb", "destroydata": false }, { "name": "/dev/sdc", "destroydata": false }, { "name": "/dev/sdd", "destroydata": false }, { "name": "/dev/sde", "destroydata": false }, { "name": "/dev/sdf", "destroydata": false }, { "name": "/dev/sdg", "destroydata": false }, { "name": "/dev/sdh", "destroydata": false }, { "name": "/dev/sdi", "destroydata": false } ] }, { "node": { "hostnames": { "manage": [ "192.168.10.101" ], "storage": [ "192.168.10.101" ] }, "zone": 2 }, "devices": [ { "name": "/dev/sdb", "destroydata": false }, { "name": "/dev/sdc", "destroydata": false }, { "name": "/dev/sdd", "destroydata": false }, { "name": "/dev/sde", "destroydata": false }, { "name": "/dev/sdf", "destroydata": false }, { "name": "/dev/sdg", "destroydata": false }, { "name": "/dev/sdh", "destroydata": false }, { "name": "/dev/sdi", "destroydata": false } ] }, { "node": { "hostnames": { "manage": [ "192.168.10.102" ], "storage": [ "192.168.10.102" ] }, "zone": 1 }, "devices": [ { "name": "/dev/sdb", "destroydata": false }, { "name": "/dev/sdc", "destroydata": false }, { "name": "/dev/sdd", "destroydata": false }, { "name": "/dev/sde", "destroydata": false }, { "name": "/dev/sdf", "destroydata": false }, { "name": "/dev/sdg", "destroydata": false }, { "name": "/dev/sdh", "destroydata": false }, { "name": "/dev/sdi", "destroydata": false } ] }, { "node": { "hostnames": { "manage": [ "192.168.10.103" ], "storage": [ "192.168.10.103" ] }, "zone": 2 }, "devices": [ { "name": "/dev/sdb", "destroydata": false }, { "name": "/dev/sdc", "destroydata": false }, { "name": "/dev/sdd", "destroydata": false }, { "name": "/dev/sde", "destroydata": false }, { "name": "/dev/sdf", "destroydata": false }, { "name": "/dev/sdg", "destroydata": false }, { "name": "/dev/sdh", "destroydata": false }, { "name": "/dev/sdi", "destroydata": false } ] } ] } ] }
(3) 導入配置文件到heketi,使heketi管理gfs
# heketi-cli -s $HEKETI_CLI_SERVER --user admin --secret 'My Secret' topology load --json=/usr/share/heketi/topology-sample.json Creating cluster ... ID: 6b7b8affdb10add55ea367e7e2f8e091 Allowing file volumes on cluster. Allowing block volumes on cluster. Creating node master ... ID: 96bbfbf66bc8ad551fe5a8c8ef289218 Adding device /dev/sdb ... OK
如果報錯:Error: Unable to get topology information: Invalid JWT token: Token missing iss claim。是因為沒加用戶名和密碼 –user admin –secret ‘My Secret’。
(4) 測試創建一個volume,看是否成功
# heketi-cli volume create --size=10 --durability=none --user "admin" --secret "My Secret" Name: vol_38412746b79cf0d7ffa69a3969c1cfed Size: 10 Volume Id: 38412746b79cf0d7ffa69a3969c1cfed Cluster Id: 6b7b8affdb10add55ea367e7e2f8e091 Mount: 192.168.72.100:vol_38412746b79cf0d7ffa69a3969c1cfed Mount Options: backup-volfile-servers= Block: false Free Size: 0 Reserved Size: 0 Block Hosting Restriction: (none) Block Volumes: [] Durability Type: none Distribute Count: 1
創建成功,heketi已經可以管理gfs服務。
k8s集群創建StorageClass實現動態管理pv pvc
-
創建StorageClass
vi storageclass-gfs-heketi-distributed.yaml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gluster-distributed provisioner: kubernetes.io/glusterfs reclaimPolicy: Retain parameters: resturl: "//192.168.72.100:8080" restauthenabled: "true" restuser: "admin" restuserkey: "My Secret" gidMin: "40000" gidMax: "50000" volumetype: "none" allowVolumeExpansion: true volumeBindingMode: Immediate
provisioner:表示存儲分配器,需要根據後端存儲的不同而變更;
reclaimPolicy: 默認即「Delete」,刪除pvc後,相應的pv及後端的volume,brick(lvm)等一起刪除;設置為」Retain」時則保留數據,需要手工處理
resturl:heketi API服務提供的url;
restauthenabled:可選參數,默認值為”false”,heketi服務開啟認證時必須設置為”true”;
restuser:可選參數,開啟認證時設置相應用戶名;
restuserkey:可選參數。開啟認證時輸入對應用戶的密碼;
secretNamespace:可選參數,開啟認證時可以設置為使用持久化存儲的namespace;
secretName:可選參數,開啟認證時,需要將heketi服務的認證密碼保存在secret資源中;
clusterid:可選參數,指定集群id,也可以是1個clusterid列表,格式為”id1,id2″;
volumetype:可選參數,設置卷類型及其參數,如果未分配卷類型,則有分配器決定卷類型;如”volumetype: replicate:3″表示3副本的replicate卷,”volumetype: disperse:4:2″表示disperse卷,其中『4』是數據,』2』是冗餘校驗,”volumetype: none”表示distribute卷;
allowVolumeExpansion:表示是否支援動態擴容,默認為true;
volumeBindingMode:表示是否立即bound pv,可選值WaitForFirstConsumer和Immediate;
創建sc:
# kubectl create -f storageclass-gfs-heketi-distributed.yaml # kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION gluster-distributed kubernetes.io/glusterfs Retain Immediate true
-
創建pvc
vi glusterfs-pvc.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: glusterfs-test spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi storageClassName: gluster-distributed
創建pvc
# kubectl create -f glusterfs-pvc.yaml # kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE glusterfs-test Bound pvc-0a3cffea-36b0-4609-a983-88df995b99e8 5Gi RWX gluster-distributed 5s
這個時候 df -h 就可以看到有新的分區被掛載
# df -h | tail -n 1 /dev/mapper/vg_5b4ef948902b85845afd387ca71c6858-brick_0fd0afa344ca798d7a9fccab5bb60a9e 5.0G 33M 5.0G 1% /var/lib/heketi/mounts/vg_5b4ef948902b85845afd387ca71c6858/brick_0fd0afa344ca798d7a9fccab5bb60a9e
-
創建一個deployment,測試讀寫
vi glusterfs-deploy.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: glusterfs-deploy labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: registry:5000/nginx:1.13 imagePullPolicy: IfNotPresent ports: - name: web containerPort: 80 volumeMounts: - name: pvc-glusterfs mountPath: /data volumes: - name: pvc-glusterfs persistentVolumeClaim: claimName: glusterfs-test
創建deployment
# kubectl create -f glusterfs-deploy.yaml deployment.apps/glusterfs-deploy created # kubectl get pod | grep glus glusterfs-deploy-cfd8c8578-45r9z 1/1 Running 0 72s glusterfs-deploy-cfd8c8578-vjrzn 1/1 Running 0 104s
測試讀寫
# kubectl exec -it glusterfs-deploy-cfd8c8578-45r9z -- bash # cd /data/ # for i in `seq 1 10`; do echo $i > $i ; done # ls 1 10 2 3 4 5 6 7 8 9 # cat 1 1
至此,gfs已經可以作為k8s的storageclass來動態管理pv pvc了。