Local Volume
https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/#local
https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/#local
hostPath 存在的问题
过去我们经常会通过hostPath volume让Pod能够使用本地存储,将Node文件系统中的文件或者目录挂载到容器内,但是hostPath volume的使用是很不方便的,并不适合在生产环境中使用。
由于集群内每个节点的差异化,要使用hostPath Volume,我们需要通过NodeSelector等方式进行精确调度,比较繁琐。
注意DirectoryOrCreate和FileOrCreate两种类型的hostPath,当Node上没有对应的File/Directory时,你需要保证kubelet有在 Node上Create File/Directory的权限。
另外,如果Node上的文件或目录是由root创建的,挂载到容器内之后,你通常还要保证容器内进程有权限对该文件或者目录进行写入,比如你需要以root用户启动进程并运行于privileged容器,
或者你需要事先修改好Node上的文件权限配置。
Scheduler并不会考虑hostPath volume的大小,hostPath也不能申明需要的storagesize,这样调度时存储的考虑,就需要人为检查并保证。
Local Volume PV 和常规 PV 的区别
对于常规的 PV,Kubernetes 都是先调度 Pod 到某个节点上,然后再持久化” 这台机器上的 Volume 目录。而 Local PV,则需要运维人员提前准备好节点的磁盘。它们在不同节点上的挂载情况可以完全不同,甚至有的节点可以没这种磁盘。所以调度器就必须能够知道所有节点与 Local Persistent Volume对应的磁盘的关联关系,然后根据这个信息来调度 Pod。也就是在调度的时候考虑 Volume 分布。
k8s v1.10+以上的版本中推出local pv方案。Local volume 允许用户通过标准 PVC 接口以简单且可移植
的方式访问 node 节点的本地存储。 PV 的定义中需要包含描述节点亲和性的信息,k8s 系统则使用该信
息将容器调度到正确的 node 节点。
local Volume 所代表的是某个被挂载的本地存储设备,例如磁盘、分区或者目录。
在 Kubernetes 中,HostPath 和 Local Volume 都可以用于将主机上的文件系统挂载到容器内部。虽然
它们有一些相似之处,但是它们之间也有一些重要的区别。
HostPath卷类型会直接挂载主机的文件系统到Pod中,这个文件系统可以是一个文件或者是一个目录。
当Pod被调度到一个节点上时,该节点上的文件系统就会被挂载到Pod中。这使得可以很容易地在容器
内部访问主机上的文件,例如主机上的日志或配置文件。但是,使用 HostPath 卷类型可能会存在安全
风险,因为容器可以访问主机上的所有文件和目录,包括其他容器的文件。
相比之下,Local Volume 卷类型只能将节点上的一个目录挂载到容器内部。当Pod被调度到一个节点上
时,Kubernetes 会为该节点创建一个唯一的目录,并将该目录挂载到 Pod 中。因为每个 Pod 只能访问
其本地的 Local Volume 目录,所以这种卷类型更加安全。但是,如果节点故障或被删除,Local
Volume 中的数据将会丢失。因此,使用 Local Volume 卷类型需要谨慎,需要确保有备份机制或持久化
存储。
local Volume 默认不支持动态配置,只能用作静态创建的持久卷。但可以采有第三方方案实现动态配置
local 类型的PV是一种更高级的本地存储抽象,它可以允许通过StorageClass来进行管理。
与 hostPath 卷相比, local 卷能够以持久和可移植的方式使用,而无需手动将 Pod 调度到节点
同样使用节点上的本地存储,但相比于 hostPath , local Volume可以声明为动态供应,并且可以利
用节点亲和性标签(nodeAffinity)实现存储亲和性,确保Pod调度到包含所需数据的节点上。而
hostPath卷在Pod重建后可能会调度至新的节点,而导致旧的数据无法使用
可以通过查看 PersistentVolume 的节点亲和性配置,就能了解卷的节点约束。
然而, local 卷仍然取决于底层节点的可用性,并不适合所有应用程序。 如果节点变得不健康,那么
local 卷也将变得不可被 Pod 访问。使用它的 Pod 将不能运行。 使用 local 卷的应用程序必须能够
容忍这种可用性的降低,以及因底层磁盘的耐用性特征而带来的潜在的数据丢失风险。
Local Volume PV 优势
两者都是使用宿主机节点本地存储
Local Volume PV 支持指定PV的存储大小,而HostPath不支持
Pod调度至哪个节点由Local Volume PV所在的节点决定,HostPath是由Pod决定HostPath所在节点
由存储管理员指定PV所在的节点做为Pod运行的节点,而非由用户决定
Local Volume 的实现
LocalPV 的实现可以理解为我们前面使用的 hostpath 加上 nodeAffinity ,比如:在宿主机 NodeA 上
提前创建好目录 ,然后在定义 Pod 时添加 nodeAffinity=NodeA ,指定 Pod 在我们提前创建好目录的
主机上运行。但是我们绝不应该把一个宿主机上的目录当作 PV 使用,因为本地目录的磁盘随时都可能
被应用写满,甚至造成整个宿主机宕机。而且,不同的本地目录之间也缺乏哪怕最基础的 I/O 隔离机
制。所以,一个 Local Persistent Volume 对应的存储介质,一定是一块额外挂载在宿主机的磁盘或者
块设备(“额外” 的意思是,它不应该是宿主机根目录所使用的主硬盘)。这个原则,我们可以称为 “一个
PV 一块盘”
Local Volume 使用场景
Local Persistent Volume 并不适用于所有应用。它的适用范围非常固定,比如:高优先级的系统应用,
需要在多个不同节点上存储数据,而且对 I/O 要求较高。Kubernetes 直接使用宿主机的本地磁盘目录
,来持久化存储容器的数据。它的读写性能相比于大多数远程存储来说,要好得多,尤其是 SSD 盘。
典型的应用包括:分布式数据存储比如 MongoDB,分布式文件系统比如 GlusterFS、Ceph 等,以及需
要在本地磁盘上进行大量数据缓存的分布式应用,其次使用 Local Persistent Volume 的应用必须具备
数据备份和恢复的能力,允许你把这些数据定时备份在其他位置。
创建 Local Volume PV
使用 Local 卷流程
- 创建 PV,使用 nodeAffinity 指定绑定的节点提供存储
- 创建 PVC,绑定PV的存储条件
- 创建Pod,引用前面的PVC和PV实现Local 存储
下面是一个使用 local 卷和 nodeAffinity 的持久卷示例:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:name: local-storage provisioner: kubernetes.io/no-provisioner # indicates that this StorageClass does not support automatic provisioning,表示该存储类不使用任何provisioner,即不支持动态分配持久卷。这意味着管理员需要手动创建并管理持久卷 volumeBindingMode: WaitForFirstConsumer #延迟绑定,只有Pod准备好才绑定PV至PVC,否则PVC处于Pending状态,支持Immediate和waitForFirstConsumer --- apiVersion: v1 kind: PersistentVolume metadata:name: example-pv spec:capacity:storage: 100GivolumeMode: FilesystemaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: DeletestorageClassName: local-storagelocal:path: /mnt/disks/ssd1 #宿主机节点的磁盘目录,此目录需要人为提前创建nodeAffinity: ##宿主机节点亲和性 required:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- example-node --- kind: PersistentVolumeClaim apiVersion: v1 metadata:name: local-pvc spec:accessModes:- ReadWriteOnceresources:requests:storage: 10GistorageClassName: local-storage#selector: # 支持使用指定的PV# matchLabels:# pv: example-pv #指定关联label为pv: example-pv的PV
使用 local 卷时,你需要设置 PersistentVolume 对象的 nodeAffinity 字段。 Kubernetes 调度器
使用 PersistentVolume 的 nodeAffinity 信息来将使用 local 卷的 Pod 调度到正确的节点。
PersistentVolume 对象的 volumeMode 字段可被设置为 "Block" (而不是默认值 "Filesystem"),以
将 local 卷作为原始块设备暴露出来。
使用 local 卷时,建议创建一个 StorageClass 并将其 volumeBindingMode 设置为
WaitForFirstConsumer 。要了解更多详细信息,请参考 local StorageClass 示例。 延迟卷绑定的操作
可以确保 Kubernetes 在为 PersistentVolumeClaim 作出绑定决策时,会评估 Pod 可能具有的其他节点
约束,例如:如节点资源需求、节点选择器、Pod 亲和性和 Pod 反亲和性。
https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/#local
案例
范例:基于 StorageClass 实现 Local 卷
范例:
#事先在PV所在的目标节点上准备目录,对于本地存储Kubernetes本身并不会自动创建路径,这是因为Kubernetes不能控制节点上的本地存储,因此无法自动创建路径
[root@node2 ~]# mkdir -p /data/mysql
volumeBindingMode: WaitForFirstConsumer #延迟绑定,只有Pod启动后再绑定PV到Pod所在节点,否则PVC处理Pending状态
[root@master1 storage]# cat storage-sc-local-pv-pvc-mysql-pod.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer #延迟绑定,只有Pod启动后再绑定PV到Pod所在节点,否则PVC处理Pending状态--- apiVersion: v1 kind: PersistentVolume metadata:name: pv-sc-local spec:capacity:storage: 100GivolumeMode: FilesystemaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: Delete #因为静态置配,所以当PVC删除后,不会删除PV和数据storageClassName: local-storagelocal:path: /data/mysqlnodeAffinity:required:nodeSelectorTerms: #指定节点- matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- node2.org--- apiVersion: v1 kind: PersistentVolumeClaim metadata:name: pvc-sc-local spec:storageClassName: local-storageaccessModes: ["ReadWriteOnce"]resources:requests:storage: 100Gi
kubectl apply -f storage-sc-local-pv-pvc-mysql-pod.yaml
没有pod绑定不上去,pending状态,以前只要有pvc,pv就可以绑定
[root@master1 storage]# kubectl get pv,pvc NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE persistentvolume/pv-sc-local 100Gi RWO Delete Available local-storage <unset> 7sNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE persistentvolumeclaim/pvc-sc-local Pending local-storage <unset> 7s [root@master1 storage]#
[root@master1 storage]# kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE local-storage kubernetes.io/no-provisioner Delete WaitForFirstConsumer false 48s
#此SC只负责定义volumeBindingMode,没有实现自动创建PV的动态置备功能,也可以不创建此SC
[root@master1 storage]# cat storage-sc-local-pv-pvc-mysql-pod.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer #延迟绑定,只有Pod启动后再绑定PV到Pod所在节点,否则PVC处理Pending状态--- apiVersion: v1 kind: PersistentVolume metadata:name: pv-sc-local spec:capacity:storage: 100GivolumeMode: FilesystemaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: Delete #因为静态置配,所以当PVC删除后,不会删除PV和数据storageClassName: local-storagelocal:path: /data/mysqlnodeAffinity:required:nodeSelectorTerms: #指定节点- matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- node2.org--- apiVersion: v1 kind: PersistentVolumeClaim metadata:name: pvc-sc-local spec:storageClassName: local-storageaccessModes: ["ReadWriteOnce"]resources:requests:storage: 100Gi --- apiVersion: apps/v1 kind: Deployment metadata:name: mysql spec:selector:matchLabels:app: mysqlstrategy:type: Recreatetemplate:metadata:labels:app: mysqlspec:containers:- image: registry.cn-beijing.aliyuncs.com/wangxiaochun/mysql:8.0.29-oraclename: mysqlenv:# 在实际中使用 secret- name: MYSQL_ROOT_PASSWORDvalue: "123456"ports:- containerPort: 3306name: mysqlvolumeMounts:- name: mysql-persistent-storagemountPath: /var/lib/mysqlvolumes:- name: mysql-persistent-storagepersistentVolumeClaim:claimName: pvc-sc-local
mysql目录没有数据
[root@node2 ~]# ls /data/mysql
kubectl apply -f storage-sc-local-pv-pvc-mysql-pod.yaml
[root@master1 storage]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
pvc-sc-local Bound pv-sc-local 100Gi RWO local-storage <unset> 9m43s
固定调度到node2
[root@master1 storage]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES controller-deployment-demo-5f884bb8-2ppvf 1/1 Running 4 (142m ago) 26h 10.244.1.189 node1.org <none> <none> controller-deployment-demo-5f884bb8-fscrl 1/1 Running 13 (142m ago) 7d5h 10.244.1.183 node1.org <none> <none> controller-deployment-demo-5f884bb8-rfsbv 1/1 Running 12 (142m ago) 7d1h 10.244.1.187 node1.org <none> <none> mysql-7969d5744d-2tqs6 1/1 Running 0 30s 10.244.2.185 node2.org <none> <none>
node2 /data/mysql有数据
[root@node2 ~]# ls /data/mysqlauto.cnf binlog.index client-cert.pem '#ib_16384_1.dblwr' ib_logfile0 '#innodb_temp' mysql.sock public_key.pem sysbinlog.000001 ca-key.pem client-key.pem ib_buffer_pool ib_logfile1 mysql performance_schema server-cert.pem undo_001binlog.000002 ca.pem '#ib_16384_0.dblwr' ibdata1 ibtmp1 mysql.ibd private_key.pem server-key.pem undo_002 [root@node2 ~]#
