Kubernetes添加帶Quota限額的CephFS StorageClass

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

CephFSmount方式分爲內核態mount和用戶態mount,內核態使用mount命令掛載,用戶態使用ceph-fuse。內核態只有在kernel 4.17 + Ceph mimic以上的版本才支持Quotas,用戶態則沒有限制。git

內核態mountgithub

# mount -t ceph 10.32.3.70:/k8s_test /mnt/cephfs/ -o name=admin,secret=AQCs2Q9bqAjCHRAAlQUF+hAiXhbErk4NdtvORQ==

用戶態mountdocker

# ceph-fuse -r /k8s_test /mnt/cephfs/ --name client.admin

配置quotavim

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。這是由於CephFSQuotas不是嚴格的,按官方說法判斷檢測週期是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中建立訪問CephSecret的步驟見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類型的StorageClassExternal 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) 建立使用PVCPod

# 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版本存在bugceph-fuse掛載時指定了-k參數,卻沒有指定-i或者-n參數,致使嘗試使用ceph-fuse掛載會報錯,最終後仍是回退到內核態掛載。

另外目前CephFS external provisioner中建立目錄時,並無指定ceph.quota.max_bytes屬性,爲了添加配額限制,須要修改代碼。

1) 修改CephFS external provisioner

CephFS external provisioner的結構比較簡單,主要就是cephfs-provisioner.gocephfs_provisioner.py兩個文件。cephfs-provisioner.go是主程序,建立CephFS Provisionercephfs_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.goexecFuseMount()函數,原來的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確實生效了。

 

參考資料

CephFS Admin Tips – Create a new user and share

kubernetes筆記: Cephfs

相關文章
相關標籤/搜索