在K8s中创建StatefulSet

遇到的问题:  

使用Deployment创建的Pod是无状态的,当挂在Volume之后,如果该Pod挂了,Replication Controller会再run一个来保证可用性,但是由于是无状态的,Pod挂了的时候与之前的Volume的关系就已经断开了,新起来的Pod无法找到之前的Pod。但是对于用户而言,他们对底层的Pod挂了没有感知,但是当Pod挂了之后就无法再使用之前挂载的磁盘了。

解决方案

使用K8s v1.5版本推出的StatefulSet可以保留Pod的状态。

参考博客

因为Kubernetes1.5版本发布也没过多久,国内的资料相当的少,除了tonybai等大牛博客上有一些StatefulSet的资料外,只能去外网上搜索了。通过在google上搜索StatefulSet的创建方式,最终发现了一篇英文博客,链接如下。对于这种新兴框架,还是要多去google啊。

https://thenewstack.io/deploy-highly-available-wordpress-instance-statefulset-kubernetes-1-5/

如何创建

在创建StatefulSet之前需要准备的东西,值得注意的是创建顺序非常关键,创建顺序如下:

  • 1、Volume
  • 2、Persistent Volume
  • 3、Persistent Volume Claim
  • 4、Service
  • 5、StatefulSet

Volume可以有很多种类型,比如nfs、glusterfs等,我们这里使用的ceph RBD来创建。

创建Volume

sudo rbd create {volume_name} --size 1024 -m {ceph-monitor-ip} -k /etc/ceph/ceph.client.admin.keyring
//禁止掉一些rdb的feature,否则挂载会失败
rbd feature disable volume101 exclusive-lock, object-map, fast-diff, deep-flatten

创建PersistentVolume

创建pv.yaml,内容如下:

apiVersion: v1 kind: PersistentVolume metadata:
 name: {pv_name}
 labels:
 {label_key}:{label_value}
spec:
 capacity:
 storage: 1Gi
 accessModes:
 - ReadWriteOnce
 rbd:
 monitors:
 - {ceph-monitor-ip}
 pool: rbd
 image: {volume_name}
 user: admin
 secretRef:
 name: ceph-secret
 fsType: ext4
 readOnly: false
 persistentVolumeReclaimPolicy: Recycle

使用

kubectl create -f pv.yaml

来创建PV。

创建PersistentVolumeClaim

这一步非常非常的关键,因为如果创建的PVC的名称和StatefulSet中的名称没有对应上,那么StatefulSet中的Pod就肯定创建不成功,我在这一步被卡了一天之久,还好看到上面那篇外文博客,才发现PVC和StatefulSet中的命名的规律。接下来细说一下需要注意的地方。

创建pvc.yaml如下:

apiVersion: v1 kind: PersistentVolumeClaim metadata:
 name: db-mysql-0
spec:
 accessModes:
 - ReadWriteOnce
 resources:
 requests:
 storage: 1Gi

我们在这里创建了一个叫做db-mysql-0的PVC,这个名字是不是很奇怪,而且在这个yaml里并没有提到PV的名字,所以PV和PVC是怎么bound起来的呢?是通过labels标签下的key:value键值对来进行匹配的,我们在创建PV时指定了label的键值对,在PVC里通过selector可以指定label。

然后再回到这个PVC的名称定义:db-mysql-0,为什么叫这样一个看似有规律的名字呢,这里需要看一下下一小节创建StatefulSet中的yaml,首先我们看到StatefulSet的name叫mysql,设置的replicas为2个,volumeMounts和volumeClaimTemplates的name必须相同,为db,所以StatefulSet创建的第一个Pod的name应该为mysql-0,第二个为mysql-1。这里StatefulSet中的Pod与PVC之间的绑定关系是通过名称来匹配的,即:

PVC_name === volumeClaimTemplates_name + "-" + pod_name

所以这个问题就有点意思了,我们要先创建PVC,但是PVC的名称实际上是由StatefulSet来确定的。我真的是不知道K8S设计者咋想的·····而且官方文档里创建StatefulSet的例子是直接给了个yaml文件,并没有告诉说要先创建什么再创建什么。

创建Service 和 StatefulSet

在上一步中我们已经创建了名为db-mysql-0的PVC了,接下来创建一个service和statefulset,service的名称可以随意取,但是statefulset的名称已经定死了,为mysql,并且statefulset中的volumeClaimTemplates_name必须为db,volumeMounts_name也必须为db。只有这样,statefulset中的pod才能通过命名来匹配到PVC,否则会创建失败。

statefulset.yaml

apiVersion: v1 kind: Service metadata:
 name: mysql-service
 labels:
 app: mysql
spec:
 ports:
 - port: 80
 name: my-port
 clusterIP: None
 selector:
 app: mysql
---
apiVersion: apps/v1beta1 kind: StatefulSet metadata:
 name: mysql
spec:
 serviceName: "mysql-service"
 replicas: 2
 template:
 metadata:
 labels:
 app: mysql
 spec:
 terminationGracePeriodSeconds: 10
 containers:
 - name: mysqlpod
 image: mysql:latest
 ports:
 - containerPort: 80
 name: my-port
 volumeMounts:
 - name: db
 mountPath: /var/lib/mysql
 volumeClaimTemplates:
 - metadata:
 name: db
 spec:
 accessModes: [ "ReadWriteOnce" ]
 resources:
 requests:
 storage: 1Gi

运行以下命令:

kubectl create -f statefulset.yaml

就可以创建statefulset了。

本文转移开源中国-在K8s中创建StatefulSet

上一篇:苹果Mac电脑永久路由的添加 & Mac 校园网连接教程


下一篇:openvswitch 流表测试 ovs-appctl