Kubernetes Volume 使用方法

常用 Volume 类型

以下是几种可用卷类型:

  • emptyDir - 用于存储临时数据的简单空目录,生命周期和 Pod 一致。
  • hostPath - 用于将宿主机中的文件系统挂载到 Pod 中,生命周期不与 Pod 绑定。
  • gitRepo - 通过拉取 Git 仓库的内容来初始化的卷。已弃用
  • nfs - 挂载到 Pod 中的 NFS 共享文件系统。
  • configMapsecret - 用于将 Kubernetes 中的部分资源和集群信息公开给 Pod 的特殊类型的卷
  • persistentVolumeClaim - 简称 PVC,使用预置和动态配置的持久卷。
  • downwardAPI - 在不使用 Kubernetes 客户端或 API 服务器的情况下获得自己或集群的信息 [5]

emptyDir 卷

emptyDir 表示与 Pod 生命周期相同的临时目录。[4]

emptyDir 配置示例

apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir:
sizeLimit: 500Mi
medium: Memory
  • emptyDir.medium - 表示此目录应使用哪种类别的存储介质,默认为 "",表示使用节点的默认介质(一般是节点的本地磁盘)。可选值必须为 "" 或者 MemoryMemory 表示使用 tmfs (存在内存而非硬盘)

PersistentVolume 和 PersistentVolumeClaim

PersistentVolume (PV)(持久化卷),是对底层的共享存储的一种抽象,PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 CephGlusterFSNFS 等,都是通过插件机制完成与共享存储的对接。[1]

PersistentVolumeClaim(PVC)是由用户发起的对存储的请求。 它类似于 Pod。 Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU和内存)。PVC 可以请求特定的存储大小和访问模式(例如,可以一次读/写或多次只读)匹配的 PV。

PVCPV 中的 spec 关键字段要匹配,比如存储(storage)大小、读写模式,才能申请到对应的 PV 中的资源。PV 和 PVC 处于一一对应的关系。 [2]

PV 可以设置三种回收策略:

  • 保留(Retain) - 保留产生的数据,PV 不进行处理
  • 回收(Recycle) - 将执行清除操作,之后可以被新的pvc使用,需要插件支持。NFS 支持全部 3 种。
  • 删除(Delete) - 删除pv和外部关联的存储资源,需要插件支持。

PV卷阶段状态

  • Available – 资源尚未被 claim 使用
  • Bound – 卷已经被绑定到 claim 了
  • Released – claim 被删除,卷处于释放状态,但未被集群回收。
  • Failed – 卷自动回收失败

NFS 作为 PV

NFS 服务部署参考

创建 PV

PV 属于集群级别的资源,不属于任何 namespace

apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-1

spec:
accessModes:
- ReadWriteMany
- ReadOnlyMany
capacity:
storage: 100Gi
nfs:
path: /data/NFSDataHome
server: 34.230.1.1
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem

---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-2
labels:
name: nfs-pv-2
spec:
nfs:
path: /k8s_volumes/v2
server: 192.168.0.3
accessModes: ["ReadWriteOnce"]
persistentVolumeReclaimPolicy: Retain
capacity:
storage: 5Gi

以上配置分别创建了 PV

  • nfs-pv-1 - accessModes["ReadWriteMany", "ReadOnlyMany"],大小为 100Gi
  • nfs-pv-2 - accessModes["ReadWriteOnce"],大小为 5Gi

查看 PV

$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
uat-nfs 100Gi RWX Retain Available 100s

创建对应的 PVC 申请 PV 存储资源

PVC 属于 Namespace 基本的资源,需要在相应的 Namespace 中使用。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 100Gi

以上 PVC 会匹配到持久卷 nfs-pv-1

查看 PVC

kubectl get pvc -A

使用 PVC

apiVersion: v1
kind: Pod
metadata:
name: vol-pvc
namespace: default
spec:
volumes:
- name: html
persistentVolumeClaim:
claimName: mypvc
containers:
- name: myapp
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
# subPath: logs/admin

k8s 该 Pod 所在 NODE 节点服务器需要安装 nfs-utils,否则挂载会报错,POD 无法运行。建议每台节点都安装

Pod 成功运行后,进入对应容器,会看到容器中通过 NFS 方式挂载了 NFS 共享存储。

$ kubectl exec -it vol-pvc -- df -h
Filesystem Size Used Avail Use% Mounted on
overlay 36G 3.4G 32G 10% /
tmpfs 64M 0 64M 0% /dev
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/centos-root 36G 3.4G 32G 10% /etc/hosts
shm 64M 0 64M 0% /dev/shm
192.168.0.3:/k8s_volumes/v4 3.6T 1.9T 1.6T 55% /usr/share/nginx/html
tmpfs 2.0G 12K 2.0G 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs 2.0G 0 2.0G 0% /proc/acpi
tmpfs 2.0G 0 2.0G 0% /proc/scsi
tmpfs 2.0G 0 2.0G 0% /sys/firmware

以上方法创建的 PV 为静态 PV,此种情况下,PV 和 PVC 具有一对一的绑定关系,即一个 PV 只能绑定到一个 PVC,如果要在另一个 Namespace 中使用同一个的 PV,是不被允许的,此时 PVC 会绑定失败: no persistent volumes available for this claim and no storage class is set

常见错误

PV 处于 Released 状态,新建 PVC 处于 Pending 状态

$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
uat-nfs 100Gi ROX,RWX Retain Bound default/pvc-admin 62m

$ kubectl get pvc -A
NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
default pvc-admin Bound uat-nfs 100Gi ROX,RWX 29s

如上所示,创建 PVC 后,PV 处于 Bound 状态,此时创建其他内容一样,只是 matadata.name 不同的 PVC ,PVC 无法成功创建,状态为 Pending

$ kubectl get pvc -A
NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
default pvc-api Pending 2m30s
default pvc-admin Bound uat-nfs 100Gi ROX,RWX 71m

查看新建的 PVC pvc-api 的描述信息

$ kubectl describe pvc pvc-api -n default
Name: pvc-api
Namespace: default
StorageClass:
Status: Pending
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal FailedBinding 14s (x12 over 2m48s) persistentvolume-controller no persistent volumes available for this claim and no storage class is set

结果显示 no persistent volumes available for this claim and no storage class is set,这是因为 PV 已经分配到了 PVC,无法再进行分配。

此时查看 PV 状态,处于 Bound 状态,CLAIM 为第一次创建 PVC

$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
uat-nfs 100Gi ROX,RWX Retain Bound default/pvc-admin 135m

此种情况下,执行以下命令手动删除已分配的 PVC

kubectl delete pvc -n default      pvc-admin

再次查看 PVC

$ kubectl get pvc -A
NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
default pvc-api Pending

$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
uat-nfs 100Gi ROX,RWX Retain Released default/pvc-admin 140m

发现 PVC 依然处于 Pending 状态,而 PV 状态变为了 Released,无法再分配给其他 PVC。

解决方法
  • 删除 PV
    手动删除 PV,因为之前创建的 PV,其回收策略为 Retain,PV 删除后,数据依然存在。如果需要此存储作为 PV,创建新的 PV 即可,然后针对不同的 Namespace 创建对应的 PVC
  • 修改 PV 的回收策略
    执行以下命令,修改 PV 的回收策略 [3]
    kubectl patch pv PV_NAME -p '{"spec":{"claimRef": null}}'

脚注