初試 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 叢集的搭建,以下是安裝的軟體及版本:
- 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 叢集
3、單節點使用 Ceph RBD
在正式開始之前,要提一下的是,為了方便後續測試 k8s 跨節點使用 RBD,這裡我們先只使用 admin 和 node0,這樣就將所有的 Pod 都排程到 node0 上執行,方便演示單節點使用 RBD,後續跨節點操作時使用 kubeadm join ...
命令將 node1 加入到叢集中即可。
k8s 叢集單節點使用 Ceph RBD,我們可以使用
$ 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/[email protected]: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/[email protected]: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 檔案儲存,來實現掛載分散式儲存。
參考資料