目录
1、Kubernetes PersistentVolumes 介绍
Kubernetes PersistentVolumes 持久化存储方案中,提供两种 API 资源方式: PersistentVolume(简称PV) 和 PersistentVolumeClaim(简称PVC)。PV 可理解为集群资源,PVC 可理解为对集群资源的请求,Kubernetes 支持很多种持久化卷存储类型。Ceph 是一个开源的分布式存储系统,支持对象存储、块设备、文件系统,具有可靠性高、管理方便、伸缩性强等特点。在日常工作中,我们会遇到使用 k8s 时后端存储需要持久化,这样不管 Pod 调度到哪个节点,都能挂载同一个卷,从而很容易读取或存储持久化数据,我们可以使用 Kubernetes 结合 Ceph 完成。
2、环境、软件准备
本次演示环境,我是在虚拟机 Linux Centos7 上操作,通过虚拟机完成 Ceph 存储集群搭建以及 Kubernetes 集群的搭建,以下是安装的软件及版本:
注意:这里我们着重描述一下 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 配置各个字段大概的意思:
ceph osd pool ls
命令列出所有,默认创建的 pool 为 rbd,所以这里可以修改为 rbd,也可以创建一个新的名称为 kube 的 pool。rbd create ...
命令创建指定大小的映像,这里我们就创建 foouname -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 来解决这个问题。
PV 支持 Static 静态请求,即提前准备好固定大小的资源。同时支持 Dynamic 动态请求,当静态 PV 不能满足需求时,k8s 集群可以提供动态分配的方式,但是需要配置 StorageClasses。k8s 支持的 PV 类型有很多,官网列出的有如下类型:
其中就有我们熟悉的 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 文件存储,来实现挂载分布式存储。
参考资料