建议使用cephfs storageClass,而非本文中手动指定pv/pvc的方式,否则容易引发cephfs性能问题,详情参考:
kubernetes挂载cephfs带来的mds卡顿问题及引入cephfs storageClass
本文仅作对pv/pvc的了解学习。
在前篇部署测试完cephfs的基础上:
Ceph集群生产环境安装部署
cephfs调优 & 性能测试 & 常用命令
本篇介绍k8s使用 pv/pvc的方式使用cephfs分布式文件系统
首先解释一下pv/pvc的相关概念:
PV:
PersistentVolumes,是k8s抽象化的存储资源,主要包括存储能力、访问模式、存储类型、回收策略等关键信息.PV是k8s实际对接存储后端的真正入口
[Access Mode] (接入模式):
ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
ReadWriteMany(RWX):读写权限,可以被多个节点挂载
[persistentVolumeReclaimPolicy](回收策略:
Retain(保留)- 保留数据,不会再分配给pvc,需要管理员手工清理数据
Recycle(回收)- 清除 PV 中的数据,保留pv资源,可以留供其他pvc使用
Delete(删除)- 删除整个pv资源及内部的数据。
PVC:
PersistentVolumeClaims,是对PV资源的一种声明,pvc绑定实体资源pv后,pod通过绑定pvc来使用pv资源.PVC是k8s的一种抽象化的声明式绑定存储资源的管理模式的中间层,pod无法直接通过pv使用存储资源,必须经过pvc,而pvc必须要绑定pv实体后,才可被pod使用.
依赖安装:
每个node需要安装ceph-common包,才能正常使用cephfs:
yum -y install ceph-common
创建secret:
在创建pv前,由于ceph是开启了cephx认证的,于是首先需要创建secret资源,k8s的secret资源采用的是base64加密
在ceph monitor上提取key:
# ceph auth get-key client.admin |base64
QVFCL3E1ZGIvWFdxS1JBQTUyV0ZCUkxldnRjQzNidTFHZXlVYnc9PQ==
# cat ceph-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: ceph-secret
data:
key: QVFCL3E1ZGIvWFdxS1JBQTUyV0ZCUkxldnRjQzNidTFHZXlVYnc9PQ==
~/ceph# kubectl apply -f ceph-secret.yaml
创建测试pv:
# cat cephfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: cephfs-pv
labels:
pv: cephfs-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
cephfs:
monitors:
- 192.168.20.112:6789
- 192.168.20.113:6789
- 192.168.20.114:6789
user: admin
secretRef:
name: ceph-secret
readOnly: false
persistentVolumeReclaimPolicy: Delete
查看:
# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
cephfs-pv 1Gi RWX Delete Available 6s
现在pvc是空闲Available状态
创建测试pvc:
# cat cephfs-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: cephfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
selector:
matchLabels:
pv: cephfs-pv
查看:
# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
cephfs-pvc Bound cephfs-pv 1Gi RWX 24s
# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
cephfs-pv 1Gi RWX Delete Bound default/cephfs-pvc 8m
可以看到pv和pvc都已经自动变为Bound状态,但是我们这里没有使用任何关联标签,使它们两者进行关联,pvc是怎么自动绑定到pv的呢?其实pvc在创建伊始就会主动去寻找符合requets条件的pv资源,如果寻找到了,便会自动进行绑定,无需做标签匹配.
小Tips:
1.当pv的容量大于pvc的需求时,pvc可以成功自动绑定pv;
2.当pv的容量小于pvc的需求时,pvc无法绑定该pv;
3.pv和pvc的绑定关系是一一对应的.
4.pv/pvc的创建顺序是:pv -> pvc -> pod
5.pv/pvc的销毁顺序是:pod -> pvc -> pv,顺序一定不要错
例如:
2G的pv可以被1G的pvc绑定,并且绑定成功后,pvc的实际空间也是2G而不是1G;
1G的pv无法被2G的pvc绑定
创建pod实例
将pod调度到某一个node上,挂载pvc
root@h009027:~/ceph# cat testpod1-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: testpod1
name: testpod1
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: testpod1
template:
metadata:
labels:
app: testpod1
spec:
containers:
- args:
- /bin/bash
- -c
- /run.sh
image: nginx
imagePullPolicy: Always
name: testpod1
ports:
- containerPort: 80
protocol: TCP
terminationMessagePath: /dev/termination-log
volumeMounts:
- mountPath: /var/www
name: cephfs-testpod1
dnsPolicy: ClusterFirst
nodeSelector:
DEVNODE: ""
restartPolicy: Always
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: cephfs-testpod1
persistentVolumeClaim:
claimName: cephfs-pvc
查看pod:
~# kubectl get pods | grep testpod1
testpod1-7847858587-2rbsq 1/1 Running 0 10s
进入pod并给nginx添加一个主页index.html:
~# kubectl exec -it testpod1-7847858587-2rbsq bash
~# echo "Just for pv/pvc test" > /var/www/index.html
获取pod ip打开浏览器测试:
(本篇测试场景外部与集群内部网段路由都已互通,如果pod内部路由未通,需要使用svc的方式暴露服务,可查看此前文章,这里不再赘述):
到这里,文件系统挂载已经测试完毕,但选用cephfs作k8s分布式文件系统的最大优势是因为其支持ReadWriteMany多节点挂载的灵活性,非常符合k8s像管理牲口一样管理你的容器的理念,下面开始跨节点测试
再创建一个部署文件,让其在另外的node上运行,与上方pod共用一个pvc:
~/ceph# cat testpod2-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: testpod2
name: testpod2
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: testpod2
template:
metadata:
labels:
app: testpod2
spec:
containers:
- args:
- /bin/bash
- -c
- /run.sh
image: registry.youkeshu.com:5000/nginx:php7.1v1
imagePullPolicy: Always
name: testpod2
ports:
- containerPort: 80
protocol: TCP
terminationMessagePath: /dev/termination-log
volumeMounts:
- mountPath: /var/www
name: cephfs-testpod2
dnsPolicy: ClusterFirst
nodeSelector:
PRODNODE: ""
restartPolicy: Always
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: cephfs-testpod2
persistentVolumeClaim:
claimName: cephfs-pvc
查看pod:
~/ceph# kubectl get pods -o wide | grep testpod
testpod1-7847858587-2rbsq 1/1 Running 0 17m 172.26.2.172 h009029
testpod2-6d4b8d5db9-wkpx6 1/1 Running 0 9s 172.26.0.52 h009028
浏览器打开testpod2主页:
结论:
cephfs可以很好的实现k8s多节点调度容器时对持久化文件的挂载支持
以上方式使用时,会将容器内的指定路径直接挂载到cephfs的根目录下,前往上篇文章中挂载mount cephfs的节点挂载目录就可以发现此问题:
[root@h020112 cephfs]# ls
index.html testfile
[root@h020112 cephfs]# cat index.html
Just for pv/pvc test
如果所有的文件都这样直接放在整个cephfs文件系统的根目录里,无疑是极不好管理的,这个时候我们可以在 Pod 中使用一个新的属性: subPath,该属性可以来解决这个问题,我们只需要更改上面的 Pod 的 YAML 文件即可
修改后的yaml文件:
root@h009027:~/ceph# cat testpod1-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: testpod1
name: testpod1
namespace: default
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/amazondev
spec:
replicas: 1
selector:
matchLabels:
app: testpod1
template:
metadata:
labels:
app: testpod1
spec:
containers:
- args:
- /bin/bash
- -c
- /run.sh
image: registry.youkeshu.com:5000/nginx:php7.1v1
imagePullPolicy: Always
name: testpod1
ports:
- containerPort: 80
protocol: TCP
terminationMessagePath: /dev/termination-log
volumeMounts:
- mountPath: /var/www
name: cephfs-testpod1
# 仅添加这一行即可
subPath: testpod1
dnsPolicy: ClusterFirst
nodeSelector:
DEVNODE: ""
restartPolicy: Always
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: cephfs-testpod1
persistentVolumeClaim:
claimName: cephfs-pvc
重新部署后,再回到挂载点查看:
[root@h020112 cephfs]# ls
index.html testfile testpod1
[root@h020112 cephfs]# ls testpod1/
[root@h020112 cephfs]#
[root@h020112 cephfs]# ll testpod1/
total 0
可以看到,这里创建了一个subPath名的目录,但是目录里面是空的,也即是说,通过k8s的抽象层pvc,容器对cephfs的根目录拥有了指定容量的使用权限,subPath仅仅是在cephfs根目录下创建了一个子目录,无论是否创建子目录,容器对cephfs的根目录都拥有使用权限,因此,为了避免多个容器同名文件冲突,便于管理维护,请在实际使用中一定不要忘记在部署文件中添加subPath项