很抱歉,前两周我还在说没发现Kubernetes有扩展API来对接Ceph创建RBD卷,这两天翻阅文档才看到原来Kubernetes已经在1.2的Alpha中支持了,在1.4中就release这个特性。
StoragaClass
StoragaClass,从表面上看像是在Kubernetes资源中定义了一个存储的方法。官方wiki介绍如下:
Each StorageClass contains the fields provisioner and parameters, which are used when a PersistentVolume belonging to the class needs to be dynamically provisioned.The name of a StorageClass object is significant, and is how users can request a particular class. Administrators set the name and other parameters of a class when first creating StorageClass objects, and the objects cannot be updated once they are created.Administrators can specify a default StorageClass just for PVCs that don’t request any particular class to bind to: see the PersistentVolumeClaim section for details.
简单来说,每个StorageClass包括provisioner
和parameters
两个资源,当PV需要绑定动态卷的时候便会用到。
那么什么是provisioner
和parameters
?
Provisioner
Storage classes have a provisioner that determines what volume plugin is used for provisioning PVs. This field must be specified. During beta, the available provisioner types are kubernetes.io/aws-ebs and kubernetes.io/gce-pd.
Storage Classes中的provisioner字段决定着部署PV的插件。
Parameters
Storage classes have parameters that describe volumes belonging to the storage class. Different parameters may be accepted depending on the provisioner. For example, the value io1, for the parameter type, and the parameter iopsPerGB are specific to EBS. When a parameter is omitted, some default is used.
Storage Classes 的parameter字段用来描述属于该storage class的volume。不同的provisioner其参数也不同。简单来说就是存储的配置信息。
目前StorageClass也封装好了几类存储的实现方法;
- AWS
- GCE
- Glusterfs
- OpenStack Cinder
- vSphere
- Ceph RBD
- Quobyte
- Azure Disk
本文着重引用Ceph RBD的方式来做实例,环境还是写前两片文章用到的那个Ceph测试环境
Ceph RBD
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
name: ceph-chengdu
provisioner: kubernetes.io/rbd
parameters:
monitors: 192.168.68.53:6789,192.168.68.54:6789,192.168.68.57:6789
adminId: kube
adminSecretName: ceph-secret
adminSecretNamespace: kube-system
pool: kube
userId: kube
userSecretName: ceph-secret
关于Ceph的Secret可以参看以前的文章,将Ceph的keyring导入进去就好了。简单介绍下storageclass里字段的含义
-
monitors
: Ceph Monitor的地址,可以用都好分割 -
adminId
: Ceph客户端用于创建块设备的用户; -
adminSecretNamespace
:admin的namespaces -
adminSecret
:admin的SecretID -
pool
: RBD的pool存储池 -
userId
: 用于块设备映射的用户ID,默认可以和admin一致 -
userSecretName
: Ceph-Secret的ID
创建PVC
在导入StoragaClass后,就可以在创建PVC里面引用这个方法了。
{
"kind": "PersistentVolumeClaim",
"apiVersion": "v1",
"metadata": {
"name": "magine1989",
"annotations": {
"volume.beta.kubernetes.io/storage-class": "ceph-chengdu"
}
},
"spec": {
"accessModes": [
"ReadWriteOnce"
],
"resources": {
"requests": {
"storage": "10Gi"
}
}
}
}
我这里定义了一个名叫magine1989的RBD块,其容量为10G。简单看下PVC和Ceph的状态。
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
magine1989 Bound pvc-0023420f-103d-11e7-9489-52540095b1e1 10Gi RWO 3h
$ kubectl get pv
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM REASON AGE
pvc-0023420f-103d-11e7-9489-52540095b1e1 10Gi RWO Delete Bound default/magine1989 4h
$ rbd ls kube --name client.kube
kubernetes-dynamic-pvc-eca2e400-103c-11e7-b8c8-52540095b1e1
$ rbd info kube/kubernetes-dynamic-pvc-eca2e400-103c-11e7-b8c8-52540095b1e1 --name client.kube
rbd image 'kubernetes-dynamic-pvc-eca2e400-103c-11e7-b8c8-52540095b1e1':
size 10240 MB in 2560 objects
order 22 (4096 kB objects)
block_name_prefix: rb.0.c3b7.2ae8944a
format: 1
可以看到在创建pvc的时候,k8s已经帮我们在Ceph的存储池里面创建一个10G的RBD块,然后创建好PV后绑定上该PVC。这样一来用户在申请PVC的时候就更方便了,不必像以前还需要系统管理员在底层手动创建好PV在通知用户创建PVC。
StatefulSet
StatefulSet在1.5版本以前叫PetSet
,除了名字改了,API对象并没有太多变化。对于将现有老的,有状态的,需要容器化的项目,StatefulSet提供非常有效的支持。
我们知道,Deployment
和replicasets
类型可以非常快速的创建Pod副本,但是前提是这些都是无状态的应用,这对于一些有状态的应用就非常尴尬了。
目前采用StatefulSet类型的容器结合一些共享存储的方案,可以解决一些这类有状态的应用在业务pod出现漂移,业务pod扩容引发的问题。
那么采用StatefulSe的应用场景如下:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
- 有序收缩,有序删除(即从N-1到0)
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 3
volumeClaimTemplates:
- metadata:
name: test
annotations:
volume.beta.kubernetes.io/storage-class: ceph-chengdu
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 5Gi
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: magine1989
image: nginx:1.11.10
volumeMounts:
- mountPath: "/mnt/rbd"
name: test
nodeSelector:
ceph: up
这里介绍下volumeClaimTemplates
,这个主要在容器在使用volumes时候,动态创建和映射容器和PVC的关系。我这里结合StorageClass就可以实现每个应用副本对应一个Volumes。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3h
web-1 1/1 Running 0 3h
web-2 1/1 Running 0 3h
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
test-web-0 Bound pvc-a202a0dc-1042-11e7-9489-52540095b1e1 5Gi RWO 3h
test-web-1 Bound pvc-a2052fad-1042-11e7-9489-52540095b1e1 5Gi RWO 3h
test-web-2 Bound pvc-a2070608-1042-11e7-9489-52540095b1e1 5Gi RWO 3h
$ kubectl get pod web-0 -o yaml
.....
volumes:
- name: test
persistentVolumeClaim:
claimName: test-web-0
.....
这里看到POD和PVC的关系是有序的对应上的。
扩展和收缩
前面说道,对于有状态的应用扩容需要结合initcontainer来实现容器运行前的操作。inicontainer我放在后面几期文章里介绍。
这里的扩容只为证明StatefulSet在部署和收缩的时候是有序进行的。
扩展
#将刚刚的3个副本扩容至5个
$ kubectl scale statefulset web --replicas=5
#这个时候观察pod调度状态
$ kubectl get pod
web-0 1/1 Running 0 3h
web-1 1/1 Running 0 3h
web-2 1/1 Running 0 3h
web-3 0/1 ContainerCreating 0 4s
$ kubectl get pod
web-0 1/1 Running 0 3h
web-1 1/1 Running 0 3h
web-2 1/1 Running 0 3h
web-3 1/1 Running 0 10s
web-4 0/1 ContainerCreating 0 0s
$ kubectl get pod
web-0 1/1 Running 0 3h
web-1 1/1 Running 0 3h
web-2 1/1 Running 0 3h
web-3 1/1 Running 0 35s
web-4 1/1 Running 0 25s
收缩
#将刚刚的5个副本扩容至2个
$ kubectl scale statefulset web --replicas=2
#只保留了最初的2个POD
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3h
web-1 1/1 Running 0 3h
#PVC保留没有删除
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
test-web-0 Bound pvc-a202a0dc-1042-11e7-9489-52540095b1e1 5Gi RWO 4h
test-web-1 Bound pvc-a2052fad-1042-11e7-9489-52540095b1e1 5Gi RWO 4h
test-web-2 Bound pvc-a2070608-1042-11e7-9489-52540095b1e1 5Gi RWO 4h
test-web-3 Bound pvc-294b1fa7-1064-11e7-9489-52540095b1e1 5Gi RWO 7m
test-web-4 Bound pvc-294def6e-1064-11e7-9489-52540095b1e1 5Gi RWO 7m
这里发现删除StatefulSet时不会删除PVC