01 引言
声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》的读书笔记
通过前面的博客,大致知道了k8s里面Volume
存储的一些概念了,有兴趣的童鞋可以参考下:
- 《k8s教程(Volume篇)-k8s存储机制概述》
- 《k8s教程(Volume篇)-PV详解》
- 《k8s教程(Volume篇)-PVC详解》
- 《k8s教程(Volume篇)-StorageClass详解》
本文结合之前的知识,从定义StorageClass
、创建 GlusterFS
和Heketi
服务、 用户申请PVC
到创建Pod
使用存储资源,对StorageClass
和动态资源分配进行详细说明。
02 准备工作
首先在各 Node
上安装 GlusterFS
客户端:
yum install glusterfs glusterfs-fuse
GlusterFS管理服务容器 需要以特权模式运行,在kube-apiserver
的启动参数中增加:
--allow-privileged=true
给要部署GlusterFS管理服务的节点打上storagenode=glusterfs
标签,是为了将GlusterFS容器定向部署到安装了GlusterFS的 Node上:
$ kubectl label node k8s-node-1 storagenode=glusterfs $ kubectl label node k8s-node-2 storagenode=glusterfs $ kubectl label node k8s-node-3 storagenode=glusterfs
03 创建GlusterFS管理服务容器集群
GlusterFS管理服务容器以DaemonSet
的方式进行部署,确保在每个Node上都运行—个GlusterFS管理服务。
glusterfs-daemonset.yaml
的内容如下:
apiVersion: apps/v1 kind: DaemonSet metadata: name: glusterfs labels: glusterfs: daemonset annotations: description: GlusterFS Daenonset tags: glusterfs spec: template: metadata: name: glusterfs labels: glusterfs-node: pod spec: nodeSelector: storagenode: glusterfs hostNetwork: true containers: - image: gluster/gluster-centos:latest name: glusterfs volumeMounts: - name: glusterfs-heketi mountPath: "/var/lib/heketi" - name: glusterfs-run mountPath: "/run" - name: glusterfs-lvm mount Path: "/run/1vm" - name: glusterfs-etc mountPath: "/etc/glusterfs" - name: glusterfs-1ogs mountPath: "/var/log /glusterfs" - name: glusterfs-config mountPath: "/var/lib/glusterd" - name: glusterfs-dev mountPath: "/dev" - name: glusterfs-misc mountPath: "/var/lio/misc/glusterfsd" - name: glusterfs-cgroup mountPath: "/sys/fs/cgroup" readonly: true - name: glusterfs-ss1 mountPath: "/etc/ssl" readonly: true securityContext: capabilities: {} privileged: true readinessProbe: timeoutSeconds: 3 initialDelaySeconds: 60 exec: command: - "/bin/bash" - "-c" - systemctl status glusterd.service livenessProbe: timeoutSeconds: 3 initialDelaySeconds: 60 exec: command: - "/bin/bash" - "-c" - systemctl status glusterd.service volumes: - name: glusterfs-heketi hostPath: path: "/var/lib/heketi" - name: glusterfs-run - name: qlusterfs-1vn hostPath: path: " /run/1vm" - name: glusterfs-etc hostPath: path: "/etc/glusterfs" - name: glusterfs-1ogs hostPath: path:"/var/log/glusterfs" - name: glusterfs-config hostPath: path:"/var/lib/glusterd" - name: glusterfs-dev hostPath: path: "/dev" - name: glusterfs-nise hostPath: path: "/var/1ib/misc/glusterfsd" - name: glusterfs-cgroup hostPath: path: "/sys/fs/cgroup" - name: glusterfs-ssl hostPath: path: "/etc/ssl"
创建:
$ kubectl create -f glusterfs-daemonset.yaml daemonset.apps/glusterfs created
查询pod:
$ kubect1 get po NAME READY STATUS RESTARTS AGE glusterfs-k2src 1/1 Running 0 1m glusterfs-q32z2 1/1 Running 0 1m
04 创建Heketi服务
Heketi是一个 提供RESTful API
管理GlusterFS卷的框架,能够在OpenStack、 Kubernetes、 OpenShift等云平台上实现动态存储资源供应,支持GlusterFS多集群管理,便于管理员对GlusterFS进行操作。
下图展示了Heketi
的功能:
4.1 创建ServiceAccount及RBAC授权
在部署Heketi服务之前,先创建ServiceAccount
并完成RBAC
授权:
# heketi-rbac.yam1 apiversion: v1 kind: ServiceAccount metadata: name: heketi-service-account --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: heketi rules: - apiGroups: - "" resources: - endpoints - services - pods verbs: - get - list - watch - apiGroups: - "" resourees: - pods/exec verbs: - create --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: heketi roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: heketi subiects: - kind: ServiceAccount name: heketi-service-account namespace: default
创建:
# kubectl create -f heketi-rbac.yaml serviceaccount/heketi-service-account created role.rbae.authorization.k8s.io/heketi created rolebinding.rbac.authorization.k8s.io/heketi created
4.2 部署Heketi服务
# heketi-deployment-svc.yaml apiVersion: apps/v1 kind: Deployment metadata: name: heketi labels: glusterfs: heketi-deployment deploy-heketi: heketi-deployment annotations: description: Defines how to deploy Heketi spec: replicas: 1 seleetor: matchLabels: name: deploy-heketi glusterfs: heketi-pod template: metadata: name: deploy-heketi labels: name: deploy-heketi glusterfs: heketi-pod spec: serviceAccountName: heketi-service-account containers: - image: heketi/heketi name: deploy-heketi env: - name: HEKETI_EXECUTOR value: kubernetes - name: HEKETI_FSTAB value: "/var/1ib/heketi/fstal" - name: HEKETI_SNAPSHOT_LIMIT value: "14" - name: HEKETI_KUBE_GLUSTER_DAEMONSET value: "y" ports: - containerPort: 8080 volumeMounts: - name: db mountPath: "/var/lib/heketi" readinessProbe: timeoutSeconds: 3 initialDelaySeconds: 3 httpGet: path: "/hello" port: 8080 livenessProbe: timeoutSeconds: 3 initialDelaySeconds: 30 httpGet: path: "/hello" port: 8080 volumes: - name: db hostPath: path: "/heketi-datan" --- kind: Service apiVersion: v1 metadata: name: heketi labels: glusterfs: heketi-service deploy-heketi: support annotations: description: Exposes Heketi Service spec: selector: name: deploy-heketi ports: name: deploy-heketi port: 8080 targetPort: 8080
需要注意的是,Heketi的DB数据需要持久化保存,建议使用hostPath
或其他共享存储进行保存:
$ kubect1 create -f heketi-deploymnent-sve.yaml deployment.apps/heketi created service/heketi created
05 通过Heketi服务管理GlusterFS集群
在Heketi能够管理GlusterFS
集群之前,首先要为其设置 GlusterFS
集群的信息。可以用一个topology.json配置文件 来完成各个GlusterFS
节点和设备的定义,Heketi要求在一个GlusterFS
集群中至少有3个节点。
- 在topologyjson配置文件 hostnames字段的manage上填写主机名;
- 在storage上填写IP地址;
- devices要求是未创建文件系统的裸设备(可以有多块盘),以供Heketi自动完成PV (Physical Volume )、 VG( Volume Group ) 和 LV ( Logical Volume )的创建。
topology.json文件的内容如下:
{ "clusters": [ { "nodes": [ { "node": { "hostnames": { "manage": [ "k8s-node-1" ], "storage": [ "192.168.18.3" ] }, "zoon": 1 }, "devices": [ "/dev/sdb" ] }, { "node": { "hostnames": { "manage": [ "k8s-node-2" ], "storage": [ "192.168.18.4" ] }, "zoon": 1 }, "devices": [ "/dev/sdb" ] }, { "node": { "hostnames": { "manage": [ "k8s-node-3" ], "storage": [ "192.168.18.5" ] }, "zoon": 1 }, "devices": [ "/dev/sdb" ] } ] } ] }
进入Heketi
容器,使用命令行工具heketi-cli
完成GlusterFS
集群的创建:
$ export HEKETI_CLI_SERVER=http://localhost:8080 $ heketi-cli topology 1oad --json=topology.json Creating cluster ... ID: f643dalcd64691c5705932a46a95d1d5 Creating node k8S-node-1 ID: 883506b09la22bd13f10bc3d0flo51223 Adding device/dev/sdb OK Creating node k8s-node-2 ID: e646879689106£82a9c4ac910a865cc8 Adding device/dev/sdb OK Creating node k8s-node-3 ID: b7783484180£6a592a30baebfb97d9be Adding device/dev/sdb OK
经过上述操作, Heketi就完成了GlusterFS
集群的创建,结果是在GlusterFS
集群各个节点的/dev/sdb
盘上成功创建了PV
和VG
。
查看Heketi的topology信息,可以看到Node和Device的详细信息,包括磁盘空间的大小和剩余空间。此时,GlusterFS的Volume和Brick还未创建:
$ heketi-cli topology info Cluster Id: £643dalcd64691c5705932a46a95dla5 Volumes: Nodes: Node Id: 883506b09la22bd13f10bc3d0fb51223 State: online Cluster Id: £643dalcd64691¢5705932a46a956105 Zone: 1 Management Hostname: k8s-node -1 Storage Hostname: 192.168.18.3 Devices: Id:b474f14b0903ed03ec80d4a989£943£2 Name: /dev/ sdb State:online Size (GiB):9 Used (GiB):0 Free (GiB):9 Bricks: Node Id: b7783484180£6a592a30baebfb97d9be State: online Cluster Id: l643dalcd64691c5705932a46a95a1a5 Zone: 1 Management Hostname: k8s-node-3 Storage Hostname: 192.168.18.5 Devices: Id: fac3fa5aclde3d5bde3aa68f6aa61285 Name: /dev/sdb State:online Size (GiB):9 Used (GiB):0 Free (GiB):9 Bricks:
06 定义StorageClass
准备工作已经就绪,集群管理员现在可以在Kubernetes 集群中定义一个 StorageClass了。
storageclass-gluster-heketi.yaml
配置文件的内容如下:
apiVersion: storage.k8s.io/v1 kind: Storageclass metadata: name: gluster-heketi provisioner: kubernetes.io/glusterfs parameters: resturl: "http: //172.17.2.2:8080" restauthenabled: "false"
provisioner参数必须被设置为“kubernetes.io/glusterfs”。
resturl的地址需要被设置为API Server所在主机可以访问到的Heketi服务地址,可以使用服务ClusterIP+Port、 PodIP+Port,或将服务映射到物理机。
创建该StorageClass资源对象:
$ kubectl create -f storageclass-gluster-heketi.yaml storageclass/gluster-heketi created
07 定义PVC
现在,用户可以定义一个PVC申请Glusterfs存储空间了。
下面是PVC的YAML 定义,其中申请了1GiB
空间的存儲资源,设置StorageClass
为“gluster-heketi
”,同时未设置Selector
,表示使用动态资源供应模式:
# pvc-gluster-heketi.yaml apiVersion: V1 kind: PersistentVolumeClaim metadata: name: pve-gluster-heketi spec: storageClassName: gluster-heketi accessModes: - Readwriteonce resources: requests: storage: 1Gi
创建:
$ kubectl create -f ppvc-gluster-heketi.yaml persistentvolumeclaim/pvc-gluster-heketi created
PVC
的定义一旦生成,系统便将触发Heketi
进行相应的操作,主要为在 GlusterFS集群中创建brick,再创建并启动一个Volume。
可以在Heketi
的日志中查看整个过程:
...... [kubeexec] DEBUG 2020/04/26 00:51:30 /sre/github .com /heketi /heketi/executors/ kubeexec/kubeexec.go:250: Host: k8s-node-1 Pod: glusterfs-ld7nh Command: gluster --mode=script volume create v01 87b9314cb76bafacfb7e9cdc04fcaf05 replica 3 192.168.18.3:/var/lib/heketi/mounts/vg b474f14b0903ed03ec80d4a989£943£2/brick_ d0 8520c9££769a0a9165£9815671f2cd/brick 192.168.18.5:/var/lib /heketi/mounts /vg fac3fa5aclde 3d5bde 3aa68f6aa61285 /brick 68 18dce118b8a54e9590199d44a3817b/brick 192.168. 18.4:/vef/1tb/heket1 /mounta/vg. 03532e7ab723933e8643o64b3Gxeelaz /bztok.9e cb8f7fdelae937011£0440le7c6c56/brick Result: volume create: vo1 87b9314cb76bafacfb7e9cdc0A fcaf05: success: please start the volume to access data [kubeexec] DEBUG 2020/04/26 00:51:33 /src/github.com/heketi/heketi/executors/kubeexec/kubeexec.go:250: Host: k8s-node-1 Pod: glusterfs-ld7nh Command: gluster --mode=script volune start vo1 87b9314cb76bafacfbTe 9cdc04fcaf05 Result: volume start: vol 87b9314cb7 6bafacfbTe 9cdc04fcaf05: suecess ......
查看PVC的详情,确认其状态为Bound
(已绑定):
$ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE pve-gluster-heketi Bound pvc-783cf949-2ala-11e7-8717-000c2 9eaed40 1Gi RWX qluster-heketi 6m
查看PV
,可以看到系统通过动态供应机制系统自动创建的PV
:
$ kubectl get pv NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE pve-783cf949-2a1a-11e7-8717-000c29eaed4o 1Gi Rwx Delete Bound 1 default/pvc-gluster-heketi gluster-heketi 6m
查看该PV的详细信息,可以看到其容量、引用的StorageClass等信息都已正确设置,状态也为Bound,回收策略则为默认的Delete。同时Gluster的Endpoint 和Path也由Heketi自动完成了设置:
$ kubectl describe pv PVC-783c£949-2ala-11e7-8717-000c2geaed40 Name: pvc-783¢£949-2ala-11e7-8717-000c29eaed40 Labels: <none> Annotations: pv.beta.kubernetes.io/gid-2000 pv.kubernetes.io/bound-by-controller=yes pv.kubernetes.io/provisioned-by=kubernetes.io/glusterfs Storageclass: gluster-heketi Status: Bound Claim: default/pve-gluster-heketi Reclaim Policy: Delete Access Modes: RWX Capacity: 1Gi Message: Source: Type: Glusterfs (a Glusterfs mount on the host that shares a pod's lifetime) EndpointsName: glusterfs-dynamic-pvc-gluster-heketi Path: Vol_87b9314cb76bafacfbTe9cdc04fcaf05 Readonly: false Events: <none>
至此,一个可供Pod
使用的PVC
就创建成功了。接下来Pod
就能通过Volume
的设置将这个PVC
挂载到容器内部进行使用了。
08 Pod使用PVC的存储资源
下面是在Pod中使用PVC定义的存储资源的配置,首先设置一个类型为 persistentVolumeClaim
的Volume
,然后将其通过volumeMounts
设置挂载到容器内的目录路径下,注意,Pod需要与PVC属于同一个命名空间:
# pod-use-pve.yam1 apiVersion: v1 kind: Pod metadata: name: pod-use-pvc spec: containers: - name: pod-use-pvc image: busybox command: - sleep - "3600" volumeMounts: - name: qluster-volume mountPath: "/pv-data" readonly: false volumes: name: qluster-volume persistentVolumeclaim: claimName: pvc-gluster-heketi
创建之后,进入容器pod-use-pvc,在/pv-data目录下创建一些文件:
$ kubectl exec -ti pod-use-pve --/bin/sh /$ cd /pv-data /$ touch a /$ echo "hello" >b
可以验证文件a和b在GlusterFS集群中正确生成。
至此,使用Kubernetes最新的动态存储供应模式,配合StorageClass和Heketi 共同搭建基于GlusterFS的共享存储就完成了。
在使用动态存储供应模式的情况下,可以解决静态模式的下列问题:
- 管理员需要预先准备大量的静态PV;
- 系统为PVC选择PV时可能存在PV空间比PVC申请空间大的情况,无法保证没有资源浪费;
所以在Kubernetes中,建议用户优先考虑使用StorageClass的动态存储供应模式进行存储资源的申请、使用、回收等操作。
09 文末
本文主要结合之前的k8s的volume的知识并以GlusterFS为案例走了一下整体的使用流程,希望能帮助到大家,谢谢大家的阅读,本文完!