本文最后更新于 2025年8月14日 上午
Kubernetes通过将容器应用所需的存储资源抽象为Volume 来解决这些问题。
Volume在Kubernetes中也是一种资源,Kubernetes提供了多种类型的Volume供容器应用使用。Pod通过挂载(Mount)的方式来使用一个或多个Volume。与Pod 具有相同生命周期的Volume被称为临时卷。其他类型的Volume是“持久”的,通常比Pod的生命周期更长。
临时卷
临时卷与Pod具有相同的生命周期,包括为Pod创建的临时卷(emptyDir, Generic Ephemeral , CSI Ephemeral),以及通过Kubernetes资源对象为Pod提供数据的临时卷等
emptyDir
这种类型的Volume将在Pod被调度道Node时,由kubelet进行创建。初始状态下目录为空,被命名为空目录。它与Pod就有相同的声明周期,当Pod被销毁时,emptyDir对应的目录也会被删除。
在默认情况下,Kubelet会在Node的工作目录下位Pod创建emptyDir 目录。另外,emptyDir可以通过medium 字段设置存储介质位”Memory”,表示使用基于内存的文件系统。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| apiVersion: v1 kind: Pod metadata: name: test-pod spec: containers: - image: busybox name: test-container volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: {}
|
设置emptyDir 为内存
1 2 3
| volumes: - name: cache-volume emptyDir: {}
|
Generic Ephemeral
Generic Ephemeral相比emptyDir 提供更加灵活的存储,并且可以设置容量上线,也可以向其中包含一些初始数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| kind: Pod apiVersion: v1 metadata: name: my-app spec: containers: - name: my-frontend image: busybox volumeMounts: - mountPath: "/scratch" name: scratch-volume command: ["sleep","100000"] volumes: - name: scratch-volume ephemeral: volumeClaimTemplate: metadata: labels: type: my-frontend-volume spec: accessModes: ["ReadWriteOnce"] storageClassName: "scratch-storage-class" resources: requests: storage: 1Gi
|
CSI Ephemeral
CSI Ephemeral 必须由第三方CSI 存储驱动程序提供
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| kind: Pod apiVersion: v1 metadata: name: pod-csi-ephemeral spec: containers: - name: my-frontend image: busybox command: ["sleep","100000"] volumeMounts: - mountPath: "/data" name: my-csi-inline-vol volumes: - name: my-csi-inline-vol csi: driver: inline.storage.kubernetes.io volumeAttributes: foo: bar
|
ConfigMap
ConfigMap主要保存应用所需的配置文件,并通过Volume形式被挂载道容器内部的文件系统中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| apiVersion: v1 kind: Pod metadata: name: cm-test-app spec: contaienr: - name: cm-test-app image: kubeguide/tomcat-app:v1 ports: - containerPort: 8080 volumeMounts: - name: serverxml mountPath: /configfiles volumes: - name: serverxml items: - key: key-serverxml path: server.xml - key: key-loggingproperties path: logging.properties
|
Secret
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: password: dmFsdWUtMgOk username: dmFsdWUtMQOK ---- apiVersion: v1 kind: Pod metadata: name: mypod spec: container: - name: mycontainer image: redis volumeMounts: - name: foo mountPath: "etc/foo" volumes: - name: foo secret: secretName: mysecret
|
Downward API
Downward API 可以将Pod或Container的某些元数据信息以文件形式挂载到容器内,供容器内的应用使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| apiVersion: v1 kind: Pod metadata: name: downward-api-demo labels: app: nginx env: production spec: containers: - name: nginx image: nginx:1.20 volumeMounts: - name: pod-info mountPath: /etc/podinfo readOnly: true command: ["/bin/sh"] args: - -c - | echo "Pod信息已挂载到 /etc/podinfo 目录:" ls -la /etc/podinfo/ echo "Pod名称: $(cat /etc/podinfo/name)" echo "命名空间: $(cat /etc/podinfo/namespace)" echo "节点名称: $(cat /etc/podinfo/node)" nginx -g 'daemon off;' volumes: - name: pod-info downwardAPI: items: - path: "name" fieldRef: fieldPath: metadata.name - path: "namespace" fieldRef: fieldPath: metadata.namespace - path: "node" fieldRef: fieldPath: spec.nodeName
|
Service Accout Token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| apiVersion: v1 kind: Pod metadata: name: sa-token-test spec: containers: - name: container-net image: busybox volumeMounts: - name: token-vol mountPath: "/service-account" readOnly: ture volume: - name: token-vol projected: sources: - serviceAccountToken: audience: api expirationSeconds: 3600 path: token
|
持久卷
持久卷不直接隶属于Pod资源,而是由Pod定义PVC 资源,再由PVC资源向Kubernetes进行PV的申请与绑定。
PV和PVC
PV和PVC 的生命周期主要经过 资源供应,资源绑定,资源使用和资源回收四个阶段
资源供应
Kubernete支持两种供应模式
- 静态模式: 预先创建若干PV,在PV的定义中能够体现存储资源的特性
- 动态模式: 无须先创建PV,通过StorageClass的设置对后端存储资源进行描述,标记存储的类型和特性,用户通过创建PVC对存储类型继续宁申请。StorageClass中的驱动提供者将自动完成PV的创建和PVC的绑定。
资源绑定
在用户定义好PVC之后,系统将根据PVC对存储资源的请求,在已存在的PV中选择一个满足要求的PV,一旦找到,就将该PV与用户定义的PVC绑定。如果在系统中没有满足的PV,则PVC会一致处于Pending状态。
资源使用
当Pod需要使用存储资源时,需要在Volume的定义中引用PVC类型的Volume,将PVC挂载到容器内的某个路径下进行使用。
资源回收
用户使用完资源后,可以删除PVC。与该PVC绑定的PV将被标记为已释放,但它还不能立刻与其他的PVC绑定,Pod在该PVC中生成的数据可能还被留着PV对应的存储设备上,只有在清除这些数据后,才能再次使用该PV。
回收策略
- Retain
Retain表示在删除PVC之后,与之绑定的PV不会被删除,仅被标记为已释放。PV中的数据仍然存在,在清空数据前不能被新的PVC使用
- Delete
Delete表示自动删除PV资源对象和相关后端存储资产,同时会删除与该PV相关的后端存储资产
- Recycle
回收,删除卷中的所有文件,可以直接被新的PVC使用
PVC与指定PV绑定
- 在PV中,通过claimRef来完成与PVC的绑定
- 在PVC中,通过volumeName 指定需要绑定的PV名称
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| apiVersion: v1 kind: PersistentVolume metatada: name: foo-pv spec: storageClassName: "" claimRef: name: foo-pvc namespace: foo
apiVersion kind: PersistentVolumeClaim metadata: name: foo-vol namespace: foo spec: storageClassName: "" volumeName: foo-pv
|
PVC资源扩容
通过设置 关键字段 allowVolumeExpansion: ture
1 2 3 4 5 6 7 8 9 10 11
| apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gluster-vol-default provisioner: kubernetes.io/glusterfs paramters: resturl: "<http://192.168.10.100:8080>" restuser: "" secretNamespace: "" secretName: "" allowVolumeExpansion: true
|
修改时,直接修改绑定的PVC中的 资源限制
1 2 3
| resources: requests: storage: 16Gi
|
PV配置项
不同的PV 是以不同的插件进行设计和实现的。其中内置的插件类型包括
CSI: 容器存储接口
FC:光纤存储设备
hostPath:宿主机目录
iSCSI:iSCSI存储设备
NFS:基于NFS协议的网络文件系统
PV资源对象的关键配置如下:
- 存储容量
用于描述存储的容量,目前仅支持对存储空间的设置
- 存储卷模式
支持配置为块设备或者文件系统,如果块设备为空则自动创建一个文件系统,支持块设备的Volume会以裸块设备的形式被挂载到容器内,并且不会创建任何文件系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| apiVersion: v1 kind: PersistentVolume metadata: name: block-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain volumeMode: Block fc: targetWWNs: ["50060e801049cfd1"] lun: 0 readOnly: false
|
- 访问模式
ReadWriteOnce (RWO): 读写权限,只能被单个Node挂载
ReadOnlyMany (ROX): 只读权限,允许被多个Node挂载
ReadWriteMany (RWX): 读写权限,允许被多个Node挂载
ReadWriteOncePod (RWOP): 可以被耽搁Pod以读写方式挂载
- 存储类别
通过storageClassName参数指定一个StorageClass资源对象的名称
- 回收策略
Retain : 保留数据
Delte : 与PV相连的后端存储完成Volume的删除操作
Recycle : 简单清楚文件操作
- 节点亲和性
通过设置nodeAffinity 来使得只有某些Node可以访问Volume
1 2 3 4 5 6 7 8
| nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - my-node
|
- 生命周期
Available : 可用状态,未与PVC进行绑定
Bound : 已与某个PVC绑定
Released : 与之绑定的PVC已被删除,但未完成资源回收,不能被其他PVC使用
Failed : 自动资源回收失败
PVC
pvc作为用户对存储资源的需求申请,主要涉及存储请求,访问模式,PV选择条件和存储类别等信息的设置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| apiVersion: v1 kind: PersistentVolumeClaim metadata: name: myclaim spec: accessModes: - ReadWriteOnce volumeMode: Filesystem resources: requests: storage: 8Gi storageClassName: slow selector: matchLabels: release: "stable" matchExpressions: - {key: environment, operator: In, values: [dev]}
|
- resource 资源请求,描述对存储资源的请求
- accessModes 可用在PVC上设置请求PV的访问模式
- volumeMode 存储卷模式
- selector 筛选合适的PV进行绑定
- Class 设定需要的后端存储的类别,以减少对后端存储特性的详细信息的依赖。
Pod中挂载PVC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| apiVersion: v1 kind: Pod metadata: name: myPod spec: containers: - name: myfrontend image: nginx volumeMounts: - mountPath: "/var/www/html" name: mypd volumes: - name: mypd persistentVolumeClaim: clientName: myclaim
|
StorageClass
StorageClass 作为对存储资源的抽象定义,可对用户设置的PVC申请屏蔽后端存储的细节。
示例
1 2 3 4 5 6 7 8 9 10 11 12
| apiVersion: v1 kind: StorageClass metadata: name: standard provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Retain allowVolumeExpansion: true mountOptions: - debug volumeBindingMode: Immediate
|
描述资源的提供者,用于提供具体的PV资源,可用将其看作后端存储驱动
通过动态资源供应模式创建的PV将继承在StorageClass 上设置的回收策略,配置字段名称为“reclaimPolicy”
是否允许卷扩容
挂载选项
存储绑定模式用于控制何时将PVC与动态创建的PV绑定。
存储参数
1 2 3 4 5 6 7 8 9 10
| kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: slow provisioner: kubernetes.io/aws-ebs parameters: type: iol iopsPerGB: "10" fsType: ext4
|
1 2 3 4 5 6 7 8 9
| apiVersion: storage.k8s.io/v1 kind: StroageClass metadata: name: example-fs provisioner: example.com/external-nfs paramters: server: nfs-server.example.com path: /share readOnly: "false"
|
1 2 3 4 5 6 7 8 9
| apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: azurefile provisioner: kubernetes.io/azure-file paramters: skuName: Standard_LRS location: eastus storageAccount: azure_storage_account_name
|
1 2 3 4 5 6
| apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer
|
设置默认StorageClass
- 开启默认Storage功能
1
| --enable-admission-plugins=...,DefaultStorageClass
|
- 在StorageClass中定义 一个注解
1 2 3 4 5 6 7 8 9
| kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: gold annotations: storageclass.beta.kubernetes.io/is-default-class="true" provisioner: kubernetes.io/gce-pd parameters: type: pd-ssd
|
内置Volume类型
NFS
将网络文件系统中的目录或文件挂载到容器内部使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| apiVersion: v1 kind: Pod metadata: name: pod-use-nfs spec: contaienrs: - image: busybox name: busybox volumeMounts: - mountPath: /data name: nfs-volume volumes: - name: nfs-volume nfs: server: 10.1.1.1 path: /nfs_data readOnly: true
|