Kubernetes与GlusterFS的爱恨情仇
	Kubernetes,容器管理领域的领导者;GlusterFS,分布式文件系统的后起之秀,他们之间会擦出什么样的火花呢?
	用Kubernetes部署的应用可以分为无状态的和有状态的,无状态的应用没有数据,Pod(一个或若干容器的集合)挂了被重新拉起,或者在Kubernetes集群不同的Node节点(可以认为是一台物理机或虚拟机)之间飘来飘去,都没有关系;有状态的应用有数据需要保存,如果容器挂了被重新拉起,容器里面保存的数据就没了。这时候我们自然而然的想到可以把数据映射到容器所在主机上,就像我们使用Docker时经常做的一样,可是这时候有个问题是,Kubernetes集群一般有多个Node节点,如果容器在挂了被重新拉起的时候被调度到其他的Node节点,那映射在原先主机上的数据还是在原先主机上,新的容器还是没有原来的数据。
	怎么办呢?
	这时候我们的另一位主角就要出场了——对,就是把数据存储在分布式存储GlusterFS上,Pod通过网络连接到分布式存储,这样不管Pod怎么在不同的Node节点间飘,连接的都是同一个分布式存储,数据都还在。
	这么说是Kubernetes需要GlusterFS了,都说“被需要的都有恃无恐”,那么GlusterFS是不是可以有恃无恐了呢?--当然不是,毕竟在这个残酷的世界,没有人是可以活得那么舒服的。事实上,Kubernetes的选择很多,目前Kubernetes支持的存储有下面这些:
	gcePersistentDisk
	awsElasticBlockStore
	AzureFile
	Azuk
	FC(Fibre Channel)
	FlexVolume
	Flocker
	NFS
	iSCSI
	RBD(Ceph Block Device)
	CephFS
	Cinder(OpenStack Block Storage)
	Glusterfs
	VsphereVolume
	Quobyte Volumes
	HostPath(就是刚才说的映射到主机的方式,多个Node节点会有问题)
	VMware Photon
	Portworx Volumes
	ScaleIO Volumes
	StorageOS
	Kubernetes有这么多选择,GlusterFS只是其中之一,GlusterFS也有自己的优点,它是一个开源的分布式文件系统,具有强大的横向扩展能力,通过扩展能够支持数PB存储容量和处理数千客户端。GlusterFS借助TCP/IP或InfiniBand RDMA网络将物理分布的存储资源聚集在一起,使用单一全局命名空间来管理数据。GlusterFS的Volume有多种模式,复制模式可以保证数据的高可靠性,条带模式可以提高数据的存取速度,分布模式可以提供横向扩容支持,几种模式可以组合使用实现优势互补。
	下面就来看看Kubernetes和GlusterFS是怎么结合起来的吧,实战开始了。
	部署Kubernetes
	部署方法可参考Kubernetes官网。
	假设Kubernetes部署在
	Master:
	192.168.XX.A
	Node:
	192.168.XX.A
	192.168.XX.B
	192.168.XX.C
	Kubernetes版本:
	# kubectl --version
	Kubernetes v1.5.2
	部署GlusterFS
	部署机器(这里跟Kubernetes部署在同样的机器):
	192.168.XX.A
	192.168.XX.B
	192.168.XX.C
	在每台机器的/etc/hosts加上:
	192.168.XX.A glusterfs1
	192.168.XX.B glusterfs2
	192.168.XX.C glusterfs3
	安装yum源(每台机器执行):
	yum install centos-release-gluster
	安装GlusterFS(每台机器执行):
	yum -y install glusterfs glusterfs-fuse glusterfs-server
	安装结束。
	启动GlusterFS(每台机器执行):
	systemctl start glusterd.service  
	systemctl enable glusterd.service
	组建集群(192.168.XX.A 机器执行):
	gluster peer probe glusterfs2  
	gluster peer probe glusterfs3
	验证(192.168.XX.A 机器执行):
	# gluster peer status 
	Number of Peers: 2
	Hostname: glusterfs2
	Uuid: 30efc726-35b5-4502-8f7f-f238ea44f3aa
	State: Peer in Cluster (Connected)
	Other names:
	192.168.XX.B
	Hostname: glusterfs3
	Uuid: 2c7aaa1b-4d51-4560-88be-cbe42e30b7a3
	State: Peer in Cluster (Connected)
	Other names:
	192.168.XX.C
	看到其他两个点的信息即代表GlusterFS集群组建成功。
	Kubernetes使用GlusterFS
	有两种方式,手动和自动,手动需要每次使用存储时自己创建GlusterFS的卷(GlusterFS的数据存储在卷Volume上);自动利用Kubernetes的 Dynamic Provisioning 特性,可以由Kubernetes自动创建GlusterFS卷,但是需要先部署Heketi软件,并且安装GlusterFS的机器上还要有裸磁盘。
	手动方式
	1)创建GlusterFS卷
	新建卷(3个副本的复制模式):
	(在每台机器执行:)
	mkdir -p /data/brick1/gv0
	(在一台机器执行:)
	gluster volume create gv0 replica 3 glusterfs1:/data/brick1/gv0 glusterfs2:/data/brick1/gv0 glusterfs3:/data/brick1/gv0 force
	启动卷:
	(在一台机器执行:)
	gluster volume start gv0
	查看卷:
	(在一台机器执行:)
	# gluster volume info  
	Volume Name: gv0
	Type: Replicate
	Volume ID: 2f8147de-fcb6-4219-81a3-71d6cfcaa609
	Status: Started
	Snapshot Count: 0
	Number of Bricks: 1 x 3 = 3
	Transport-type: tcp
	Bricks:
	Brick1: glusterfs1:/data/brick1/gv0
	Brick2: glusterfs2:/data/brick1/gv0
	Brick3: glusterfs3:/data/brick1/gv0
	Options Reconfigured:
	transport.address-family: inet
	nfs.disable: on
	可以看到所创建的卷的信息。
	2)Kubernetes创建PV等存储
	Kubernetes用PV(PersistentVolume)、PVC(PersistentVolumeClaim)来使用GlusterFS的存储,PV与GlusterFS的Volume相连,相当于提供存储设备,所以需要由知道GlusterFS Volume的系统管理员创建(这里我们自己就是系统管理员);PVC消耗PV提供的存储,由应用部署人员创建,应用直接使用PVC进而使用PV的存储。
	以下操作在Kubernetes Master节点执行。
	系统管理员创建Endpoint、Service、PV(Endpoint和Service不用每次都建,可以复用):
	先创建三个文件:
	glusterfs-endpoints.json:
	{
	  "kind": "Endpoints",
	  "apiVersion": "v1",
	  "metadata": {
	    "name": "glusterfs-cluster"
	  },
	  "subsets": [
	    {
	      "addresses": [
	        {
	          "ip": "192.168.XX.A"
	        }
	      ],
	      "ports": [
	        {
	          "port": 1
	        }
	      ]
	    },
	    {
	      "addresses": [
	        {
	          "ip": "192.168.XX.B"
	        }
	      ],
	      "ports": [
	        {
	          "port": 1
	        }
	      ]
	    },
	    {
	      "addresses": [
	        {
	          "ip": "192.168.XX.C"
	        }
	      ],
	      "ports": [
	        {
	          "port": 1
	        }
	      ]
	    }
	  ]
	}
	glusterfs-service.json:
	{
	  "kind": "Service",
	  "apiVersion": "v1",
	  "metadata": {
	    "name": "glusterfs-cluster"
	  },
	  "spec": {
	    "ports": [
	      {"port": 1}
	    ]
	  }
	}
	glusterfs-pv.yaml:
	apiVersion: v1
	kind: PersistentVolume
	metadata:
	  name: gluster-dev-volume1
	  labels:
	    name: my1 
	spec:
	  capacity:
	    storage: 1Gi
	  accessModes:
	    - ReadWriteMany
	  glusterfs:
	    endpoints: "glusterfs-cluster"
	    path: "gv0"
	    readOnly: false
	执行命令创建:
	kubectl apply -f glusterfs-endpoints.json
	kubectl apply -f glusterfs-service.json
	kubectl apply -f glusterfs-pv.yaml
	查看Endpoint、Service、PV:
	kubectl get ep
	kubectl get svc
	kubectl get pv
	3)Kubernetes创建应用
	应用部署人员创建PVC及应用(这里以MySQL为例):
	创建两个文件:
	glusterfs-pvc.yaml:
	kind: PersistentVolumeClaim
	apiVersion: v1
	metadata:
	  name: glusterfs-mysql1
	spec:
	  accessModes:
	    - ReadWriteMany
	  resources:
	    requests:
	      storage: 1Gi
	  selector:
	    matchLabels:
	      name: "mysql1"
	mysql-deployment.yaml:
	apiVersion: v1
	kind: Service
	metadata:
	  name: mysql
	  labels:
	    name: mysql
	spec:
	  type: NodePort
	  ports:
	  - name: mysqlport
	    port: 3306
	    nodePort: 31016
	  selector:
	    name: mysql
	---
	apiVersion: extensions/v1beta1 
	kind: Deployment 
	metadata: 
	  name: mysql
	spec: 
	  replicas: 1
	  template: 
	    metadata: 
	      labels: 
	        name: mysql
	    spec: 
	      containers: 
	        - name: mysqlcontainer
	          image: registry.hundsun.com/library/mysql:5.7.12
	          imagePullPolicy: IfNotPresent
	          env:
	          - name: MYSQL_ROOT_PASSWORD
	            value: root12345
	          ports: 
	            - containerPort: 3306
	          volumeMounts:
	            - name: gluster-mysql-data
	              mountPath: "/var/lib/mysql"
	      volumes:
	      - name: gluster-mysql-data
	        persistentVolumeClaim:
	          claimName: glusterfs-mysql1
	执行命令创建:
	kubectl apply -f glusterfs-pvc.yaml
	kubectl apply -f mysql-deployment.yaml
	查看PVC、Service:
	kubectl get pvc
	kubectl get svc
	查看Pod:
	# kubectl get po -o wide
	NAME                       READY     STATUS    RESTARTS   AGE       IP            NODE
	mysql-1858843218-68cts     1/1       Running   0          30m       10.254.39.9   192.168.XX.C
	看到MySQL Pod是Running状态,表示容器创建成功,运行在 192.168.XX.C 节点上。
	4)测试
	可以用MySQL客户端连接(连接的IP是任意Kubernetes Node节点IP,31016和root12345是mysql-deployment.yaml里指定的映射端口和MySQL root用户密码),连接后我们建一个数据库liao:
	# ./mysql -h 192.168.XX.A -P 31016 -uroot -proot12345
	Welcome to the MariaDB monitor.  Commands end with ; or \g.
	Your MySQL connection id is 3
	Server version: 5.7.12 MySQL Community Server (GPL)
	Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.
	Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
	MySQL [(none)]> 
	MySQL [(none)]> create database liao;
	Query OK, 1 row affected (0.02 sec)
	MySQL [(none)]> 
	MySQL [(none)]> show databases;
	+--------------------+
	| Database           |
	+--------------------+
	| information_schema |
	| liao               |
	| mysql              |
	| performance_schema |
	| sys                |
	+--------------------+
	5 rows in set (0.01 sec)
	MySQL [(none)]> 
	可以看到已经成功创建了一个数据库liao。
	现在我们测试一下Pod重新调度后数据还在不在:
	删除Pod:
	kubectl delete po mysql-1858843218-68cts
	Pod被删除后Kubernetes会自动把它重新拉起,在哪个Node节点上拉起由Kubernetes自己调度决定。
	过一小会儿重新查看Pod:
	# kubectl get po -o wide
	NAME                       READY     STATUS    RESTARTS   AGE       IP            NODE
	mysql-1858843218-v1fvf     1/1       Running   0          28s       10.254.34.5   192.168.XX.A
	可以看到Pod已经被调度到192.168.XX.A上。
	MySQL客户端连接并查看数据库:
	# ./mysql -h 192.168.XX.A -P 31016 -uroot -proot12345
	Welcome to the MariaDB monitor.  Commands end with ; or \g.
	Your MySQL connection id is 2
	Server version: 5.7.12 MySQL Community Server (GPL)
	Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.
	Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
	MySQL [(none)]> 
	MySQL [(none)]> 
	MySQL [(none)]> show databases;
	+--------------------+
	| Database           |
	+--------------------+
	| information_schema |
	| liao               |
	| mysql              |
	| performance_schema |
	| sys                |
	+--------------------+
	5 rows in set (0.03 sec)
	MySQL [(none)]> 
	可以看到我们建的liao数据库还在,说明虽然Pod重新调度,但数据还在。
	有人会疑问这里两次连接的都是192.168.XX.A的31016端口,为什么说连接到了不同的Pod,这是因为Kubernetes的kube-proxy会把我们配置的Service里映射的端口在每个Kubernetes Node上都开出来,也就是在任何一个Kubernetes Node上都能连接到Pod,Pod重新调度后,还是在任何一个Kubernetes Node上都能连接,但后面的Pod其实已经是新的了。
	自动方式
	自动方式需要先部署Heketi软件,Heketi用来管理GlusterFS,并提供RESTful API接口供Kubernetes调用。Heketi需要使用裸磁盘,假设三个GlusterFS节点上都挂了一块裸磁盘 /dev/xvde。
	1)部署Heketi
	部署在:
	192.168.XX.A
	安装:
	yum install heketi heketi-client -y
	修改/etc/heketi/heketi.json(省略了没有修改的部分):
	{
	  ...
	  "port": "8083",
	  ...
	  "_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": "/home/liao/key/key",
	      "user": "root",
	      "port": "22",
	      "fstab": "/etc/fstab"
	    },
	 ...
	  }
	}
	这里主要把端口改为8083了(防止冲突),executor改为ssh, sshexec的各项配置也做了相应修改。
	其中的Keyfile制作方法:
	ssh-keygen -t rsa
	输入key(随便起的名字),一直回车。
	制作完成后会在当前目录下生成key、key.pub,把 key.pub上传到GlusterFS三台服务器的/root/.ssh/下面,并重命名为authorized_keys,/etc/heketi/heketi.json中的Keyfile指向生成的key(包含路径)。
	启动:
	systemctl enable heketi
	systemctl start heketi
	看日志:
	journalctl -u heketi
	(Heketi数据目录:/var/lib/heketi)
	验证:
	curl http://192.168.XX.A:8083/hello
	或:
	heketi-cli --server http://192.168.XX.A:8083 cluster list
	配置节点:
	新建topology.json:
	{
	    "clusters": [
	        {
	            "nodes": [
	                {
	                    "node": {
	                        "hostnames": {
	                            "manage": [
	                                "glusterfs1"
	                            ],
	                            "storage": [
	                                "192.168.XX.A"
	                            ]
	                        },
	                        "zone": 1
	                    },
	                    "devices": [
	                        "/dev/xvde"
	                    ]
	                },
	                {
	                    "node": {
	                        "hostnames": {
	                            "manage": [
	                                "glusterfs2"
	                            ],
	                            "storage": [
	                                "192.168.XX.B"
	                            ]
	                        },
	                        "zone": 2
	                    },
	                    "devices": [
	                        "/dev/xvde"
	                    ]
	                },
	                {
	                    "node": {
	                        "hostnames": {
	                            "manage": [
	                                "glusterfs3"
	                            ],
	                            "storage": [
	                                "192.168.XX.C"
	                            ]
	                        },
	                        "zone": 1
	                    },
	                    "devices": [
	                        "/dev/xvde"
	                    ]
	                }
	            ]
	        }
	    ]
	}
	载入配置:
	export HEKETI_CLI_SERVER=http://192.168.XX.A:8083
	heketi-cli topology load --json=topology.json
	查看拓扑:
	heketi-cli topology info
	建个大小为2G的volume试试:
	heketi-cli volume create --size=2
	查看:
	heketi-cli volume list
	删除:
	heketi-cli volume delete <Id>
	2)Kubernetes创建StorageClass
	Kubernetes通过创建StorageClass来使用 Dynamic Provisioning 特性,StorageClass连接Heketi,可以根据需要自动创建GluserFS的Volume,StorageClass还是要系统管理员创建,不过StorageClass不需要每次创建,因为这个不需要很多,不同的PVC可以用同一个StorageClass。
	新建文件:
	glusterfs-storageclass.yaml:
	apiVersion: storage.k8s.io/v1beta1
	kind: StorageClass
	metadata:
	  name: slow
	provisioner: kubernetes.io/glusterfs
	parameters:
	  resturl: "http://192.168.XX.A:8083"
	  volumetype: "replicate:3"
	replicate:3代表会创建三个副本复制模式的GluserFS Volume。
	执行命令创建:
	kubectl apply -f glusterfs-storageclass.yaml
	查看:
	# kubectl get storageclass
	NAME      TYPE
	slow      kubernetes.io/glusterfs
	3)Kubernetes创建应用
	应用部署人员创建PVC及应用(还是以MySQL为例)。
	创建两个文件:
	glusterfs-pvc.yaml:
	kind: PersistentVolumeClaim
	apiVersion: v1
	metadata:
	  name: glusterfs-mysql1
	  annotations:
	    volume.beta.kubernetes.io/storage-class: "slow"
	spec:
	  accessModes:
	    - ReadWriteMany
	  resources:
	    requests:
	      storage: 1Gi
	mysql-deployment.yaml:
	apiVersion: v1
	kind: Service
	metadata:
	  name: mysql
	  labels:
	    name: mysql
	spec:
	  type: NodePort
	  ports:
	  - name: mysqlport
	    port: 3306
	    nodePort: 31016
	  selector:
	    name: mysql
	---
	apiVersion: extensions/v1beta1 
	kind: Deployment 
	metadata: 
	  name: mysql
	spec: 
	  replicas: 1
	  template: 
	    metadata: 
	      labels: 
	        name: mysql
	    spec: 
	      containers: 
	        - name: mysqlcontainer
	          image: registry.hundsun.com/library/mysql:5.7.12
	          imagePullPolicy: IfNotPresent
	          env:
	          - name: MYSQL_ROOT_PASSWORD
	            value: root12345
	          ports: 
	            - containerPort: 3306
	          volumeMounts:
	            - name: gluster-mysql-data
	              mountPath: "/var/lib/mysql"
	      volumes:
	      - name: gluster-mysql-data
	        persistentVolumeClaim:
	          claimName: glusterfs-mysql1
	执行命令创建:
	kubectl apply -f glusterfs-pvc.yaml
	kubectl apply -f mysql-deployment.yaml
	查看Endpoint、Service、PV,可以发现这些都自动建好了:
	# kubectl get ep
	NAME                                 ENDPOINTS                                                     AGE
	glusterfs-dynamic-glusterfs-mysql1   192.168.XX.A:1,192.168.XX.B:1,192.168.XX.C:1                  9s
	# kubectl get svc
	NAME                                 CLUSTER-IP       EXTERNAL-IP     PORT(S)     AGE
	glusterfs-dynamic-glusterfs-mysql1   10.254.132.6     <none>          1/TCP       42s
	# kubectl get pv
	NAME                                       CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS    CLAIM                      REASON    AGE
	pvc-f81121a0-ae8b-11e7-a91a-286ed488c82a   1Gi        RWX           Delete          Bound     default/glusterfs-mysql1             4m
	查看PVC:
	# kubectl get pvc
	NAME               STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
	glusterfs-mysql1   Bound     pvc-f81121a0-ae8b-11e7-a91a-286ed488c82a   1Gi        RWX           5m
	可以看到PV和PVC已经绑定好。
	还是可以用刚才的命令连接到MySQL:
	mysql -h 192.168.XX.A -P 31016 -uroot -proot12345
	按刚才的方式测试MySQL Pod重新调度后数据还在不在,可以发现数据还在。
	从上面可以看到手动方式需要系统管理员每次手动建GlusterFS的Volume和Kubernetes的PV,或者系统管理员事先建好一批Volume和PV;而自动方式不需要,Kubernetes可以根据应用部署人员的需要动态创建Volume和PV,节省了很多工作量,推荐使用自动方式。
	原文链接:
	https://rdc.hundsun.com/portal/article/826.html
	https://rdcqii.hundsun.com/portal/article/827.html
	声明:文章收集于网络,版权归原作者所有,为传播信息而发,如有侵权,请联系小编删除,谢谢!
 
 时间:2020-06-21 17:53 来源: 转发量:次
声明:本站部分作品是由网友自主投稿和发布、编辑整理上传,对此类作品本站仅提供交流平台,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,不为其版权负责。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。
相关文章:
相关推荐:
网友评论:
最新文章
            
        热门文章
            
        
















