初试 Kubernetes 集群使用 Ceph RBD 块存储

目录

  • Kubernetes PersistentVolumes 介绍
  • 环境、软件准备
  • 单节点使用 Ceph RBD
  • Kubernetes PV & PVC 方式使用 Ceph RBD
  • 测试单节点以及多节点使用 Ceph RBD

1、Kubernetes PersistentVolumes 介绍

Kubernetes PersistentVolumes 持久化存储方案中,提供两种 API 资源方式: PersistentVolume(简称PV) 和 PersistentVolumeClaim(简称PVC)。PV 可理解为集群资源,PVC 可理解为对集群资源的请求,Kubernetes 支持很多种持久化卷存储类型。Ceph 是一个开源的分布式存储系统,支持对象存储、块设备、文件系统,具有可靠性高、管理方便、伸缩性强等特点。在日常工作中,我们会遇到使用 k8s 时后端存储需要持久化,这样不管 Pod 调度到哪个节点,都能挂载同一个卷,从而很容易读取或存储持久化数据,我们可以使用 Kubernetes 结合 Ceph 完成。

2、环境、软件准备

本次演示环境,我是在虚拟机 Linux Centos7 上操作,通过虚拟机完成 Ceph 存储集群搭建以及 Kubernetes 集群的搭建,以下是安装的软件及版本:

  1. Centos:release 7.4.1708 (Core)
  2. Ceph:jewel-10.2.10
  3. Kubernetes:v1.6.2
  4. Docker:v1.12.6

注意:这里我们着重描述一下 Kubernetes 集群如何使用 Ceph RBD 来实现持久化存储,所以需要提前搭建好 Kubernetes 集群和 Ceph 存储集群,具体搭建过程可参考之前文章 国内使用 kubeadm 在 Centos 7 搭建 Kubernetes 集群 和 初试 Centos7 上 Ceph 存储集群搭建,这里就不在详细讲解了。同时由于本机内存限制,共开启了 3 个虚拟机节点,每个节点既是 Ceph 集群节点又是 Kubernetes 集群节点,所以功能节点图如下:

初试 Kubernetes 集群使用 Ceph RBD 块存储_第1张图片

3、单节点使用 Ceph RBD

在正式开始之前,要提一下的是,为了方便后续测试 k8s 跨节点使用 RBD,这里我们先只使用 admin 和 node0,这样就将所有的 Pod 都调度到 node0 上执行,方便演示单节点使用 RBD,后续跨节点操作时使用 kubeadm join ... 命令将 node1 加入到集群中即可。

k8s 集群单节点使用 Ceph RBD,我们可以使用 Kubernetes Examples Github 官方示例代码,稍加修改即可。

$ cd /home/wanyang3/k8s
$ git clone https://github.com/kubernetes/examples.git
$ tree examples/staging/volumes/rbd
|-- rbd-with-secret.yaml
|-- rbd.yaml
|-- README.md
`-- secret
    `-- ceph-secret.yaml

可以看到,官方示例代码中提供了 rbd-with-secret.yamlrbd.yamlceph-secret.yaml 三个文件。我们知道,在搭建 Ceph 集群时,默认开启了 cephx 安全认证的,所以在 k8s 集群使用 Ceph RBD 时,也是要配置认证信息的,下边我分别演示下如何配置安全认证信息。

3.1 使用 rbd.yaml

$ cat examples/staging/volumes/rbd/rbd.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: rbd
spec:
  containers:
    - image: kubernetes/pause
      name: rbd-rw
      volumeMounts:
      - name: rbdpd
        mountPath: /mnt/rbd
  volumes:
    - name: rbdpd
      rbd:
        monitors:
        - '10.16.154.78:6789'
        - '10.16.154.82:6789'
        - '10.16.154.83:6789'
        pool: kube
        image: foo
        fsType: ext4
        readOnly: true
        user: admin
        keyring: /etc/ceph/keyring
        imageformat: "2"
        imagefeatures: "layering"

