1. 在Ceph上爲Kubernetes建立一個文件系統html
# ceph osd pool create cephfs_data 128 # ceph osd pool create cephfs_metadata 128 # ceph fs new cephfs cephfs_metadata cephfs_data
2. CephFS配置Quotasnginx
CephFS的mount方式分爲內核態mount和用戶態mount,內核態使用mount命令掛載,用戶態使用ceph-fuse。內核態只有在kernel 4.17 + Ceph mimic以上的版本才支持Quotas,用戶態則沒有限制。git
內核態mount:github
# mount -t ceph 10.32.3.70:/k8s_test /mnt/cephfs/ -o name=admin,secret=AQCs2Q9bqAjCHRAAlQUF+hAiXhbErk4NdtvORQ==
用戶態mount:docker
# ceph-fuse -r /k8s_test /mnt/cephfs/ --name client.admin
配置quota:vim
1) 首先在CephFS建立一個要限額的目錄後端
# mkdir /mnt/cephfs # ceph-fuse /mnt/cephfs # mkdir /mnt/cephfs/k8s_test
2) 而後在目錄上使用setfattr設置限額屬性api
# setfattr -n ceph.quota.max_bytes -v 100000000 /mnt/cephfs/k8s_test
好比上面這條命令限制/k8s_test目錄只能使用100MB大小的空間。bash
3) 掛載限額目錄並測試app
# mkdir /mnt/k8s_test # ceph-fuse -r /k8s_test /mnt/k8s_test/ --name client.admin --client-quota
因爲使用的內核和Ceph版本比較低,只能在用戶態測試。在Jewel及以前版本的ceph-fuse,掛載時要指定--client-quota參數,限額纔會生效。而在Luminous以後的版本,則不支持這個參數了,會自動識別quota。因爲我這裏使用的是Jewel版本,因此指定了--client-quota參數。而後寫入200MB數據測試一下:
# cd /mnt/k8s_test # dd if=/dev/zero of=test1.bin bs=1M count=200 dd: error writing ‘test1.bin’: Disk quota exceeded 129+0 records in 128+0 records out 134348800 bytes (134 MB) copied, 0.428233 s, 314 MB/s # df -h Filesystem Size Used Avail Use% Mounted on ceph-fuse 92M -64Y -36M 100% /mnt/cephfs
能夠看到中途提示超出配額,可是寫入了134MB數據,超過了指定的配額100MB。這是由於CephFS的Quotas不是嚴格的,按官方說法判斷檢測週期是10s。
再次寫入數據,能夠發現徹底寫不進去了:
# dd if=/dev/zero of=test2.bin bs=1M count=200 dd: error writing ‘test2.bin’: Disk quota exceeded 1+0 records in 0+0 records out 0 bytes (0 B) copied, 0.00162182 s, 0.0 kB/s
3. 更新k8s用戶權限
# ceph auth caps client.k8s mon 'allow rwx' osd 'allow rwx pool=k8s, allow rw pool=cephfs_data' mds 'allow rwp'
若是尚未建立k8s用戶,則使用下面的命令建立:
# ceph auth get-or-create client.k8s mon 'allow rwx' osd 'allow rwx pool=k8s, allow rw pool=cephfs_data' mds 'allow rwp' -o ceph.client.k8s.keyring
在Kubernets中建立訪問Ceph的Secret的步驟見《Kubernetes配置Ceph RBD StorageClasses做爲Persistent Volumes Claims後端》第3~5步。
4. Kubernetes Volume使用CephFS
Kubernetes Volume原生支持CephFS類型,使用方法:
# echo ‘apiVersion: v1 kind: Pod metadata: name: nginx-test-cephfs spec: containers: - name: nginx-test-cephfs image: registry.exmaple.com/base/nginx:v1.0 volumeMounts: - name: cephfs mountPath: "/data/" volumes: - name: cephfs cephfs: monitors: - 10.32.3.70:6789 - 10.32.3.71:6789 - 10.32.3.72:6789 path: /k8s_test user: k8s secretRef: name: ceph-k8s-secret readOnly: false’ | kubectl create -f -
進入容器查看:
# kubectl exec nginx-test-cephfs -it -- /bin/bash [root@nginx-test-cephfs ~]# df -h Filesystem Size Used Avail Use% Mounted on 10.32.3.70:6789,10.32.3.71:6789,10.32.3.72:6789:/k8s_test 5.2T 1.1G 5.2T 1% /data
5. Kubernetes Persistent Volume使用CephFS
Kubernetes Persistent Volume原生支持CephFS類型,使用方法:
# echo 'apiVersion: v1 kind: PersistentVolume metadata: name: nginx-test-cephfs-pv-01 namespace: test spec: capacity: storage: 100Mi accessModes: - ReadWriteMany cephfs: monitors: - 10.32.3.70:6789 - 10.32.3.71:6789 - 10.32.3.72:6789 path: /k8s_test user: k8s secretRef: name: ceph-k8s-secret readOnly: false --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: nginx-test-cephfs-pvc-01 spec: accessModes: - ReadWriteMany resources: requests: storage: 50Mi --- apiVersion: v1 kind: Pod metadata: name: nginx-test-cephfs-01 spec: containers: - name: nginx-test-cephfs image: registry.exmaple.com/base/nginx:v1.0 volumeMounts: - name: cephfs-vol1 mountPath: "/data/" volumes: - name: cephfs-vol1 persistentVolumeClaim: claimName: nginx-test-cephfs-pvc-01' | kubectl create -f -
進入容器查看:
# kubectl exec nginx-test-cephfs -it -- /bin/bash [root@nginx-test-cephfs ~]# df -h Filesystem Size Used Avail Use% Mounted on 10.32.3.70:6789,10.32.3.71:6789,10.32.3.72:6789:/k8s_test 5.2T 1.1G 5.2T 1% /data
6. Kubernetes StorageClass使用CephFS
Kubernetes StorageClass原生不支持CephFS,可是在社區的孵化項目External Storage中添加了CephFS類型的StorageClass。External Storage是對核心的Kubernetes controller manager的擴展,其中包含的每一個external provisioner能夠獨立部署以支持擴展的StorageClass類型。
部署CephFS external provisioner:
1) 下載External Storage代碼
# go get github.com/kubernetes-incubator/external-storage
同時要保證CephFS external provisioner依賴的package源碼存在於$GOPATH/src目錄下,若是有缺失,後面編譯會報錯,按照報錯使用go get下載就行。
2) 編譯、打包鏡像、上傳鏡像
進入CephFS external provisioner的源碼目錄:
# cd $GOPATH/src/github.com/kubernetes-incubator/external-storage/ceph/cephfs
修改Makefile,將REGISTRY變量改爲本身的鏡像倉庫地址,注意結尾要帶/:
# vim Makefile ifeq ($(REGISTRY),) REGISTRY = registry.example.com/ endif
修改Dockerfile,指定CEPH_VERSION與本身Ceph Cluster的版本一致:
# vim Dockerfile ENV CEPH_VERSION "mimic"
編譯,生成cephfs-provisioner二進制文件:
# make
打包docker鏡像,並上傳到鏡像倉庫:
# make push
3) 部署CephFS external provisioner
進入部署目錄:
# cd $GOPATH/src/github.com/kubernetes-incubator/external-storage/ceph/cephfs/deploy
修改鏡像地址:
# vim rbac/deployment.yaml image: "registry.example.com/cephfs-provisioner:latest"
修改但願部署到的namespace:
# NAMESPACE=kube-system # sed -r -i "s/namespace: [^ ]+/namespace: $NAMESPACE/g" ./rbac/*.yaml
部署:
# kubectl -n $NAMESPACE apply -f ./rbac
4) 建立cephfs StorageClass
# echo ‘apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: cephfs provisioner: ceph.com/cephfs parameters: monitors: 10.32.3.70:6789,10.32.3.71:6789,10.32.3.72:6789 adminId: k8s adminSecretName: ceph-k8s-secret adminSecretNamespace: kube-system‘ | kubectl create -f -
5) 建立一個PersistentVolumeClaim
# echo ‘apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nginx-test-cephfs-pvc-03 annotations: volume.beta.kubernetes.io/storage-class: "cephfs" spec: accessModes: - ReadWriteMany resources: requests: storage: 100Mi’ | kubectl create -f -
6) 建立使用PVC的Pod
# echo ‘apiVersion: v1 kind: Pod metadata: name: nginx-test-cephfs-03 spec: containers: - name: nginx-test-cephfs-03 image: registry.example.com/base/nginx:v1.0 volumeMounts: - name: pvc mountPath: "/data/" volumes: - name: pvc persistentVolumeClaim: claimName: nginx-test-cephfs-pvc-03’ | kubectl create -f -
7) 查看容器狀態
# kubectl exec nginx-test-cephfs-03 -it -- /bin/bash # df -h Filesystem Size Used Avail Use% Mounted on 10.32.3.70:6789,10.32.3.71:6789,10.32.3.72:6789:/volumes/kubernetes/kubernetes-dynamic-pvc-6bfb0ff3-6980-11e8-aa58-5a90b87a7c36 5.2T 1.1G 5.2T 1% /data
7. 爲CephFS StorageClass添加Quotas支持
注意容器中CephFS的掛載方式,使用的是內核態mount,掛載目錄的容量並非PVC聲明的100MiB,而是整個CephFS的可用大小。
查看源碼發如今Kubernetes 1.10以後的版本纔會嘗試用戶態mount。並且目前使用的Kubernetes 1.10.4版本存在bug,ceph-fuse掛載時指定了-k參數,卻沒有指定-i或者-n參數,致使嘗試使用ceph-fuse掛載會報錯,最終後仍是回退到內核態掛載。
另外目前CephFS external provisioner中建立目錄時,並無指定ceph.quota.max_bytes屬性,爲了添加配額限制,須要修改代碼。
1) 修改CephFS external provisioner
CephFS external provisioner的結構比較簡單,主要就是cephfs-provisioner.go和cephfs_provisioner.py兩個文件。cephfs-provisioner.go是主程序,建立CephFS Provisioner。cephfs_provisioner.py 是對ceph_volume_client.CephFSVolumeClient的封裝,方便調用。
修改思路就是在CephFS中建立目錄時指定size參數,底層的CephFSVolumeClient.create_volume()判斷size存在時會調用setattr設置ceph.quota.max_bytes屬性。
具體修改內容能夠參考這個PR。修改完後,從新執行第6步中的打包部署操做使之生效。
2) 修改Kubelet
因爲1.10.4版本的kubelet存在bug,使用ceph-fuse掛載目錄時指定了-k參數卻沒有指定-i或者-n參數,致使掛載報錯。須要修改代碼,加上-i參數。具體位置是kubernetes/pkg/volume/cephfs/cephfs.go的execFuseMount()函數,原來的mount參數:
func (cephfsMounter *cephfsMounter) checkFuseMount() bool { … mountArgs := []string{} mountArgs = append(mountArgs, "-k") mountArgs = append(mountArgs, keyring_file) mountArgs = append(mountArgs, "-m") mountArgs = append(mountArgs, src) mountArgs = append(mountArgs, mountpoint) mountArgs = append(mountArgs, "-r") mountArgs = append(mountArgs, cephfsVolume.path) … }
追加兩行:
mountArgs = append(mountArgs, "--id") mountArgs = append(mountArgs, cephfsVolume.id)
若是使用的ceph-fuse版本低於Luminous,還要加上--client-quota參數:
mountArgs = append(mountArgs, "--client-quota")
而後從新編譯kubelet,替換安裝文件,重啓服務生效。編譯方法參考《編譯Kubelet二進制文件》。
3) 驗證Quota
從新使用第6步的配置建立一個Pod,進入容器查看:
# kubectl exec nginx-test-cephfs-03 -it -- /bin/bash root@nginx-test-cephfs-03:/# df -h Filesystem Size Used Avail Use% Mounted on ceph-fuse 100M 0 100M 0% /data
看到掛載方式是ceph-fuse,目錄可用大小也是quota配置的100M。寫入數據測試一下:
# dd if=/dev/zero of=/data/test.bin bs=1M count=200 dd: error writing '/data/test.bin': Disk quota exceeded 123+0 records in 122+0 records out 128421888 bytes (128 MB, 122 MiB) copied, 4.32033 s, 29.7 MB/s # df -h Filesystem Size Used Avail Use% Mounted on ceph-fuse 100M 100M 0 100% /data
Quota確實生效了。
參考資料