您的位置:首页 > 其它

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

2018-01-08 10:03 1186 查看
目录

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 集群的搭建,以下是安装的软件及版本:

Centos:release 7.4.1708 (Core)

Ceph:jewel-10.2.10

Kubernetes:v1.6.2

Docker:v1.12.6

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



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.yaml、rbd.yaml 和 ceph-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
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 示例
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息