简要说明一下 volumes 下 rbd 配置各个字段大概的意思:

  • monitors:这是 Ceph 集群的 monitor 监视器,Ceph 集群可以配置多个 monitor,如有多多个配置所有,本次我们搭建的 Ceph 集群只有一个 monitor,所以这里需要修改为 10.222.76.119:6789
  • pool:这是 Ceph 集群中存储数据进行归类区分使用,可使用 ceph osd pool ls 命令列出所有,默认创建的 pool 为 rbd,所以这里可以修改为 rbd,也可以创建一个新的名称为 kube 的 pool。
  • image:这是 Ceph 块设备中的磁盘映像文件,可使用 rbd create ... 命令创建指定大小的映像,这里我们就创建 foo
  • fsType:文件系统类型,默认使用 ext4 即可。
  • readOnly:是否为只读,这里测试使用只读即可。
  • user:这是 Ceph Client 访问 Ceph 存储集群所使用的用户名,这里我们使用 admin 即可。
  • keyring:这是 Ceph 集群认证需要的密钥环,记得搭建 Ceph 存储集群时生成的 ceph.client.admin.keyring 么,就是这个文件。
  • imageformat:这是磁盘映像文件格式,可以使用 2,或者老一些的 1
  • imagefeatures: 这是磁盘映像文件的特征,需要 uname -r 查看集群系统内核所支持的特性,这里我们安装的 Ceontos7 内核版本为 3.10.0-693.5.2.el7.x86_64 只支持 layering。

好了,那么我们将 rbd.yaml 文件修改如下:

apiVersion: v1
kind: Pod
metadata:
  name: rbd1
spec:
  containers:
    - image: kubernetes/pause
      name: rbd-rw
      volumeMounts:
      - name: rbdpd
        mountPath: /mnt/rbd
  volumes:
    - name: rbdpd
      rbd:
        monitors:
        - '10.222.76.119:6789'
        pool: rbd
        image: foo
        fsType: ext4
        readOnly: true
        user: admin
        keyring: /etc/ceph/keyring
        imageformat: "2"
        imagefeatures: "layering"

不过,在执行创建该 Pod 之前,需要先手动创建 Image foo,否则创建 Pod 会报错。这里我就不在详细描述过程了,具体可以参照文章 初试 Ceph 存储之块设备、文件系统、对象存储 中块设备部分,贴下操作代码。

# 创建一个大小为 1024M 的 ceph image
$ rbd create foo --size 1024
$ rbd list
foo
# 临时关闭内核不支持的特性
$ rbd feature disable foo exclusive-lock, object-map, fast-diff, deep-flatten
$ rbd info foo
rbd image 'foo':
    size 1024 MB in 256 objects
    order 22 (4096 kB objects)
    block_name_prefix: rbd_data.10602ae8944a
    format: 2
    features: layering
    flags:

# 把 foo image 映射到内核
$ sudo rbd map foo
/dev/rbd0
$ rbd showmapped
id pool image snap device    
0  rbd  foo   -    /dev/rbd0

# 将 foo image 格式化为 ext4 格式的文件系统,注意这里也可以不执行,后边创建 Pod 时也会自动完成
$ sudo mkfs.ext4 -m0 /dev/rbd0

我们期望的是,下边创建的 Pod 会将该块设备挂载到 /mnt/rbd 目录,不过在创建前还有一步不要忘记了,那就是去 k8s 节点上生成 keyring 密钥文件,否则是连接不上 Ceph 存储集群的,执行时会报错如下。

 1s 1s  1   kubelet, node0      Warning FailedMount MountVolume.SetUp failed for volume "kubernetes.io/rbd/57437366-f05d-11e7-b073-080027ee5979-rbdpd" (spec.Name: "rbdpd") pod "57437366-f05d-11e7-b073-080027ee5979" (UID: "57437366-f05d-11e7-b073-080027ee5979") with: rbd: map failed exit status 22 rbd: sysfs write failed
2018-01-03 16:09:02.753112 7faa5534dd80  0 librados: client.admin authentication error (22) Invalid argument
rbd: couldn't connect to the cluster!

所以,我们要去 node0 节点生成 keyring (因为现在是单节点测试,pod 只会被调度到 node0,后续加入node1 时也需要生成 keyring),同时这里 node0 既是 Ceph 集群 osd 节点又是 k8s 节点,所以已存在该文件,复制一份即可,

$ cp /etc/ceph/ceph.client.admin.keyring /etc/ceph/keyring

好了,现在可以创建使用 Ceph RBD 作为后端存储的 Pod 啦!

$ kubectl create -f rbd.yaml
pod "rbd1" created
$ kubectl get pod
NAME      READY     STATUS    RESTARTS   AGE
rbd1      1/1       Running   0          13s

