内容简介:kubernetes从1.10版本开始支持local volume(本地卷),workload(不仅是statefulsets类型)可以充分利用本地快速SSD,从而获取比remote volume(如cephfs、RBD)更好的性能。在local volume出现之前,statefulsets也可以利用本地SSD,方法是配置hostPath,并通过nodeSelector或者nodeAffinity绑定到具体node上。但hostPath的问题是,管理员需要手动管理集群各个node的目录,不太方便。下面两种
local volume
kubernetes从1.10版本开始支持local volume(本地卷),workload(不仅是statefulsets类型)可以充分利用本地快速SSD,从而获取比remote volume(如cephfs、RBD)更好的性能。
在local volume出现之前,statefulsets也可以利用本地SSD,方法是配置hostPath,并通过nodeSelector或者nodeAffinity绑定到具体node上。但hostPath的问题是,管理员需要手动管理集群各个node的目录,不太方便。
下面两种类型应用适合使用local volume。
- 数据缓存,应用可以就近访问数据,快速处理。
- 分布式存储系统,如分布式数据库Cassandra ,分布式文件系统ceph/gluster
下面会先以手动方式创建PV、PVC、Pod的方式,介绍如何使用local volume,然后再介绍external storage提供的半自动方式,最后介绍社区的一些发展。
创建一个storage class
首先需要有一个名为 local-volume
的sc。
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: local-volume provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer
sc的provisioner是 kubernetes.io/no-provisioner
。
WaitForFirstConsumer
表示PV不要立即绑定PVC,而是直到有Pod需要用PVC的时候才绑定。调度器会在调度时综合考虑选择合适的local PV,这样就不会导致跟Pod资源设置,selectors,affinity and anti-affinity策略等产生冲突。很明显:如果PVC先跟local PV绑定了,由于local PV是跟node绑定的,这样selectors,affinity等等就基本没用了,所以更好的做法是先根据调度策略选择node,然后再绑定local PV。
静态创建PV
通过kubectl命令,静态创建一个5GiB的PV;该PV使用node ubuntu-1的 /data/local/vol1
目录;该PV的sc为local-volume。
apiVersion: v1 kind: PersistentVolume metadata: name: example-local-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: local-volume local: path: /data/local/vol1 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - ubuntu-1
Retain(保留)是指,PV跟PVC释放后,管理员需要手工清理,重新设置该卷。
需要指定PV对应的sc;目录 /data/local/vol1
也需要创建。
kubectl get pv example-local-pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE example-local-pv 5Gi RWO Retain Available local-volume 8d
使用local volume PV
接下来创建一个关联 sc:local-volume的PVC,然后将该PVC挂到nginx容器里。
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: myclaim spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi storageClassName: local-volume --- kind: Pod apiVersion: v1 metadata: name: mypod spec: containers: - name: myfrontend image: nginx volumeMounts: - mountPath: "/usr/share/nginx/html" name: mypd volumes: - name: mypd persistentVolumeClaim: claimName: myclaim
进入到容器里,会看到挂载的目录,大小其实就是上面创建的PV所在磁盘的size。
/dev/sdb 503G 235M 478G 1% /usr/share/nginx/html
在宿主机的 /data/local/vol1
目录下创建一个 index.html
文件:
echo "hello world" > /data/local/vol1/index.html
然后再去curl容器的IP地址,就可以得到刚写入的字符串了。
删除Pod/PVC,之后PV状态改为Released,该PV不会再被绑定PVC了。
动态创建PV
手工管理local PV显然是很费劲的,社区提供了 external storage 可以动态的创建PV(实际仍然不够自动化)。
local volume provisioner的官方编排在 local-volume/provisioner/deployment/kubernetes/example/default_example_provisioner_generated.yaml
目录里,不过官方文档一会fast-disk,一会local-storage,有点混乱。我这里统一都用 local-volume
。
--- apiVersion: v1 kind: ConfigMap metadata: name: local-provisioner-config namespace: default data: storageClassMap: | local-volume: hostDir: /data/local mountDir: /data/local blockCleanerCommand: - "/scripts/shred.sh" - "2" volumeMode: Filesystem fsType: ext4 --- apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: local-volume-provisioner namespace: default labels: app: local-volume-provisioner spec: selector: matchLabels: app: local-volume-provisioner template: metadata: labels: app: local-volume-provisioner spec: serviceAccountName: local-volume-admin containers: - image: "silenceshell/local-volume-provisioner:v2.1.0" imagePullPolicy: "Always" name: provisioner securityContext: privileged: true env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName volumeMounts: - mountPath: /etc/provisioner/config name: provisioner-config readOnly: true - mountPath: /data/local name: local mountPropagation: "HostToContainer" volumes: - name: provisioner-config configMap: name: local-provisioner-config - name: local hostPath: path: /data/local --- apiVersion: v1 kind: ServiceAccount metadata: name: local-volume-admin namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: local-volume-provisioner-pv-binding namespace: default subjects: - kind: ServiceAccount name: local-volume-admin namespace: default roleRef: kind: ClusterRole name: system:persistent-volume-provisioner apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: local-volume-provisioner-node-clusterrole namespace: default rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: local-volume-provisioner-node-binding namespace: default subjects: - kind: ServiceAccount name: local-volume-admin namespace: default roleRef: kind: ClusterRole name: local-volume-provisioner-node-clusterrole apiGroup: rbac.authorization.k8s.io
kubectl创建后,由于是daemonset类型,每个节点上都会启动一个provisioner。该provisioner会监视 “discovery directory”,即上面配置的 /data/local
。
$ kubectl get pods -o wide|grep local-volume local-volume-provisioner-rrsjp 1/1 Running 0 5m 10.244.1.141 ubuntu-2 <none> local-volume-provisioner-v87b7 1/1 Running 0 5m 10.244.2.69 ubuntu-3 <none> local-volume-provisioner-x65k9 1/1 Running 0 5m 10.244.0.174 ubuntu-1 <none>
前面 mypod/myclaim
已经删除了,我们重新创建一个,此时pvc myclaim是Pending状态,provisoner并没有自动供给存储。为什么呢?
原来 external-storage
的逻辑是这样的:其Provisioner本身其并不提供local volume,但它在各个节点上的provisioner会去动态的“发现”挂载点(discovery directory),当某node的provisioner在 /data/local/
目录下发现有挂载点时,会创建PV,该PV的 local.path
就是挂载点,并设置nodeAffinity为该node。
那么如何获得挂载点呢?
直接去创建目录是行不通的,因为provsioner希望PV是隔离的,例如capacity,io等。试着在ubuntu-2上的 /data/local/
下创建一个 xxx
目录,会得到这样的告警。
discovery.go:201] Path "/data/local/xxx" is not an actual mountpoint
目录不是挂载点,不能用。
该目录必须是真材实料的mount才行。一个办法是加硬盘、格式化、mount,比较麻烦,实际可以通过本地文件格式化(loopfs)后挂载来“欺骗”provisioner,让它以为是一个mount的盘,从而自动创建PV,并与PVC绑定。
如下。
将下面的代码保存为文件 loopmount
,加执行权限并拷贝到 /bin
目录下,就可以使用该命令来创建挂载点了。
#!/bin/bash # Usage: sudo loopmount file size mount-point touch $1 truncate -s $2 $1 mke2fs -t ext4 -F $1 1> /dev/null 2> /dev/null if [[ ! -d $3 ]]; then echo $3 " not exist, creating..." mkdir $3 fi mount $1 $3 df -h |grep $3
使用脚本创建一个6G的文件,并挂载到 /data/local
下。之所以要6G,是因为前面PVC需要的是5GB,而格式化后剩余空间会小一点,所以设置文件更大一些,后面才好绑定PVC。
# loopmount xxx 6G /data/local/xxx /data/local/xxx not exist, creating... /dev/loop0 5.9G 24M 5.6G 1% /data/local/x1
查看PV,可见Provisioner自动创建了PV,而kubernetes会将该PV供给给前面的PVC myclam,mypod也run起来了。
# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE local-pv-600377f7 5983Mi RWO Delete Bound default/myclaim local-volume 1s
可见,目前版本的local volume还无法做到像cephfs/RBD一样的全自动化,仍然需要管理员干涉,显然这不是一个好的实现。
社区有人提交了基于LVM做local volume动态供给的 Proposal ,不过进展很缓慢。作者是huawei的员工,应该huawei已经实现了。
除了基于LVM,也可以基于 ext4 project quota
来实现LV的动态供给。
除了使用磁盘,还可以考虑使用内存文件系统,从而获取更高的io性能,只是容量就没那么理想了。一些特殊的应用可以考虑。
mount -t tmpfs -o size=1G,nr_inodes=10k,mode=700 tmpfs /data/local/tmpfs
总的来说,local volume本地卷目前不支持动态供给,还无法真正推广使用,但可以用来解决一些特定问题。
Ref:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 支持向量机(一):支持向量机的分类思想
- Vardump 更新,支持打印各种 Java 数据结构,支持嵌套
- Vardump 更新,支持打印各种 Java 数据结构,支持嵌套
- NutzBoot v2.1.5 添加单元测试支持及 ssdb 支持
- iView 3.1.0 版本:支持 TypeScript,支持 Vue CLI 3
- Mesalink v1.0.0 发布,正式支持 TLS 1.3 和 IPv6,支持CMake编译,支持Windows,实现生产环境可用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML Dog
Patrick Griffiths / New Riders Press / 2006-11-22 / USD 49.99
For readers who want to design Web pages that load quickly, are easy to update, accessible to all, work on all browsers and can be quickly adapted to different media, this comprehensive guide represen......一起来看看 《HTML Dog》 这本书的介绍吧!