基于 Kubernetes 1.22 版本
官方文档:
一、介绍
Local 卷表示配置的本地存储设备,如磁盘、分区或目录。Local 卷只能用作静态创建的PV,不支持动态资源调配。
与 hostPath 卷相比,Local 卷以持久和可移植的方式使用,无需手动将 POD 调度到节点。系统通过查看 PV 上的节点关联来了解卷的节点约束。
注意,Local 卷取决于基础节点的可用性,并不适用于所有应用程序。如果节点变得不正常,则 Pod 将无法访问本地卷,使用此卷的 Pod 无法运行。使用 Local 卷的应用程序必须能够容忍这种可用性降低以及潜在的数据丢失,这取决于底层磁盘的耐久性特征。
以下示例显示了使用 Local 卷和 nodeAffinity 的 PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- example-node
使用 Local 卷时必须设置 PV 的 nodeAffinity。 Kubernetes 调度程序使用 PV 的 nodeAffinity 将这些 Pod 调度到正确的节点。
PV 的 volumeMode 可以设置为“Block”(而不是默认值“Filesystem”)以将 Local 卷公开为原始块设备。
使用 Local 卷时,建议创建一个 StorageClass,volumeBindingMode 设置为 WaitForFirstConsumer。即延迟绑定,即创建 PVC 后,并不立刻执行绑定操作,而是要等到该 PVC 被使用时,调度器再综合考虑这个 Pod 声明的 PVC,到底应该跟哪个 PV 进行绑定。
通过这个延迟绑定机制,原本实时发生的 PVC 和 PV 的绑定过程,就被延迟到了 Pod 第一次调度的时候在调度器中进行,从而保证了这个绑定结果不会影响 Pod 的正常调度。
二、示例演示
先创建一个 Local StorageClass:
[root@cp storageclass]# cat local.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
[root@cp storageclass]# kubectl apply -f local.yaml
[root@cp storageclass]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local kubernetes.io/no-provisioner Delete WaitForFirstConsumer false 5s
现在创建一个PV:
[root@cp storageclass]# cat test-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: test-pv
spec:
capacity:
storage: 1Mi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local
local:
path: /data
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cp
[root@cp storageclass]# kubectl apply -f test-pv.yaml
[root@cp storageclass]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
test-pv 1Mi RWO Retain Available local 6s
我们这里定义了一个 local 字段,表明它是一个 Local PV。path 字段,指定的正是这个 PV 对应的本地磁盘的路径。这也就意味着如果 Pod 要想使用这个 PV,那它就必须运行在 cp 节点上。所以,在这个 PV 的定义里,添加了一个节点亲和性 nodeAffinity 字段指定 cp 这个节点。这样,调度器在调度 Pod 的时候,就能够知道一个 PV 与节点的对应关系,从而做出正确的选择。
创建一个 PVC:
[root@cp storageclass]# cat test-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Mi
storageClassName: local
[root@cp storageclass]# kubectl apply -f test-pvc.yaml
persistentvolumeclaim/test-pvc created
[root@cp storageclass]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-pvc Pending local 5s
[root@cp storageclass]# kubectl describe pvc test-pvc | tail -n1
Normal WaitForFirstConsumer 12s (x3 over 35s) persistentvolume-controller waiting for first consumer to be created before binding
我们可以看到上述 PVC 处于待绑定状态,创建一个Pod 来使用这个 PVC:
[root@cp storageclass]# cat test-pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox:stable
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-pvc
[root@cp storageclass]# kubectl apply -f test-pod.yaml
[root@cp storageclass]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-pvc Bound test-pv 1Mi RWO local 5m35s
[root@cp storageclass]# tree /data/
/data/
└── SUCCESS