β

kubernetes持久化存储Ceph RBD

奇虎360-addops 21 阅读

最近在调研kubernetes持久化存储,准备写一两篇关于这方面的文章,一是作为记录,二是可以给需要的同学作为一个参考。

kubernetes存储的应用场景

kubernetes中对于存储的使用主要集中在以下几个方面:

kubernetes持久化概念

kubernetes使用两种API资源来管理存储。分别是PersistentVolume和PersistentVolumeClaim。下面分别介绍下这两种资源的概念。

kubernetes可以使用三种方式来访问存储资源。

该种方式移植性比较差,可扩展能力差,把Volume的基本信息完全暴露给用户,有安全隐患。

systemd

集群管理员创建一些PV。它们带有可供集群用户使用的实际存储的细节。之后便可用于PVC消费。(注意: 这种方式请求的PVC必须要与管理员创建的PV保持一致,如: 存储大小和访问模式)。否则不会将PVC绑定到PV上。

systemd

当管理员创建的静态PV都不匹配用户的PVC,集群可以使用动态的为PVC创建卷。此配置基于StorageClass。PVC请求存储类(StorageClass),并且管理员必须要创建并配置该StorageClass,该StorageClass才能进行动态的创建。

systemd

kubernetes数据持久化demo

好了,上面已经对kubernetes持久化要用的概念进行了介绍,但是这些只是基本的概念,如果想要系统的了解请看官方文档:)

在实验前,你需要有一个可以使用的kubernetes和ceph集群,这里不介绍这两个集群的搭建了。 进行试验前最好先看下官方文档 persistent-volumes

实验环境

kubernetes集群版本:1.9.0 ceph集群版本:10.2.10

安装 ceph-common 包

在kubernetes集群的所有Node上安装ceph-common包,具体的操作指令如下:

# yum install -y ceph-common

静态PV

创建ceph secret

在ceph mon节点运行 ceph auth get-key client.admin 命令获取admin的key。定义一个ceph secret文件。

apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret
data:
  key: QVFBOFF2SlZheUJQRVJBQWgvS2cwT1laQUhPQno3akZwekxxdGc9PQ==

注意: 文件中的key需要在ceph mon节点使用 ceph auth get-key client.admin | base64 命令对获取的key进行base64。

保存定义的文件,如 ceph-secret.yaml , 之后创建一个secret:

# kubectl create -f ceph-secret.yaml 
secret "ceph-secret" created
创建Persistent Volume

创建一个PV对象,使用下面文件的定义:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: ceph-pv 
spec:
  capacity:
    storage: 2Gi 
  accessModes:
    - ReadWriteOnce 
  rbd: 
    monitors: 
      - mon-hosts:6789
    pool: rbd 
    image: ceph-image
    user: admin
    secretRef:
      name: ceph-secret 
    fsType: ext4 
    readOnly: false
  persistentVolumeReclaimPolicy: Recycle

注意: 我们这里直接使用了ceph默认的pool rbd, 由于文件中使用了ceph-image,所以需要在ceph集群中创建该镜像。 rbd create ceph-image -s 128

保存定义的PV文件,如ceph-pv.yaml,并创建一个PV:

# kubectl create -f ceph-pv.yaml
persistentvolume "ceph-pv" created

查看PV的状态是否正常,如果获取的状态是Available则说明该PV处于可用状态,并且没有被PVC绑定。

# kubectl get pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                     STORAGECLASS   REASON    AGE
ceph-pv     1Gi        RWO            Recycle          Available                                                      56s
创建Persistent Volume Claim

PVC需要指定访问模式和存储的大小,当前只支持这两个属性,一个PVC绑定到一个PV上。一旦PV被绑定到PVC上就不能被其它的PVC所绑定。它们是一对一的关系。但是多个Pod可以使用同一个PVC进行卷的挂载。

PVC的定义文件如下:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: ceph-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

保存定义的文件,并基于该文件创建PVC,并检查其状态,如果状态为Bound则说明该PVC已经绑定到PV,如果状态为Pending或Failed则表示PVC绑定PV失败,可用通过查看PVC事件或者kubernetes各个组件日志进行错误排查。

#  kubectl create -f task-claim.yaml
persistentvolumeclaim "ceph-claim" created
# kubectl get pvc
NAME              STATUS    VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ceph-claim        Bound     ceph-pv     1Gi        RWO                           6s
创建Pod

定义一个Pod,在Pod里面启动一个container,并使用PVC去挂载Ceph RBD卷为读写模式。

apiVersion: v1
kind: Pod
metadata:
  name: ceph-pod2           
spec:
  containers:
  - name: ceph-busybox
    image: busybox          
    command: ["sleep", "60000"]
    volumeMounts:
    - name: ceph-vol1       
      mountPath: /usr/share/busybox 
      readOnly: false
  volumes:
  - name: ceph-vol1         
    persistentVolumeClaim:
      claimName: ceph-claim

保存Pod的定义文件,如: ceph-pod.yaml。并创建该Pod。之后查看Pod的状态,如果Running则表示卷挂载成功,Pod正常运行。 这样便可以做个简单的操作,进行到该Pod的容器中,向 /usr/share/busybox 目录写入一些数据,之后删除该Pod,在创建一个新的Pod,看之前的数据是否还存在:)

#kubectl create -f ceph-pod.yaml 
pod "ceph-pod2" created
kubectl get pods -o wide
NAME                                READY     STATUS    RESTARTS   AGE       IP              NODE
ceph-pod2                           1/1       Running   0          20s       10.139.54.211   app31.add.bjdt.qihoo.net

动态PV

创建RBD pool

虽然ceph提供了默认的pool rbd,但是建议创建一个新的pool为kubernetes持久化使用。在ceph的monitors节点创建一个名为 kube 的pool.

