Kubernetes 存储

本文最后更新于 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。

回收策略

  1. Retain

Retain表示在删除PVC之后,与之绑定的PV不会被删除,仅被标记为已释放。PV中的数据仍然存在,在清空数据前不能被新的PVC使用

  1. Delete

Delete表示自动删除PV资源对象和相关后端存储资产,同时会删除与该PV相关的后端存储资产

  1. 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
# pv
apiVersion: v1
kind: PersistentVolume
metatada:
name: foo-pv
spec:
storageClassName: ""
claimRef:
name: foo-pvc
namespace: foo

# pvc
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资源对象的关键配置如下:

  1. 存储容量

用于描述存储的容量,目前仅支持对存储空间的设置

  1. 存储卷模式

支持配置为块设备或者文件系统,如果块设备为空则自动创建一个文件系统,支持块设备的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
  1. 访问模式

ReadWriteOnce (RWO): 读写权限,只能被单个Node挂载

ReadOnlyMany (ROX): 只读权限,允许被多个Node挂载

ReadWriteMany (RWX): 读写权限,允许被多个Node挂载

ReadWriteOncePod (RWOP): 可以被耽搁Pod以读写方式挂载

  1. 存储类别

通过storageClassName参数指定一个StorageClass资源对象的名称

  1. 回收策略

Retain : 保留数据

Delte : 与PV相连的后端存储完成Volume的删除操作

Recycle : 简单清楚文件操作

  1. 节点亲和性

通过设置nodeAffinity 来使得只有某些Node可以访问Volume

1
2
3
4
5
6
7
8
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- my-node
  1. 生命周期

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
  • Provisioner

描述资源的提供者,用于提供具体的PV资源,可用将其看作后端存储驱动

  • Reclaim Policy

通过动态资源供应模式创建的PV将继承在StorageClass 上设置的回收策略,配置字段名称为“reclaimPolicy”

  • allVolumeExpansion

是否允许卷扩容

  • MountOptions

挂载选项

  • Volume Binding mode

存储绑定模式用于控制何时将PVC与动态创建的PV绑定。

  • Parameters

存储参数

  • AWS EBS Volume
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

  • NFS Volume
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"
  • AzureFile Volume
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
  • Local Volume
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

  1. 开启默认Storage功能
1
--enable-admission-plugins=...,DefaultStorageClass
  1. 在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

Kubernetes 存储
http://gadoid.io/2025/08/14/Kubernetes-存储/
作者
Codfish
发布于
2025年8月14日
许可协议