1. 程式人生 > >初試 Kubernetes 叢集使用 Ceph RBD 塊儲存

初試 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 叢集節點,所以功能節點圖如下:

這裡寫圖片描述

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/[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 檔案儲存,來實現掛載分散式儲存。

參考資料