# ceph osd pool create kube 1024
# ceph auth get-or-create client.kube mon 'allow r' osd 'allow class-read object_prefix rbd_children, allow rwx pool=kube' -o ceph.client.kube.keyring
创建ceph secret

与静态创建的ceph-secret是同一个,这里就不在重复创建。

创建kube用户的ceph secret

在ceph monitors节点运行命令 ceph auth get-key client.kube 获取kube用户的key。并对该用户key进行base64用于下面的文件。

apiVersion: v1
kind: Secret
metadata:
  name: ceph-kube-secret
  namespace: default
data:
  key: QVFCbEV4OVpmaGJtQ0JBQW55d2Z0NHZtcS96cE42SW1JVUQvekE9PQ== 
type:
  kubernetes.io/rbd

保存定义的ceph secret文件,如ceph-kube-secret.yaml。执行如下命令创建secret:

# kubectl create -f ceph-kube-secret.yaml 
secret "ceph-kube-secret" created

查看secret是否创建成功。

# kubectl get secret ceph-kube-secret
NAME               TYPE                DATA      AGE
ceph-kube-secret   kubernetes.io/rbd   1         2m
创建动态RBD StorageClass

在创建StorageClass资源前,先介绍下StorageClass的概念: StorageClass 为管理员提供了描述存储 class 的方法。 不同的 class 可能会映射到不同的服务质量等级或备份策略,或由群集管理员确定的任意策略。 Kubernetes 本身不清楚各种 class 代表的什么。这个概念在其他存储系统中有时被称为“配置文件”。StorageClass不仅仅使用与ceph RBD还可以用于 Cinder , NFS , Glusterfs 等等。

好了,下面我们来创一个动态的storage class。定义文件如下:

kind: StorageClass
metadata:
  name: dynamic
  annotations:
     storageclass.beta.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/rbd
parameters:
  monitors: 10.139.206.209:6789
  adminId: admin
  adminSecretName: ceph-secret
  adminSecretNamespace: kube-system
  pool: kube
  userId: kube
  userSecretName: ceph-kube-secret
  fsType: ext4
  imageFormat: "1"

保存文件,并创建storage class。

# kubectl create -f rbd-storage-class.yaml 
storageclass "dynamic" created

检查storage class是否创建成功。

# kubectl get storageclass
NAME                PROVISIONER         AGE
dynamic (default)   kubernetes.io/rbd   54s
创建Persistent Volume Claim

具体的描述细节请看创建静态PV时,对PVC的描述。或查看官方文档。下面我们直接定义PVC文件。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: ceph-claim
spec:
  accessModes:
    rs ReadOnlyMany
  resources:
    requests:
      storage: 1Gi

保存定义的文件,并创建该PVC。

# kubectl create -f static-ceph-pvc.yaml 
persistentvolumeclaim "ceph-claim" created

检查PVC是否创建成功,并查看PVC的状态,如果PVC的状态为Bound则表示已经绑定到PV了。这里详细的说下,在kubernetes中一个指定访问模式和存储大小的PVC只能绑定到指定访问权限和存储大小的PV上,但是这样需要集群管理员手动的创建PV。这样就很麻烦,为了减少管理员的工作。管理员可以创建一个storageclass的资源,当指定规格的PVC请求的时候,StorageClass会动态的给该PVC提供一个PV。 我们查看下该PVC是否被该StorageClass绑定一个符合需求的PV上。我们执行下面的命令:

# kubectl get pvc
NAME              STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
ceph-claim        Bound     pvc-c32aca7e-38cd-11e8-af69-f0921c10a7bc   1Gi        ROX            dynamic        6s

我们看到 ceph-claim 这个PVC已经绑定到了 pvc-c32aca7e-38cd-11e8-af69-f0921c10a7bc 这个PV,而该PV是由名为 dynamic 的storageclass动态创建的。

创建Pod

我们定义一个Pod来将刚刚创建的PVC挂载到该Pod的容器中去。我们定义的Pod的文件内容如下:

apiVersion: v1
kind: Pod
metadata:
  name: static-ceph-pod2
spec:
  containers:
  - name: ceph-busybox
    image: busybox
    command: ["sleep", "60000"]
    volumeMounts:
    - name: ceph-vol1
      mountPath: /usr/share/busybox
      readOnly: false
  volumes:
  - name: ceph-vol1
    persistentVolumeClaim:
      claimName: ceph-claim

保存定义Pod的文件,我们创建一个Pod:

# kubectl get pod static-ceph-pod2 
NAME               READY     STATUS    RESTARTS   AGE
static-ceph-pod2   1/1       Running   0          40s

ok, 已经成功的将该PVC挂载到了Pod中的容器中。

总结

好了,到此为止,我们已经介绍了如何将kubernetes与ceph RBD关联起来,实现将被kubernetes编排的服务数据持久化。我们分别对静态PV和动态PV分别进行了实验,但是ceph RBD也有自己的缺点。

在说明ceoh RBD缺点之前,先介绍下PV的访问模式,PV支持三种访问模式。

模式包括:

但是ceph RBD只能进行单节点读写或多节点读,不能进行多节点读写,如下图所示:

systemd

但是有的业务可能需要多节点读写的功能,正好cephfs解决了这个问题,下篇文章我会介绍下cephfs如何与kubernetes结合实现数据持久化存储。

参考

https://www.kubernetes.org.cn/3462.html https://kubernetes.io/docs/concepts/storage/persistent-volumes/ https://github.com/kubernetes-incubator/external-storage/tree/master/ceph/rbd/examples

作者:奇虎360-addops
应用运维|运维开发|opsdev|addops|虚拟化|openstack|docker|容器化|k8s|智能运维
原文地址:kubernetes持久化存储Ceph RBD, 感谢原作者分享。

发表评论