网站建设淘宝客模板下载,线上代运营公司,怎么制作游戏地图,网站建设教程特别棒湖南岚鸿权 威前言
环境#xff1a;k8s 1.22.17 、centos7.9 有时候#xff0c;为了使用本地服务器上的磁盘存储资源#xff0c;我们会使用hostPath这种方式来为k8s提供本地存储#xff0c;本篇就来对比一下hostPath、local这两种使用本地服务器储存的方案#xff0c;从而引出第三种lo…前言
环境k8s 1.22.17 、centos7.9 有时候为了使用本地服务器上的磁盘存储资源我们会使用hostPath这种方式来为k8s提供本地存储本篇就来对比一下hostPath、local这两种使用本地服务器储存的方案从而引出第三种local-path本地储存。
hostPath卷
hostPath 卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中但是我们知道pod重启后会随机调度所以就需要为pod固定主机节点。下面仅演示hostPath的使用方法挂载一个宿主机上的目录到pod中
#hostPath示例一
#pod中直接使用hostPath卷
[rootmatser data]# vim nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:nodeName: master #固定pod能调度的节点确保pod重启后仍能访问之前的数据containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /var/log/nginx #持久化日志name: hostpath-volumerestartPolicy: Alwaysvolumes:- name: hostpath-volumehostPath: #hostPath卷path: /data/nginx #使用宿主机上的/data/nginx目录type: DirectoryOrCreatekubectl apply -f nginx.yaml
kubectl delete -f nginx.yaml#hostPath示例二
#pod中使用pvcpvc与pv关联pv中定义hostPathpod固定调度节点
[rootmatser data]# cat hostPath.yaml
apiVersion: v1
kind: PersistentVolume
metadata:name: hostpath-pvlabels:type: local
spec:storageClassName: capacity:storage: 10GiaccessModes:- ReadWriteManyhostPath:path: /data/nginxtype: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: hostpath-pvc
spec:accessModes:- ReadWriteManyresources:requests:storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:nodeName: master #固定pod能调度的节点确保pod重启后仍能访问之前的数据containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /var/log/nginxname: hostpath-volumerestartPolicy: Alwaysvolumes:- name: hostpath-volumepersistentVolumeClaim: #使用pvcclaimName: hostpath-pvc
[rootmatser data]#
#创建完成pv和pvc,当pvc与pv绑定之后发现并没有创建hostPath目录只有当pod调度到节点上时才会真正创建hostPath目录。
#当pod重启之后如果pod没有指定调度的节点则仍然会在其他节点创建hostPath目录所以为了使pod能访问之前的数据都要把pod固定调度到指定节点。#hostPath示例三
#pod中使用pvcpvc与pv关联pv中定义hostPath且定义节点亲和性#为节点打标签只打了一个节点如果是多个节点那么pod会随机调度到这些节点数据就没有唯一性而言。
[rootmatser data]# kubectl label nodes node2 storagetrue
[rootmatser data]# cat hostPath.yaml
apiVersion: v1
kind: PersistentVolume
metadata:name: hostpath-pvlabels:type: local
spec:storageClassName: capacity:storage: 10GiaccessModes:- ReadWriteManyhostPath:path: /data/nginxtype: DirectoryOrCreatenodeAffinity: #定义了节点亲和性required:nodeSelectorTerms:- matchExpressions: - key: storageoperator: Invalues:- true
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: hostpath-pvc
spec:accessModes:- ReadWriteManyresources:requests:storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec: #pod中不在指定调度节点而是有pv中定义了节点亲和性k8s会根据pv的节点亲和性来判断pod要调度到哪些节点containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /var/log/nginxname: hostpath-volumerestartPolicy: Alwaysvolumes:- name: hostpath-volumepersistentVolumeClaim:claimName: hostpath-pvc
[rootmatser data]# hostPath卷总结我们发现无论是pod中直接使用hostPath还是pod调用pvcpvc调用pvpv中使用hostPath两者本质上没啥区别示例1和实例2中都在pod中固定了调度节点而实例3是在pv中定义了节点亲和性。
local卷
local 卷所代表的是某个被挂载的本地存储设备例如磁盘、分区或者目录。 local 卷只能用作静态创建的持久卷。不支持动态配置。
与 hostPath 卷相比local 卷能够以持久和可移植的方式使用而无需手动将 Pod 调度到节点。系统通过查看 PersistentVolume 的节点亲和性配置就能了解卷的节点约束。然而local 卷仍然取决于底层节点的可用性并不适合所有应用程序。 如果节点变得不健康那么 local 卷也将变得不可被 Pod 访问。使用它的 Pod 将不能运行。 使用 local 卷的应用程序必须能够容忍这种可用性的降低以及因底层磁盘的耐用性特征而带来的潜在的数据丢失风险。
下面是一个使用 local 卷和 nodeAffinity 的持久卷示例
#local的使用和上面示例三hostPath卷的使用没多大区别如下
[rootmatser data]# cat local.yaml
apiVersion: v1
kind: PersistentVolume
metadata:name: local-pv
spec:capacity:storage: 10GivolumeMode: FilesystemaccessModes:- ReadWriteManypersistentVolumeReclaimPolicy: Retainlocal: #这里定义的是local卷path字段定义的是目录这个目录必须先创建path: /data/nginxnodeAffinity: #节点亲和性required:nodeSelectorTerms:- matchExpressions:- key: storageoperator: Invalues:- true
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: local-pvc
spec:accessModes:- ReadWriteManyresources:requests:storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:containers: #没有定义节点选择器k8s会根据pv定义的节点亲和性来调度pod- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /var/log/nginxname: local-volumerestartPolicy: Alwaysvolumes:- name: local-volumepersistentVolumeClaim:claimName: local-pvc
[rootmatser data]#
使用 local 卷时你需要设置 PersistentVolume 对象的 nodeAffinity 字段。 Kubernetes 调度器使用 PersistentVolume 的 nodeAffinity 信息来将使用 local 卷的 Pod 调度到正确的节点。
PersistentVolume 对象的 volumeMode 字段可被设置为 Block 而不是默认值 Filesystem以将 local 卷作为原始块设备暴露出来。
使用 local 卷时建议创建一个 StorageClass 并将其 volumeBindingMode 设置为 WaitForFirstConsumer。要了解更多详细信息请参考 local StorageClass 示例。 延迟卷绑定的操作可以确保 Kubernetes 在为 PersistentVolumeClaim 作出绑定决策时会评估 Pod 可能具有的其他节点约束例如如节点资源需求、节点选择器、Pod 亲和性和 Pod 反亲和性。总结local卷和hostPath没啥区别都可以通过在pv中定义节点亲和性这样使用该pv的pod就会被k8s调度到指定的节点。唯一区别的是local可以使用裸设备磁盘、分区、目录而hostPath只能是文件或目录。
local-path-provisioner动态供给localPath或local卷
无论是hostPath卷还是local 卷他们都不支持动态扩容而local-path-provisioner很好的弥补了这一缺陷。
kubernetes-sigs版https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner
注意kubernetes-sigs版不支持动态扩容/动态供给dynamically provisioning所以建议使用rancher版。这里介绍的都是rancher版。
rancher版https://github.com/rancher/local-path-provisioner下载local-path-provisioner yml文件
# 进入https://github.com/rancher/local-path-provisioner里面有很详细的安装教程
#安装local-path-provisioner
wget https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.24/deploy/local-path-storage.yaml查看官方configmap解析
#local-path-storage.yaml中定义了一个configmap我们先来看下官方样例中对这个cm的介绍.
provisioner的配置存储在一个configmap中configmap包含1个json文件配置即config.json、1个Pod模板即helperPod.yaml、两个bash脚本即setup和teardown如下所示kind: ConfigMap
apiVersion: v1
metadata:name: local-path-confignamespace: local-path-storage
data:config.json: |-{nodePathMap:[{node:DEFAULT_PATH_FOR_NON_LISTED_NODES,paths:[/opt/local-path-provisioner]},{node:yasker-lp-dev1,paths:[/opt/local-path-provisioner, /data1]},{node:yasker-lp-dev3,paths:[]}]}setup: |-#!/bin/shset -eumkdir -m 0777 -p $VOL_DIRteardown: |-#!/bin/shset -eurm -rf $VOL_DIRhelperPod.yaml: |-apiVersion: v1kind: Podmetadata:name: helper-podspec:containers:- name: helper-podimage: busyboxnodePathMap字段是一个数组用于自定义在每个节点上存储数据的位置。
如果一个节点没有在nodePathMap上列出而Kubernetes想要在它上面创建卷那么default_path_for_non_listd_nodes中指定的路径将被用于分配。
如果nodePathMap上列出了一个节点则将使用paths中指定的路径进行发放。
如果仅列出了节点但路径设置为[]则提供程序将拒绝在该节点上提供服务。
如果节点上指定了多个路径则在provision供给时将随机选择路径。
规则路径必须是绝对路径路径不能是根/一个节点可以有多个不同的路径不能重复列出节点一个节点不能列出相同的路径。sharedFileSystemPath允许提供者使用同时挂载在所有节点上的文件系统。在这种情况下支持所有访问模式:ReadWriteOnce, ReadOnlyMany和ReadWriteMany存储声明。
另外volumeBindingMode: Immediate可以在StorageClass定义中使用。
请注意nodePathMap和sharedFileSystemPath是互斥的。如果使用sharedFileSystemPath则nodePathMap必须设置为[]。setup脚本在创建卷之前运行setup脚本来在节点上准备卷目录。
teardown脚本删除卷后运行teardown脚本清理节点上的卷目录。
helperPod.yaml模板用于创建一个helper pod用这个helper pod来执行setup和teardown脚本。provisioner支持自动热重载即可以在线修改local-path-config配置provisioner会自动生效配置从local-path-provisioner pod中可以查看日志如果provisioner生效失败则provisioner仍然会保持上一个有效的local-path-config配置。#指定local-path-provisioner创建的卷类型可以通过以下2种方式指定local-path-provisioner要给你创建什么类型的卷
当你手动创建PVC时在pvc的中添加以下注解:
annotations:volumeType: local or hostPath亦可以在存储类的定义中添加以下注解
StorageClass:
annotations:defaultVolumeType: local or hostPath需要注意的是StorageClass的注释将应用于使用它的所有卷如果PVC提供了注释则覆盖SC上的注释。如果这两个注解都没有提供那么默认使用hostPath。开始安装local-path-provisioner
#查看修改local-path-storage.yaml内容
[rootmatser data]# cat local-path-storage.yaml
apiVersion: v1
kind: Namespace
metadata:name: local-path-storage
---
apiVersion: v1
kind: ServiceAccount
metadata:name: local-path-provisioner-service-accountnamespace: local-path-storage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: local-path-provisioner-role
rules:- apiGroups: [ ]resources: [ nodes, persistentvolumeclaims, configmaps ]verbs: [ get, list, watch ]- apiGroups: [ ]resources: [ endpoints, persistentvolumes, pods ]verbs: [ * ]- apiGroups: [ ]resources: [ events ]verbs: [ create, patch ]- apiGroups: [ storage.k8s.io ]resources: [ storageclasses ]verbs: [ get, list, watch ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: local-path-provisioner-bind
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: local-path-provisioner-role
subjects:- kind: ServiceAccountname: local-path-provisioner-service-accountnamespace: local-path-storage
---
apiVersion: apps/v1
kind: Deployment
metadata:name: local-path-provisionernamespace: local-path-storage
spec:replicas: 1selector:matchLabels:app: local-path-provisionertemplate:metadata:labels:app: local-path-provisionerspec:serviceAccountName: local-path-provisioner-service-accountcontainers:- name: local-path-provisionerimage: rancher/local-path-provisioner:v0.0.24imagePullPolicy: IfNotPresentcommand:- local-path-provisioner- --debug- start- --config- /etc/config/config.jsonvolumeMounts:- name: config-volumemountPath: /etc/config/env:- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespacevolumes:- name: config-volumeconfigMap:name: local-path-config
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: local-pathannotations: #添加了注释表示StorageClass提供哪些卷类型可以是hostPath和local默认值为hostPathvolumeType: hostPath
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain #修改为Retain原来默认是Delete
allowVolumeExpansion: true #允许扩容
---
kind: ConfigMap
apiVersion: v1
metadata:name: local-path-confignamespace: local-path-storage
data:config.json: |-{nodePathMap:[{node:DEFAULT_PATH_FOR_NON_LISTED_NODES, #指定其它节点使用/data/local-path-provisioner目录作为存储paths:[/data/local-path-provisioner] #存储目录会自动创建},{node:master, #指定使用master节点的/opt/local-path-provisioner目录作为存储paths:[/opt/local-path-provisioner] #存储目录会自动创建} #如果不想让指定节点作为存储节点则需显示的列出来并且将该节点的path设置[]]}setup: |-#!/bin/shset -eumkdir -m 0777 -p $VOL_DIRteardown: |-#!/bin/shset -eurm -rf $VOL_DIRhelperPod.yaml: |-apiVersion: v1kind: Podmetadata:name: helper-podspec:containers:- name: helper-podimage: busyboximagePullPolicy: IfNotPresent
[rootmatser data]# kubectl apply -f local-path-storage.yaml创建pod、pvc进行验证
[rootmatser data]# cat local-path.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: local-path-pvc
spec:storageClassName: local-pathaccessModes:- ReadWriteOnceresources:requests:storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-179namespace: default
spec:replicas: 1selector:matchLabels:app: nginx-179template:metadata:labels:app: nginx-179spec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx-containerports:- containerPort: 80name: httpprotocol: TCPvolumeMounts:- mountPath: /usr/share/nginx/htmlname: local-path-volumerestartPolicy: Alwaysvolumes:- name: local-path-volumepersistentVolumeClaim:claimName: local-path-pvc
[rootmatser data]# kubectl apply -f local-path.yaml#验证发现pod随机调度到node2节点并且已经自动创建了/data/local-path-provisioner/目录并且存在权限是777的pvc-e04ceb06-1a30-4b83-8215-7786850f3d93_default_local-path-pvc目录所有动态分配pv验证成功了。#验证过程中发现pv其实还是具有节点亲和性的这说明当节点挂掉的时候pod无法重新调度到其他节点因为pod使用的pv定义节点亲和性
#这也难怪provisioner创建的卷类型本身就是hostPath或local卷。
[rootmatser data]# kubectl get pv pvc-0926a91c-854a-400f-be54-ad3fdd5e0051 -oyaml
apiVersion: v1
kind: PersistentVolume
metadata:........hostPath: #其实卷的类型仍是hostPathpath: /opt/local-path-provisioner/pvc-0926a91c-854a-400f-be54-ad3fdd5e0051_default_local-path-pvctype: DirectoryOrCreatenodeAffinity: #具有节点亲和性required:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- master
........存在的问题
#发现如果在pod中定义nodeName想让pod调度到某台节点pod会无法调度pod的events报错如下
[rootmatser data]# kubectl describe pod nginx-1791-5d444554cb-b2mvq
Events:Type Reason Age From Message---- ------ ---- ---- -------Warning FailedMount 6s kubelet Unable to attach or mount volumes: unmounted volumes[local-path-volume], unattached volumes[local-path-volume kube-api-access-c7h9m]: error processing PVC default/local-path-pvc1: PVC is not bound
查看pvc的报错如下
[rootmatser data]# kubectl describe pvc local-path-pvc1
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal WaitForFirstConsumer 5s (x2 over 15s) persistentvolume-controller waiting for first consumer to be created before binding这是怎么回事呢pod显示pvc没有绑定pvc又在等待pod来消费这不是死循环吗。如果pod中不指定nodeName让pod随机调度是能正常创建的但是一旦定义了nodeName就不能正常了这是什么回事呢local-path-provisioner仅支持ReadWriteOnce访问模式
在写pvc的时候如果将accessModes写成 ReadWriteMany则pvc将一直处于penging状态查看local-path-provisioner pod的日志或kubectl describe pvc local-path-pvc 发现了以下报错 Type Reason Age From Message---- ------ ---- ---- -------Normal WaitForFirstConsumer 11m persistentvolume-controller waiting for first consumer to be created before bindingNormal ExternalProvisioning 102s (x42 over 11m) persistentvolume-controller waiting for a volume to be created, either by external provisioner rancher.io/local-path or manually created by system administratorNormal Provisioning 52s (x7 over 11m) rancher.io/local-path_local-path-provisioner-6464fcbd8b-bhmqs_d68778ed-2a18-4f48-9788-1b2dc0f2b88f External provisioner is provisioning volume for claim default/local-path-pvcWarning ProvisioningFailed 52s (x7 over 11m) rancher.io/local-path_local-path-provisioner-6464fcbd8b-bhmqs_d68778ed-2a18-4f48-9788-1b2dc0f2b88f failed to provision volume with StorageClass local-path: Only support ReadWriteOnce access mode
[rootmatser data]# kubectl describe pvc local-path-pvc
#怎么local-path-provisioner创建的pv仅支持ReadWriteOnce访问模式而已的呢卸载local-path-provisioner
#1、手动删除pv确保已经没有pv是使用local-path 这个存储类的
#2、kubectl delete -f local-path-storage.yaml
#3、手动删除节点上的目录总结
1、pod中直接使用hostPath来挂载宿主机的指定目录但是为了防止pod重启后没有调度到上一次调度的宿主机节点所以pod中需要定义nodeName指定调度主机。
2、可以在pv中使用hostPath然后创建pvc与pv进行绑定然后pod中使用pvc即可pod中仍需要定义nodeName指定调度主机。
3、可以在pv中使用hostPath并且pv中定义节点亲和性然后创建pvc与pv进行绑定然后pod中使用pvc即可此时pod中不需要定义nodeName指定调度主机k8s会根据pv中定义的节点亲和性来选择调度pod这样其实也是间接的指定了pod要调度的主机。
4、local的使用和上面第3点相同都是在pv中定义节点亲和性local与hostPath的区别在于local可以使用裸设备、目录、分区而hostPath只能是目录或文件。
5、local和hostPath都没有动态供给都是手动的。
6、引入local-path-provisioner只是为了实现local或hostPath的动态供给。
7、创建一个local-path-provisioner 的pod、存储类、cm、服务账号等资源对象来实现动态供给。
8、本质上local-path-provisioner提供的卷仍是hostPath或local所以local-path-provisioner提供的pv仍是具有节点亲和性的这就说明当宿主机挂机了的时候由于pod绑定的pv具有节点亲和性所以pod无法在其他节点重新调度pod就会存在故障。这其实就是hostPath、local卷的劣势。
9、使用local-path-provisioner动态供给pv发现pod无法使用nodeName节点选择器这一点有待研究。
10、使用local-path-provisioner动态供给pvpvc只能是ReadWriteOnce因为local-path-provisioner pod显示StorageClass local-path: Only support ReadWriteOnce access mode