接下来我们去 node0 上验证一下是否正确启动并挂载该 Ceph rbd 吧!

# node0 节点上执行
$ docker ps
CONTAINER ID        IMAGE                                                                                                COMMAND                  CREATED             STATUS              PORTS               NAMES
070605ea0186        docker.io/kubernetes/pause@sha256:2088df8eb02f10aae012e6d4bc212cabb0ada93cb05f09e504af0c9811e0ca14   "/pause"                 3 minutes ago      Up 3 minutes                           k8s_rbd-rw_rbd1_default_edc7712b-f057-11e7-b073-080027ee5979_0

# 查看节点挂载信息 
$ mount | grep /dev/rbd0
/dev/rbd0 on /var/lib/kubelet/plugins/kubernetes.io/rbd/rbd/rbd-image-foo type ext4 (ro,relatime,stripe=1024,data=ordered)
/dev/rbd0 on /var/lib/kubelet/pods/edc7712b-f057-11e7-b073-080027ee5979/volumes/kubernetes.io~rbd/rbdpd type ext4 (ro,relatime,stripe=1024,data=ordered) 

# 容器挂载信息
# docker inspect 070605ea0186
...
"Mounts": [
            {
                "Source": "/var/lib/kubelet/pods/edc7712b-f057-11e7-b073-080027ee5979/volumes/kubernetes.io~rbd/rbdpd",
                "Destination": "/mnt/rbd",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Source": "/var/lib/kubelet/pods/edc7712b-f057-11e7-b073-080027ee5979/volumes/kubernetes.io~secret/default-token-b177v",
                "Destination": "/var/run/secrets/kubernetes.io/serviceaccount",
                "Mode": "ro",
                "RW": false,
                "Propagation": "rprivate"
            },
            {
                "Source": "/var/lib/kubelet/pods/edc7712b-f057-11e7-b073-080027ee5979/etc-hosts",
                "Destination": "/etc/hosts",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Source": "/var/lib/kubelet/pods/edc7712b-f057-11e7-b073-080027ee5979/containers/rbd-rw/ff5f0f93",
                "Destination": "/dev/termination-log",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

3.2 使用 rbd-with-secret & ceph-secret

接下来使用 rbd-with-secret 和 ceph-secret 方式,这种方式跟上边直接使 keyring 文件认证最大的区别就是使用 k8s secret 对象,该 secret 对象用于 k8s volume 插件通过 cephx 认证访问 ceph 存储集群。不过要提一下的是,k8s secret 认证 key 需要使用 base64 编码。

# 获取 Ceph keying 并生成 secret key
$ grep key /etc/ceph/ceph.client.admin.keyring |awk '{printf "%s", $NF}'|base64
QVFBM1QweGFKTFVVSFJBQUZrU3dpV08rNGM0Wjh1dUNlVHdMSUE9PQ==

或者

$ ceph auth get-key client.admin |base64
QVFBM1QweGFKTFVVSFJBQUZrU3dpV08rNGM0Wjh1dUNlVHdMSUE9PQ==

修改 ceph-secret.yaml 文件中,key 字段替换成上边生成的字符串。

$ cat ceph-secret.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: ceph-secret
type: "kubernetes.io/rbd"  
data:
  key: QVFBM1QweGFKTFVVSFJBQUZrU3dpV08rNGM0Wjh1dUNlVHdMSUE9PQ==

创建名称为 ceph-secret 的 Secret。

$ kubectl create -f ceph-secret.yaml 
secret "ceph-secret" created
$ kubectl get secret
NAME                  TYPE                                  DATA      AGE
ceph-secret           kubernetes.io/rbd                     1         24s

接下来,需要修改一下 rbd-with-secret.yaml 文件,主要修改 rbd 相关信息,修改完成后如下。

$ cat rbd-with-secret.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: rbd2
spec:
  containers:
    - image: kubernetes/pause
      name: rbd-rw
      volumeMounts:
      - name: rbdpd
        mountPath: /mnt/rbd
  volumes:
    - name: rbdpd
      rbd:
        monitors: 
        - '10.222.76.119:6789'
        pool: rbd
        image: foo
        fsType: ext4
        readOnly: true
        user: admin
        secretRef:
          name: ceph-secret

我们看到跟上边不使用 secret 的最大区别就是将 keyring 修改为 secretRef 指向创建的 ceph-secret。接下来创建该 Pod 啦!

$ kubectl create -f rbd-with-secret.yaml 
pod "rbd2" created

$ kubectl get pod
NAME      READY     STATUS    RESTARTS   AGE
rbd2      1/1       Running   0          58s

跟上边示例一样,妥妥没问题,可以去 node0 上查看 mount 信息验证一下,这里就不在演示了。

4、Kubernetes PV & PVC 方式使用 Ceph RBD

上边我们演示了单节点 k8s volume 使用 Ceph RBD 存储,但是实际应用中不会这么简单,一旦 Pod 删除掉,那么挂载 volume 中的数据就不会存在了,那是因为 volume 跟 pod 的生命周期是一样的。那么有什么办法可以解决呢? 也就是即使 pod 被删除,volume 中的数据依旧存在。为此,k8s 提供了两种 API 资源方式:PersistentVolume 和 PersistentVolumeClaim 来解决这个问题。

  • PersistentVolume (PV) 可以理解为在集群中已经由管理员配置的一块存储,作为集群的资源,而且拥有独立与 Pod 的生命周期,意思就是 Pod 删除了,但 PV 还在,PV 上的数据依旧存在。
  • PersistentVolumeClaim (PVC) 可以理解为用户对存储资源的请求,跟 Pod 类似,Pod 消耗节点资源,PVC 消耗 PV 资源,Pod 可以配置请求分配特定大小的资源,比如 CPU、内存,PVC 可以配置请求特定大小资源和访问方式,比如 RWO(ReadWriteOnce) ROX( ReadOnlyMany) RWX(ReadWriteMany)。

PV 支持 Static 静态请求,即提前准备好固定大小的资源。同时支持 Dynamic 动态请求,当静态 PV 不能满足需求时,k8s 集群可以提供动态分配的方式,但是需要配置 StorageClasses。k8s 支持的 PV 类型有很多,官网列出的有如下类型:

  • GCEPersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • FC (Fibre Channel)
  • FlexVolume
  • Flocker
  • NFS
  • iSCSI
  • RBD (Ceph Block Device)
  • CephFS
  • Cinder (OpenStack block storage)
  • Glusterfs
  • VsphereVolume
  • Quobyte Volumes
  • HostPath (Single node testing only – local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
  • VMware Photon
  • Portworx Volumes
  • ScaleIO Volumes
  • StorageOS

其中就有我们熟悉的 Ceph RBD 和 CephFS,接下来就演示一下如何使用 PV & PVC 结合 Ceph RBD 完成上边演示操作。

4.1 创建测试 Image

首先跟上边一样创建一个测试使用的 Image 命名为 ceph-rbd-pv-test ,大小为 1024 M 测试够用即可。

# 创建一个大小为 1024M 的 ceph image
$ rbd create ceph-rbd-pv-test --size 1024
# rbd list
ceph-rbd-pv-test
foo

# 临时关闭内核不支持的特性
$ rbd feature disable ceph-rbd-pv-test exclusive-lock, object-map, fast-diff, deep-flatten
$ rbd info ceph-rbd-pv-test
rbd image 'ceph-rbd-pv-test':
    size 1024 MB in 256 objects
    order 22 (4096 kB objects)
    block_name_prefix: rbd_data.10812ae8944a
    format: 2
    features: layering
    flags: 

# 把 ceph-rbd-pv-test image 映射到内核
$ sudo rbd map ceph-rbd-pv-test
/dev/rbd1

# rbd showmapped
id pool image            snap device    
0  rbd  foo              -    /dev/rbd0 
1  rbd  ceph-rbd-pv-test -    /dev/rbd1 

4.2 创建 PV

还记得上边提过 Ceph 认证的 secret,这里也是需要的,这次就不用再创建了,直接复用上边的即可。新建 PV 文件 rbd-pv.yaml 如下:

$ vim rbd-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: ceph-rbd-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  rbd:
    monitors:
      - 10.222.76.119:6789
    pool: rbd
    image: ceph-rbd-pv-test
    user: admin
    secretRef:
      name: ceph-secret
    fsType: ext4
    readOnly: false
  persistentVolumeReclaimPolicy: Recycle

这里就不在一一解释每个字段了,直接创建 PV Pod。

$ kubectl create -f rbd-pv.yaml 
persistentvolume "ceph-rbd-pv" created
$ kubectl get pv
NAME          CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
ceph-rbd-pv   1Gi        RWO           Recycle         Available                                      13s

4.3 创建 PVC

好了,上边 PV 资源已经创建好了,接下来创建对资源的请求 PVC,新建 PVC 文件 rbd-pv-claim.yaml 如下:

$ vim rbd-pv-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ceph-rbd-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

PVC 很简单,只需指定 accessModes(这里使用 ReadWriteOnce,k8s 对 RBD 只支持 ReadWriteOnce 和 ReadOnlyMany,因为接下来验证测试需要写入文件,所以使用 ReadWriteOnce 即可)和对资源的请求大小即可,那么就创建一下 PVC Pod。

$ kubectl create -f rbd-pv-claim.yaml 
persistentvolumeclaim "ceph-rbd-pv-claim" created
$ kubectl get pvc
NAME                STATUS    VOLUME        CAPACITY   ACCESSMODES   STORAGECLASS   AGE
ceph-rbd-pv-claim   Bound     ceph-rbd-pv   1Gi        RWO 

4.4 创建挂载 RBD 的 Pod

PV 和 PVC 都创建好了,接下来就需要创建挂载该 RBD 的 Pod 了,这里我使用官方示例中的 busybox 容器测试吧!新建 Pod 文件 rbd-pvc-pod1.yaml 如下:

$ vim rbd-pvc-pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: rbd-pvc-pod
  name: ceph-rbd-pv-pod1
spec:
  containers:
  - name: ceph-rbd-pv-busybox
    image: busybox
    command: ["sleep", "60000"]
    volumeMounts:
    - name: ceph-rbd-vol1
      mountPath: /mnt/ceph-rbd-pvc/busybox
      readOnly: false
  volumes:
  - name: ceph-rbd-vol1
    persistentVolumeClaim:
      claimName: ceph-rbd-pv-claim

从文件可以看出,我们要将上边创建的 ceph-rbd-pv-claim 请求的资源挂载到容器的 /mnt/ceph-rbd-pvc/busybox 目录。接下来创建一下该 Pod,看是否能够正常运行吧!

$ kubectl create -f rbd-pvc-pod1.yaml 
pod "ceph-rbd-pv-pod1" created
$ kubectl get pod
NAME               READY     STATUS    RESTARTS   AGE
ceph-rbd-pv-pod1   1/1       Running   0          19s
rbd1               1/1       Running   0          1h

等待一段时间后(因为他要执行 ext4 格式化以及挂载路径)容器就运行起来啦!那到底有没有真正挂载到容器内部指定位置呢?我们可以登录到 node0 查看一下。

# node0 节点上操作
$ docker ps
CONTAINER ID        IMAGE                                                                                                COMMAND                  CREATED              STATUS              PORTS               NAMES
65cde9254c64        docker.io/busybox@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0            "sleep 60000"            About a minute ago   Up About a minute                       k8s_ceph-rbd-pv-busybox_ceph-rbd-pv-pod1_default_1c5f5d10-f06a-11e7-b073-080027ee5979_0

$ docker exec -it 65cde9254c64 df -h |grep /dev/rbd1
Filesystem                Size      Used Available Use% Mounted on
/dev/rbd1               975.9M      2.5M    906.2M   0% /mnt/ceph-rbd-pvc/busybox

$ docker exec -it 65cde9254c64 mount |grep /dev/rbd1
/dev/rbd1 on /mnt/ceph-rbd-pvc/busybox type ext4 (rw,relatime,stripe=1024,data=ordered)

OK 我们可以看到的确将映射的 /dev/rbd1 挂载到 /mnt/ceph-rbd-pvc/busybox 目录,大小为 1G 左右。

5、测试单节点以及多节点使用 Ceph RBD

接下来我们要进行一下测试,分别测试同一节点上和不同节点上,Pod 之间是否能够共享同一个 Ceph RBD 存储。

5.1 单节点测试

我们继续使用上边演示 PV & PVC 方式创建的测试 Pod,写入一些数据到 RBD 存储中,然后删除该 Pod,创建一个新的 Pod,使用相同的 PVC 并挂载同样的目录,看能否读取到写入的数据。注意:此时还未加入 node1,所有所有创建的 Pod 都会被调度到 node0,从而实现单节点测试。

# node0 执行,往 pod ceph-rbd-pv-pod1 容器的挂载目录写入测试数据
$ docker exec -it 65cde9254c64 touch /mnt/ceph-rbd-pvc/busybox/ceph-rbd-test.txt
$ docker exec -it 65cde9254c64 vi /mnt/ceph-rbd-pvc/busybox/ceph-rbd-test.txt
$ docker exec -it 65cde9254c64 cat /mnt/ceph-rbd-pvc/busybox/ceph-rbd-test.txt
This is ceph rbd test file.

写入完毕,接下来我们删除 ceph-rbd-pv-pod1 该 Pod,同时可以查看下创建的 PV 和 PVC 是否会受到影响。

# 删除 Pod
$ kubectl delete -f rbd-pvc-pod.yaml 
pod "ceph-rbd-pv-pod1" deleted

# 查看 PV 和 PVC 是否存在
$ kubectl get pv,pvc
NAME             CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS    CLAIM                       STORAGECLASS   REASON    AGE
pv/ceph-rbd-pv   1Gi        RWO           Recycle         Bound     default/ceph-rbd-pv-claim   

NAME                    STATUS    VOLUME        CAPACITY   ACCESSMODES   STORAGECLASS   AGE
pvc/ceph-rbd-pv-claim   Bound     ceph-rbd-pv   1Gi        RWO     

OK 从上边可以看到当删除 Pod 后,对应的 PV 和 PVC 依旧存在,并没有随着 Pod 删除而消失。也就是当再次创建原 Pod 或新 Pod 时可以继续使用该 PVC,那么我们就创建一个新的 Pod,使用该 PVC 并挂载同一目录,查看测试数据是否存在吧!新建 Pod 文件 rbd-pvc-pod2.yaml 如下:

# vim rbd-pvc-pod2.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: rbd-pvc-pod
  name: ceph-rbd-pv-pod2
spec:
  containers:
  - name: ceph-rbd-pv-busybox2
    image: busybox
    command: ["sleep", "60000"]
    volumeMounts:
    - name: ceph-rbd-vol2
      mountPath: /mnt/ceph-rbd-pvc/busybox
      readOnly: false
  volumes:
  - name: ceph-rbd-vol2
    persistentVolumeClaim:
      claimName: ceph-rbd-pv-claim

从文件可以看出,我们使用了同一个 ceph-rbd-pv-claim 并且将请求的资源挂载到容器的 /mnt/ceph-rbd-pvc/busybox 同一个目录,接下来创建一下该 Pod。

$ kubectl create -f rbd-pvc-pod2.yaml 
pod "ceph-rbd-pv-pod2" created

$ kubectl get pods
NAME               READY     STATUS    RESTARTS   AGE
ceph-rbd-pv-pod2   1/1       Running   0          26s
rbd1               1/1       Running   0          1h

创建成功,登录到 node0 验证一下是否能够读取到测试文件吧!

# node0 节点执行
$ docker ps
CONTAINER ID        IMAGE                                                                                                COMMAND                  CREATED             STATUS              PORTS               NAMES
63d648257636        docker.io/busybox@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0            "sleep 60000"            35 seconds ago      Up 34 seconds                           k8s_ceph-rbd-pv-busybox2_ceph-rbd-pv-pod2_default_d48eaaae-f06c-11e7-b073-080027ee5979_0

$ docker exec -it 63d648257636 cat /mnt/ceph-rbd-pvc/busybox/ceph-rbd-test.txt
This is ceph rbd test file.

OK 数据能够完整的被同节点的 rbd-pvc-pod2 读取到。

5.2 多节点测试

同一 node 上多个 Pod 是可以挂载同一个 Ceph RBD,接下来我们尝试下跨节点挂载同一个 Ceph RBD ,看下能不能够成功吧!此时我们加入 node1 到 k8s 集群中,然后启动多个 pod,并且挂载同一个 Ceph RBD,使 Pod 分配到不同节点上去。我们就以上边 rbd-pvc-pod1 和 rbd-pvc-pod2 为例,删除掉 Pod 并重新创建一次看看。

# node1 上执行,加入 k8s 集群
$ kubeadm join --token b87453.4c4b9e895774f3be 10.222.76.189:6443

# admin 节点查看集群所有节点
$ kubectl get node
NAME      STATUS    AGE       VERSION
admin     Ready     1h        v1.6.2
node0     Ready     1h       v1.6.2
node1     Ready     22s       v1.6.2

# 删除并重新创建一下 Pod
$ kubectl delete -f rbd-pvc-pod1.yaml
$ kubectl delete -f rbd-pvc-pod2.yaml
$ kubectl create -f rbd-pvc-pod1.yaml 
pod "ceph-rbd-pv-pod1" created
$ kubectl create -f rbd-pvc-pod2.yaml
pod "ceph-rbd-pv-pod2" created

$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                            READY     STATUS              RESTARTS   AGE       IP              NODE
default       ceph-rbd-pv-pod1                1/1       Running             0          3m        10.96.2.2       node1
default       ceph-rbd-pv-pod2                0/1       ContainerCreating   0          6s        <none>          node0  

我们看到,貌似不可行!ceph-rbd-pv-pod1 被分配到 node1 并且成功 Running 运行,ceph-rbd-pv-pod2 被分配到 node2 但是状态为 ContainerCreating。查看下 ceph-rbd-pv-pod2 出错的原因。

$ kubectl describe pod/ceph-rbd-pv-pod2
Name:       ceph-rbd-pv-pod2
Namespace:  default
Node:       node0/10.222.76.119
Start Time: Thu, 04 Jan 2018 10:31:21 +0800
Labels:     test=rbd-pvc-pod
Annotations:    <none>
Status:     Pending
IP:     
Controllers:    <none>
Containers:
  ceph-rbd-pv-busybox2:
    Container ID:   
    Image:      busybox
    Image ID:       
    Port:       
    Command:
      sleep
      60000
    State:      Waiting
      Reason:       ContainerCreating
    Ready:      False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /mnt/ceph-rbd-pvc/busybox from ceph-rbd-vol2 (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-b177v (ro)
Conditions:
  Type      Status
  Initialized   True 
  Ready     False 
  PodScheduled  True 
Volumes:
  ceph-rbd-vol2:
    Type:   PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  ceph-rbd-pv-claim
    ReadOnly:   false
  default-token-b177v:
    Type:   Secret (a volume populated by a Secret)
    SecretName: default-token-b177v
    Optional:   false
QoS Class:  BestEffort
Node-Selectors: <none>
Tolerations:    node.alpha.kubernetes.io/notReady=:Exists:NoExecute for 300s
        node.alpha.kubernetes.io/unreachable=:Exists:NoExecute for 300s
Events:
  FirstSeen LastSeen    Count   From            SubObjectPath   Type        Reason      Message
  --------- --------    -----   ----            -------------   --------    ------      -------
  25s       25s     1   default-scheduler           Normal      Scheduled   Successfully assigned ceph-rbd-pv-pod2 to node0
  25s       8s      6   kubelet, node0              Warning     FailedMount MountVolume.SetUp failed for volume "kubernetes.io/rbd/59beacee-f0f7-11e7-b073-080027ee5979-ceph-rbd-pv" (spec.Name: "ceph-rbd-pv") pod "59beacee-f0f7-11e7-b073-080027ee5979" (UID: "59beacee-f0f7-11e7-b073-080027ee5979") with: rbd: image ceph-rbd-pv-test is locked by other nodes

从输出中,我们可以明显看到 rbd: image ceph-rbd-pv-test is locked by other nodes 错误信息。说明 Ceph RBD 仅能被 k8s 中的一个 node 挂载,也就是不支持跨节点挂载同一 Ceph RBD。其实从 kubernetes 官网 Persistent Volumes 文档 中 Access Modes 部分支持 mode 列表中可以看到,rbd 只支持 ReadWriteOnce 和 ReadOnlyMany,暂时并不支持 ReadWriteMany。不过也指出 Ceph 另一种存储类型 cephfs 文件存储对三种 Mode 方式都支持。下一篇我们继续研究 Kubernetes 集群多节点挂载 CephFS 文件存储,来实现挂载分布式存储。

参考资料

  • Ceph 官网文档
  • Kubernetes Persistent Volumes 官网文档
  • Kubernetes Examples Volumes RBD Github 示例

你可能感兴趣的:(Kubernetes,ceph存储)