初試 Kubernetes 叢集使用 CephFS 檔案儲存
目錄
- Kubernetes PersistentVolumes 介紹
- 環境、軟體準備
- 單節點使用 CephFS
- Kubernetes PV & PVC 方式使用 CephFS
- 測試跨節點使用 CephFS
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 叢集如何使用 CephFS 來實現持久化儲存,所以需要提前搭建好 Kubernetes 叢集和 Ceph 儲存叢集,具體搭建過程可參考之前文章 國內使用 kubeadm 在 Centos 7 搭建 Kubernetes 叢集
3、單節點使用 CephFS
有上一篇 初試 Kubernetes 叢集使用 Ceph RBD 塊儲存 操作的基礎,這次就更加輕車熟路了!首先我們單節點使用 CephFS,先只使用 admin 和 node0,這樣就將所有的 Pod 都排程到 node0 上執行。
k8s 叢集單節點使用 CephFS,我們可以使用 Kubernetes Examples Github 官方示例程式碼,稍加修改即可。
$ cd /home/wanyang3/k8s
$ git clone https://github.com/kubernetes/examples.git
# tree examples/staging/volumes/cephfs
|-- cephfs-with-secret.yaml
|-- cephfs.yaml
|-- README.md
`-- secret
`-- ceph-secret.yaml
跟之前使用 Ceph RBD 類似,也提供了兩種方式供 k8s 叢集使用 CephFS,在搭建 Ceph 叢集時,預設開啟了 cephx 安全認證的,所以在 k8s 叢集使用 CephFS 時,也是要配置認證資訊的,下邊分別演示一下吧!
3.1 建立 cephfs
在正式開始演示之前,我們先在 admin 節點建立一個 cephfs,測試下 cephfs 是否可用吧!詳細操作過程可參考文章 初試 Ceph 儲存之塊裝置、檔案系統、物件儲存 中檔案系統部分,貼下操作程式碼。
# 建立元資料伺服器 MDS
$ ceph-deploy mds create admin node0 node1
...
$ ceph mds stat
e5: 1/1/1 up {0=node0=up:active}, 1 up:standby
# 建立 cephfs
$ ceph osd pool create cephfs_data 128
pool 'cephfs_data' created
$ ceph osd pool create cephfs_metadata 128
pool 'cephfs_metadata' created
$ ceph fs new cephfs cephfs_metadata cephfs_data
new fs with metadata pool 2 and data pool 1
$ ceph fs ls
name: cephfs, metadata pool: cephfs_metadata, data pools: [cephfs_data ]
# 建立認證檔案 admin.secret
$ cat /etc/ceph/ceph.client.admin.keyring
[client.admin]
key = AQD01VVaVvzzLRAAaTURyUZwI9Ad3uYYFRL+VA==
caps mds = "allow *"
caps mon = "allow *"
caps osd = "allow *"
$ vim /etc/ceph/admin.secret
AQD01VVaVvzzLRAAaTURyUZwI9Ad3uYYFRL+VA==
$ mkdir /mnt/cephfs
$ mount -t ceph 10.222.78.12:6789:/ /mnt/cephfs -o name=admin,secretfile=/etc/ceph/admin.secret
$ df -h
...
10.222.78.12:6789:/ 66G 32G 34G 49% /mnt/cephfs
從上邊看到在 admin 節點已經成功將 cephfs 掛載到 /mnt/cephfs 啦!說明整個儲存叢集是沒有問題的,接下來演示的時候,就不需要在各個節點再次建立 cephfs 了,pod 容器內部掛載即可。當然也建立不成功,因為目前 一個 Ceph 儲存叢集只支援建立一個 cephfs。
3.2 使用 cephfs.yaml
$ cat cephfs.yaml
apiVersion: v1
kind: Pod
metadata:
name: cephfs1
spec:
containers:
- name: cephfs-rw
image: kubernetes/pause
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs
volumes:
- name: cephfs
cephfs:
monitors:
- 10.222.78.12:6789
user: admin
secretFile: "/etc/ceph/admin.secret"
readOnly: true
修改完的配置如上,這裡我們要掛載 /mnt/cephfs 目錄到 Pod 容器內。在建立之前,我們要去 node0 節點生成 admin.secret (因為現在是單節點測試,Pod 只會被排程到 node0,後續加入node1 時也需要生成 admin.secret),同時這裡 node0 既是 Ceph 叢集 osd 節點又是 k8s 節點,所以已存在該檔案,取出 Key 值即可。
$ cat /etc/ceph/ceph.client.admin.keyring
[client.admin]
key = AQD01VVaVvzzLRAAaTURyUZwI9Ad3uYYFRL+VA==
caps mds = "allow *"
caps mon = "allow *"
caps osd = "allow *"
$ vim /etc/ceph/admin.secret
AQD01VVaVvzzLRAAaTURyUZwI9Ad3uYYFRL+VA==
好了,現在可以建立使用 CephFS 作為後端儲存的 Pod 了。
$ kubectl create -f cephfs.yaml
pod "cephfs1" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
cephfs1 1/1 Running 0 12s
接下來我們去 node0 上驗證一下是否正確啟動並掛載該 CephFS 吧!
# node0 上操作
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b9f2bac921d1 docker.io/kubernetes/[email protected]:2088df8eb02f10aae012e6d4bc212cabb0ada93cb05f09e504af0c9811e0ca14 "/pause" 28 seconds ago Up 27 seconds k8s_cephfs-rw_cephfs1_default_5cc74af6-f5ea-11e7-be96-080027ee5979_0
$ mount
...
10.222.78.12:6789:/ on /var/lib/kubelet/pods/5cc74af6-f5ea-11e7-be96-080027ee5979/volumes/kubernetes.io~cephfs/cephfs type ceph (ro,relatime,name=admin,secret=<hidden>,acl)
$ docker inspect b9f2bac921d1
...
"Mounts": [
{
"Source": "/var/lib/kubelet/pods/5cc74af6-f5ea-11e7-be96-080027ee5979/containers/cephfs-rw/80747a86",
"Destination": "/dev/termination-log",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
{
"Source": "/var/lib/kubelet/pods/5cc74af6-f5ea-11e7-be96-080027ee5979/volumes/kubernetes.io~cephfs/cephfs",
"Destination": "/mnt/cephfs",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
{
"Source": "/var/lib/kubelet/pods/5cc74af6-f5ea-11e7-be96-080027ee5979/volumes/kubernetes.io~secret/default-token-jg3f8",
"Destination": "/var/run/secrets/kubernetes.io/serviceaccount",
"Mode": "ro",
"RW": false,
"Propagation": "rprivate"
},
{
"Source": "/var/lib/kubelet/pods/5cc74af6-f5ea-11e7-be96-080027ee5979/etc-hosts",
"Destination": "/etc/hosts",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
3.3 使用 cephfs-with-secret & ceph-secret
接下來使用 cephfs-with-secret 和 ceph-secret 方式,這種方式跟上邊直接使 admin.secret 檔案認證最大的區別就是使用 k8s secret 物件,該 secret 物件用於 k8s volume 外掛通過 cephx 認證訪問 ceph 儲存叢集。不過要提一下的是,k8s secret 認證 key 需要使用 base64 編碼。
# 獲取 Ceph ceph.client.admin.keyring 並生成 secret key
$ ceph auth get-key client.admin |base64
QVFEMDFWVmFWdnp6TFJBQWFUVVJ5VVp3STlBZDN1WVlGUkwrVkE9PQ==
修改 ceph-secret.yaml 檔案中,key 欄位替換成上邊生成的字串。
$ cat ceph-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: ceph-secret
data:
key: QVFEMDFWVmFWdnp6TFJBQWFUVVJ5VVp3STlBZDN1WVlGUkwrVkE9PQ==
建立名稱為 ceph-secret 的 Secret。
$ kubectl create -f ceph-secret.yaml
secret "ceph-secret" created
$ kubectl get secret
NAME TYPE DATA AGE
ceph-secret Opaque 1 11s
default-token-jg3f8 kubernetes.io/service-account-token 3 28m
接下來,需要修改一下 cephfs-with-secret.yaml 檔案,主要修改 cephfs 相關資訊,修改完成後如下。
# cat cephfs-with-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: cephfs2
spec:
containers:
- name: cephfs-rw
image: kubernetes/pause
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs
volumes:
- name: cephfs
cephfs:
monitors:
- 10.222.78.12:6789
user: admin
secretRef:
name: ceph-secret
readOnly: true
配置跟上邊類似,唯一區別就是 secretRef 換成剛建立的 ceph-secret 物件,接下來建立該 Pod 啦!
$ kubectl create -f cephfs-with-secret.yaml
pod "cephfs2" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
cephfs1 1/1 Running 0 11m
cephfs2 1/1 Running 0 25s
跟上邊示例一樣,妥妥沒問題,可以去 node0 上檢視 mount 資訊驗證一下,這裡就不在演示了。
4、Kubernetes PV & PVC 方式使用 CephFS
上一篇文章中指出,k8s 支援的 PV 型別有很多,其中就有我們熟悉的 Ceph RBD 和 CephFS,接下來就演示一下如何使用 PV & PVC 結合 CephFS 完成上邊演示操作。這裡使用上邊建立的同一個 cephfs,因為一個 Cephfs 儲存叢集只支援建立一個 cephfs。還有就是,這裡我們可以加入 node1 了,組成一個多節點的 k8s 叢集,測試跨節點使用 CephFS。
4.1 建立 PV
還記得上邊提過 Ceph 認證的 secret,這裡也是需要的,這次就不用再建立了,直接複用上邊的即可。新建 PV 檔案 rbd-pv.yaml 如下:
$ vim cephfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: cephfs-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
cephfs:
monitors:
- 10.222.78.12:6789
user: admin
secretRef:
name: ceph-secret
readOnly: false
persistentVolumeReclaimPolicy: Recycle
注意,這裡我們使用的 accessModes 模型為 ReadWriteMany,kubernetes 官網 Persistent Volumes 文件中指出 CephFS 檔案儲存對三種 Mode 方式都支援,CephFS 支援讀寫多次,也是實際工作中需要的。接下來建立 PV。
$ kubectl create -f cephfs-pv.yaml
persistentvolume "cephfs-pv" created
$ kubectl get pv
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM STORAGECLASS REASON AGE
cephfs-pv 1Gi RWX Recycle Available
4.2 建立 PVC
好了,上邊 PV 資源已經建立好了,接下來建立對資源的請求 PVC,新建 PVC 檔案 cephfs-pv-claim.yaml 如下:
$ cat cephfs-pv-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: cephfs-pv-claim
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
這裡提一下的是,因為接下來驗證測試需要跨節點讀取和寫入檔案,所以使用 ReadWriteMany 模型,接下來建立 PVC。
$ kubectl create -f cephfs-pv-claim.yaml
persistentvolumeclaim "cephfs-pv-claim" created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESSMODES STORAGECLASS AGE
cephfs-pv-claim Bound cephfs-pv 1Gi RWX 10s
4.3 建立掛載 CephFS 的 Pod
PV 和 PVC 都建立好了,接下來就需要建立掛載該 CephFS 的 Pod 了,這裡我使用官方示例中的 busybox 容器測試吧!新建 Pod 檔案 cephfs-pvc-pod1.yaml 如下:
# vim cephfs-pvc-pod1.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: cephfs-pvc-pod
name: cephfs-pv-pod1
spec:
containers:
- name: cephfs-pv-busybox1
image: busybox
command: ["sleep", "60000"]
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs-vol1
readOnly: false
volumes:
- name: cephfs-vol1
persistentVolumeClaim:
claimName: cephfs-pv-claim
從檔案可以看出,我們要將上邊建立的 cephfs-pv-claim 請求的資源掛載到容器的 /mnt/cephfs 目錄。接下來建立一下該 Pod,看是否能夠正常執行吧!建立之前,我們先造點資料到 /mnt/cephfs 目錄,方便後邊讀取測試。
# 提前寫入資料
$ vim /mnt/cephfs/test.txt
This is cephfs test file.
# 建立 cephfs-pv-pod1
$ kubectl create -f cephfs-pvc-pod.yaml
pod "cephfs-pv-pod1" created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
cephfs-pv-pod1 1/1 Running 0 47s
$ kubectl get pod --all-namespaces -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE
default cephfs-pv-pod1 1/1 Running 0 26s 10.96.2.2 node1
...
我們看到 Pod 能夠正常啟動,並且分配到了 node1,接下來我們去 node1 驗證一下吧!
# node1 上操作
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3cc605bed890 docker.io/[email protected]:436bbf48aa1198ebca8eac0ad9a9c80c8929d9242e02608f76ce18334e0cfe6a "sleep 60000" 12 seconds ago Up 12 seconds k8s_cephfs-pv-busybox1_cephfs-pv-pod1_default_a2397f5d-f677-11e7-be96-080027ee5979_0
$ docker exec -it 3cc605bed890 /bin/sh
/ # df -h
Filesystem Size Used Available Use% Mounted on
10.222.78.12:6789:/ 65.4G 34.1G 31.3G 52% /mnt/cephfs
...
/ # ls /mnt/cephfs
test.txt
/ # cat /mnt/cephfs/test.txt
This is cephfs test file.
# 建立一個新檔案,測試下邊跨節點看能否掛載的上,並且能夠讀取出來吧。
/ # vi /mnt/cephfs/cephfs-pv-pod1.txt
/ # cat /mnt/cephfs/cephfs-pv-pod1.txt
This message write by cephfs-pv-pod1 pod.
OK 我們看到 Pod 容器內能夠正確掛載 CephFS 併成功讀取到之前建立的檔案。
5、測試跨節點使用 CephFS
上一篇文中 K8s 叢集跨節點使用 Ceph RBD 存在 rbd: image ceph-rbd-pv-test is locked by other nodes
錯誤資訊,說明 Ceph RBD 僅能被 k8s 中的一個 node 掛載,也就是不支援跨節點掛載同一 Ceph RBD。那麼 CephFS 也會存在這個問題嗎?接下來我們驗證一下。
我們再在另外一個 node 上建立掛載同一個 CephFS 的 Pod,看是否可以跨節點掛載吧!
# 建立掛載 cephfs 的 pod2,配置同 pod1
$ vim cephfs-pvc-pod2.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: cephfs-pvc-pod
name: cephfs-pv-pod2
spec:
containers:
- name: cephfs-pv-busybox2
image: busybox
command: ["sleep", "60000"]
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs-vol2
readOnly: false
volumes:
- name: cephfs-vol2
persistentVolumeClaim:
claimName: cephfs-pv-claim
接下來建立一下該 Pod,看能夠建立成功吧!
$ kubectl create -f cephfs-pvc-pod2.yaml
pod "cephfs-pv-pod2" created
$ kubectl get pods --all-namespaces -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE
default cephfs-pv-pod1 1/1 Running 0 9m 10.96.2.3 node1
default cephfs-pv-pod2 1/1 Running 0 16s 10.96.1.4 node0
OK 我們看到 cephfs-pv-pod2 被分配到了 node0 並且正常執行起來了。說明 K8s 支援 CephFS 跨節點掛載。接下來,我們去 node0 驗證一下是否正確掛載該 CephFS 吧!
# node0 上操作
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8e544e9f497 docker.io/[email protected]:436bbf48aa1198ebca8eac0ad9a9c80c8929d9242e02608f76ce18334e0cfe6a "sleep 60000" About a minute ago Up About a minute k8s_cephfs-pv-busybox2_cephfs-pv-pod2_default_faf6f3fd-f678-11e7-be96-080027ee5979_0
$ docker exec -it f8e544e9f497 /bin/sh
/ # df -h
Filesystem Size Used Available Use% Mounted on
10.222.78.12:6789:/ 65.4G 34.1G 31.3G 52% /mnt/cephfs
...
/ # ls -l /mnt/cephfs
total 1
-rw-r--r-- 1 root root 42 Jan 11 02:36 cephfs-pv-pod1.txt
-rw-r--r-- 1 root root 26 Jan 10 09:39 test.txt
/ # cat /mnt/cephfs/cephfs-pv-pod1.txt
This message write by cephfs-pv-pod1 pod.
OK 一切正常,Pod 容器內能夠正確掛載同一 CephFS 併成功讀取到 pod1 建立的檔案。下邊我們在pod2 中寫入檔案,看下 pod1 中是否能夠讀取的到吧!
# node0 pod2 中寫入檔案
$ docker exec -it f8e544e9f497 /bin/sh
/ # vi /mnt/cephfs/cephfs-pv-pod2.txt
/ # cat /mnt/cephfs/cephfs-pv-pod2.txt
this message write by cephfs-pv-pod2 pod from node0.
# node1 pod1 讀取檔案
$ docker exec -it 3cc605bed890 /bin/sh
/ # ls /mnt/cephfs/
cephfs-pv-pod1.txt cephfs-pv-pod2.txt test.txt
依舊妥妥沒問題噠!再次說明,k8s 叢集支援跨節點掛載 CephFS 檔案儲存。同時 kubernetes 官網 Persistent Volumes 文件 中指出,當靜態 PV 都不匹配使用者的 PVC 請求時,k8s 叢集還支援 Dynamic 動態提供 Volume 給 PVC,不過這種方式需要配置 StorageClasses,檢視 Kubernetes 官網 Storage Classes 文件 Provisioner 部分指出支援 Ceph RBD,下一篇我們繼續研究 Kubernetes 叢集使用 RBD 作為 StorageClass PVC,來實現分散式儲存。
參考資料