kubernetes笔记: Cephfs
by 伊布
有了前面ceph RBD的基础,再来看cephfs就简单很多了。本文介绍了kubernetes上使用cephfs的方法,重点介绍了kubernetes上用cephfs支持storage class的解法。
cephfs
cephfs类似nfs。cephfs服务器上配置完成后,客户端可以将远端目录mount到本地。cephfs服务器的配置就不说了,有人搞定的感觉就是好。主要来说说客户端mount。
cephfs有两种mount方式:内核(即mount命令)、用户态(ceph-fuse)。
内核mount
因为上文RBD介绍里已经在本地 /etc/ceph/ 下配置好了,所以下面可以直接mount。
# mount -t ceph 1.2.3.4:/ /mnt/cephfs/ -o name=admin,secret=`ceph auth print-key client.admin`
# df -h|grep cephfs
172.25.60.3:/ 17T 63G 17T 1% /mnt/cephfs
上面将整个cephfs都挂载到了 /mnt/cephfs 目录下。如果你不想这么大范围怎么做呢?cephfs没有像RBD一样有pool+image这样比较好的隔离手段,其做法是可以在cephfs根目录下创建一个子目录,mount的时候指定这个子目录。例如。
# mkdir /mnt/cephfs/xxx
# mkdir /mnt/xxx
# mount -t ceph 1.2.3.4:/xxx /mnt/xxx/ -o name=admin,secret=`ceph auth print-key client.admin`
# df -h|grep xxx
172.25.60.3:/xxx 17T 63G 17T 1% /mnt/xxx
注意,这时看到的虽然是子目录,但其可用大小和根目录mount是一样的。为什么呢?我们用的centos 7.3的内核版本不支持。据说更高内核版本的客户端+服务器可以支持。
用户态mount
cephfs还支持用户态mount,方法是使用ceph-fuse命令。
yum install ceph-fuse -y
注意如果centos只是配置了centos、epel两个源,可能会因为版本依赖问题而无法安装ceph-fuse。此时应该配置使用ceph自己的repo。
rpm -Uvh http://mirrors.ustc.edu.cn/centos/7/extras/x86_64/Packages/epel-release-7-9.noarch.rpm
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
安装后就可以ceph-fuse了。
# ceph-fuse -r /xxx /mnt/xxx/
ceph-fuse[1108]: starting ceph client
2018-05-22 23:32:21.846814 7fc560879ec0 -1 init, newargv = 0x7fc56a916780 newargc=11
ceph-fuse[1108]: starting fuse
# df -h|grep xxx
ceph-fuse 17T 63G 17T 1% /mnt/xxx
可以看到,挂载成功了,和内核mount一样,其大小也是整个cephfs的size。
但通过配置,ceph-fuse可以限定用户mount的大小。
限定用户态mount的size
需要两步:
1 设置用户待使用目录的attr
setfattr -n ceph.quota.max_bytes -v 100000000 /mnt/cephfs/xxx # 100 MB
2 用户mount时,指定--client-quota
参数
# ceph-fuse -r /xxx /mnt/xxx --client-quota
# df -h|grep xxx
ceph-fuse 92M 0 92M 0% /mnt/xxx
# cd /mnt/xxx
# dd if=/dev/zero of=test bs=1M count=100 #在/mnt/xxx目录下创建一个test文件,大小是100MB
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 1.23772 s, 84.7 MB/s
# ls -l -h # 可以创建成功
total 101M
-rw-r--r-- 1 root root 100M May 22 23:47 test
# df -h |grep xxx #没空间了
ceph-fuse 92M - - - /mnt/xxx
# dd if=/dev/zero of=test2 bs=1M count=100 # 创建一个test2文件,大小100MB,失败,提示超过quota了
dd: error writing ‘test2’: Disk quota exceeded
1+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000886542 s, 0.0 kB/s
# ls -l -h #只有文件名,没有内容
total 101M
-rw-r--r-- 1 root root 100M May 22 23:47 test
-rw-r--r-- 1 root root 0 May 22 23:47 test2
需要注意:
- 二者缺一不可。如果只是设置了setfattr,会发现一个很神奇的现象:用户mount了以后,的确可以看到像上面的size大小,但其实是限制不住的,用户可以写超过 setfattr的限制。
- quota的检测会略微延迟一点,ceph说是几秒钟,所以我们看到第一个100MB的文件是创建成功了的
对于k8s来说,其实是够用的,因为mount是由k8s来做的,容器的用户不参与这个过程,所以可以为其设置 –client-quota。我给k8s提了一个PR,还在等社区的意见
用户态、内核态卸载,其实都可以 umount 命令。当然用户态也可以用更专业的:
fusermount -u mountpoint --> 可以直接 umount
cephfs用作Volume
贴个yaml略过。
apiVersion: v1
kind: Pod
metadata:
name: cephfs2
spec:
containers:
- name: cephfs-rw
image: gcr.io/nginx
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs
volumes:
- name: cephfs
cephfs:
monitors:
- 1.2.3.4:6789
user: "admin"
secretRef:
name: ceph-secret
readOnly: true
cephfs用作PV/PVC
贴个yaml略过。PVC、Pod就不贴了。跟RBD里是一样的。
apiVersion: v1
kind: PersistentVolume
metadata:
name: cephfs-pv3
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
cephfs:
monitors:
- 1.2.3.4:6789
path: /xxx
user: admin
secretRef:
name: ceph-secret
readOnly: false
persistentVolumeReclaimPolicy: Recycle
cephfs用作storage class
重点来说说storage class。你可能会说,哎,官方支持storage class的存储类型里,明明没有cephfs呀。
对,但也不全对。
目前k8s(v1.10)的确是不支持cephfs用作storage class的,但是我们已经有了ceph集群,而RBD又不支持 ReadWriteMany,这样就没办法做共享存储类型的Volume了,使用场景会受一些限制。而为了这个场景再单独去维护一套glusterfs,又很不划算,当然是能用cephfs做storage class最完美啦。
社区其实是有项目做这个的,就是 external storage,只是现在还在孵化器里。
所谓external storage其实就是一个 controller,它会去监听 apiserver 的storage class api的变化,当发现有cephfs的请求,它会拿来处理:根据用户的请求,创建PV,并将PV的创建请求发给api server;PV创建后再将其与PVC绑定。
同时,controller的 cephfs-provisioner会调用 cephfs_provisioner.py
脚本去cephfs集群上去创建目录,目录名规则为 "kubernetes-dynamic-pvc-%s", uuid.NewUUID()
。
const {
provisionCmd = "/usr/local/bin/cephfs_provisioner"
}
func (p *cephFSProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) {
args := []string{"-n", share, "-u", user}
if p.enableQuota {
capacity := options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
requestBytes := strconv.FormatInt(capacity.Value(), 10)
args = append(args, "-s", requestBytes)
}
cmd := exec.Command(provisionCmd, args...)
// set env
cmd.Env = []string{
"CEPH_CLUSTER_NAME=" + cluster,
"CEPH_MON=" + strings.Join(mon[:], ","),
"CEPH_AUTH_ID=" + adminID,
"CEPH_AUTH_KEY=" + adminSecret}
output, cmdErr := cmd.CombinedOutput()
在ceph上看,目录树如下
├── kubernetes
│ ├── kubernetes-dynamic-pvc-0f1354bc-75e6-11e8-9910-0a580af4035a
│ ├── kubernetes-dynamic-pvc-14e82c0a-7603-11e8-9910-0a580af4035a
│ ├── kubernetes-dynamic-pvc-1dadffbf-75e5-11e8-9910-0a580af4035a
...
├── _kubernetes:kubernetes-dynamic-pvc-0f1354bc-75e6-11e8-9910-0a580af4035a.meta
├── _kubernetes:kubernetes-dynamic-pvc-14e82c0a-7603-11e8-9910-0a580af4035a.meta
├── _kubernetes:kubernetes-dynamic-pvc-1dadffbf-75e5-11e8-9910-0a580af4035a.meta
...
也就是说,external-storage作为ceph集群的一个用户,自己维护了不同PVC和cephfs目录的对应关系。
cephfs的external storage controller的部署可以参考这里。
部署后,创建一个名为cephfs的storage classs。此时,需要指定到cephfs的地址、登录账号信息。比如说用户有两种cephfs:普通机械硬盘和快速的SSD盘,那么可以创建两个sc,一个用来做shared-slow,一个用来做shared-fast。
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: cephfs
provisioner: ceph.com/cephfs
parameters:
monitors: 1.2.3.4:6789
adminId: admin
adminSecretName: ceph-secret
adminSecretNamespace: "cephfs"
再创建个pvc,指定storage class为cephfs;创建Pod,挂载这个pvc。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: claim
annotations:
volume.beta.kubernetes.io/storage-class: "cephfs"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: gcr.io/nginx
volumeMounts:
- name: pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: pvc
persistentVolumeClaim:
claimName: claim
很完美对不对?naive。目前external storage并不支持设置cephfs的大小,因此,所有容器看到的挂载目录都是一样大的,显然离可用还有一定距离。
不过,由于external storage用的是python client,所以fix下也很简单,你可以参考我的PR。当然了,别忘了修改kubelet的这个PR。
external-storage的PR已经合入了,kubernetes的还没有,需要考虑不同ceph版本兼容的问题。
服用了这两个PR以后,你也可以和我一样快乐的使用cephfs sc了。
Ref:
Subscribe via RSS