摘要

总结一下kubernetes对接Ceph过程中遇到的问题,持续更新中 ……

一、环境准备

实验环境有点特殊,先部署了一套超融合环境,openstack(M版)+ceph(L版),且全部容器化。之后在openstack平台上起了3台Centos7.1虚机,并在这3台虚机上部署了kubernete 1.9.3版本。

二、手工创建Image

找了一些资料,讲的都不是很全,所以这里先讲一下我的理解。这一步操作的目的是在ceph上创建一个块存储,然后通过内核将这个块存储映射给k8s所在的虚机,最后k8s将Pod建在这个块存储上。

所以第一步得把块存储创建出来,在ceph上执行:

rbd create foo2 --size 1024
rbd feature disable foo exclusive-lock, object-map, fast-diff, deep-flatten

之后在物理机上加载内核(Pod将起在的那台物理机上,注意是物理机,不是Node,不是kvm,也不是docker)

sudo modprobe rbd

进入Pod将起的Node(或者说kvm虚机),然后把ceph任意一个osd的/etc/ceph目录拷过来,并安装ceph(yum install ceph或其它方式),最后执行map映射

rbd map foo

检查一下结果

之后执行一下格式化

sudo mkfs.ext4 -m0 /dev/rbd0

三、创建Pod

上一步结束之后,等于已经在ceph上挂了一块盘给了k8s的某个Node节点,这一步就是要在该节点上创建Pod并mount这个盘。

先给这个Node打个tag

kubectl label nodes k8s2 zone=k8s2

从github上下载官方测试用例

git clone https://github.com/kubernetes/examples.git

修改 xxxx/cephJoint/examples/staging/volumes/rbd/rbd.yaml文件如下:

apiVersion: v1 
kind: Pod 
metadata: 
  name: busybox
  namespace: default
spec:
  nodeSelector:
    zone: k8s2
  containers:
  - name: busybox
    image: registry.cn-hangzhou.aliyuncs.com/yanfulei/busybox:latest
    volumeMounts:
      - name: rbdpd
        mountPath: /mnt/rbd
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
  restartPolicy: Always
  volumes:
    - name: rbdpd
      rbd:
        monitors:
        - '172.16.170.130:6789'
        - '172.16.170.131:6789'
        - '172.16.170.132:6789'
        pool: rbd
        image: foo
        fsType: ext4
        readOnly: true
        user: admin
        keyring: /etc/ceph/ceph.client.admin.keyring

启动Pod

kubectl create -f rbd.yaml

检查一下启动结果,大概要2分钟左右吧,取决于你前面创建的ceph块有多大,k8s会将这块盘格式化一遍,需要一些时间。

四、问题与思考

上述的挂载方式还存在一个很大的问题,简单来试一下,新创建了一个centos的pod如图:

然后再通过kubectl delete 删掉之后,我们检查一下设备,就会发现挂载到k8s2这个node上的盘已经被回收了。再次用相同的命令启动,会发现挂载失败的错误。

所以说这种对接场景下,Ceph RBD存储的生命周期和Pod是一致的,Pod被删了,数据也没了。所以在生产环境中需要有持久化的对接方式。

五、使用PV和PVC挂载Pod

具体过程不想发了,yaml到处都是,大致过程就是建一个PV,建一个PVC,最后Pod建在PVC上面。当Pod删掉之后,PV和PVC都在。重建Pod之后,容器里挂的盘依然不变,甚至容器从Centos换成ubuntu等,盘还是那个盘,盘里的东西还是原来的东西。

六、使用Kubernetes StorageClass

解决了持久化问题之后,又有一个新的需要思考的问题,生产环境中不可能手工先在ceph上建一个RBD块,再通过内核mount给Node吧,那该怎么让k8s自动调度分配存储空间?这时候就需要使用k8s的StorageClass功能了。

先创建一个StorageClass

[root@k8s1 rbd]# cat rbd-storage-class.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: rbd
provisioner: kubernetes.io/rbd
parameters:
  monitors: 172.16.170.130:6789
  adminId: admin
  adminSecretName: ceph-secret
  adminSecretNamespace: default
  pool: rbd
  userId: admin
  userSecretName: ceph-secret

再创建一个PV

[root@k8s1 rbd]# cat rbd-dyn-pv-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ceph-rbd-dyn-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: rbd
  resources:
    requests:
      storage: 1Gi

最后创建一个Pod

[root@k8s1 rbd]# cat rbd-dyn-pvc-pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: rbd-dyn-pvc-pod
  name: ceph-rbd-dyn-pv-pod1
spec:
  containers:
  - name: ceph-rbd-dyn-pv-busybox1
    image: registry.cn-hangzhou.aliyuncs.com/yanfulei/busybox
    command: ["sleep", "60000"]
    volumeMounts:
    - name: ceph-dyn-rbd-vol1
      mountPath: /mnt/ceph-dyn-rbd-pvc/busybox
      readOnly: false
  volumes:
  - name: ceph-dyn-rbd-vol1
    persistentVolumeClaim:
      claimName: ceph-rbd-dyn-pv-claim

这时候就不再依赖nodeSelector调度了,通过kubectl describe看到Pod已经被调度到了k8s3上

之后登入k8s3节点看一下容器磁盘,发现已经成功挂了一块1G的盘给Pod