Kubenets 存储的分类+数据的持久化+PVC/PV+StorageClass
1. ConfigMap
以注入的方式存储非机密的配置信息(例如配置文件、环境变量、命令行参数等)。Pod 可以通过环境变量或挂载为文件的方式读取 ConfigMap。
# 文件方式创建
$ kubectl create configmap xxx --from-file=xxx.file
# 命令参数方式创建
$ kubectl create configmap xxx --from-literal=name=xxx --from-literal=password=xx
# --dry-run只编写不运行, -o yaml > xxx.yaml 导出到xx.yaml保存为yaml格式
--dry-run=client
-o yaml > xxx.yaml
# 完整命令
$ kubectl create configmap xxx --from-literal=name=xxx --from-literal=password=xxx --dry-run=client -o yaml > xxx.yaml
使用方式:
- 作为环境变量注入 Pod
apiVersion: v1
kind: ConfigMap
metadata:
name: app-env-bulk
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: envfrom-demo
spec:
replicas: 1
selector:
matchLabels:
app: envfrom-demo
template:
metadata:
labels:
app: envfrom-demo
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "env | grep DB_"]
envFrom:
- configMapRef:
name: app-env-bulk
2.作为环境变量单个键值注入
apiVersion: v1
kind: ConfigMap
metadata:
name: app-env
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: env-demo
spec:
replicas: 1
selector:
matchLabels:
app: env-demo
template:
metadata:
labels:
app: env-demo
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "env | grep LOG_LEVEL"]
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-env
key: LOG_LEVEL
- name: FEATURE_FLAG
valueFrom:
configMapKeyRef:
name: app-env
key: FEATURE_FLAG
-
以卷 (configMap volume) 的方式挂载为文件/目录
apiVersion: v1 kind: ConfigMap metadata: name: app-config-files --- apiVersion: apps/v1 kind: Deployment metadata: name: volume-demo spec: replicas: 1 selector: matchLabels: app: volume-demo template: metadata: labels: app: volume-demo spec: containers: - name: app image: busybox command: ["sh", "-c", "ls /config && cat /config/application.properties"] volumeMounts: - name: config-vol mountPath: /config readOnly: true volumes: - name: config-vol configMap: name: app-config-files
2. Secret
存储敏感数据(如密码、证书、密钥),内容会以 Base64 编码保存。与 ConfigMap 类似,可通过环境变量或卷挂载到 Pod,并在 API Server/ETCD 中进行额外的访问控制。
# base64编码
$ echo -n "Hello World" | base64
SGVsbG8gV29ybGQ=
# base64解码
$ echo -n "SGVsbG8gV29ybGQ=" | base64 -d
常见类型如下:
-
Opaque:默认类型,存放任意 key/value,需要自行决定编码内容。
apiVersion: v1 kind: Secret metadata: name: app-secret type: Opaque stringData: username: admin password: s3cr3t or apiVersion: v1 kind: Secret metadata: name: app-secret type: Opaque data: username: base64(admin) password: base64(s3cr3t) -
kubernetes.io/service-account-token:ServiceAccount 自动挂载的令牌,附带 CA、namespace 等字段。
apiVersion: v1 kind: Secret metadata: name: default-token annotations: kubernetes.io/service-account.name: default type: kubernetes.io/service-account-token -
kubernetes.io/dockercfg 与 kubernetes.io/dockerconfigjson:Docker Registry 凭据,分别对应旧版 .dockercfg 和新版 .dockerconfigjson。
apiVersion: v1 kind: Secret metadata: name: regcred type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: <base64-encoded-config> -
kubernetes.io/basic-auth:基于用户认证,保存用户名/密码对。
apiVersion: v1 kind: Secret metadata: name: basic-auth type: kubernetes.io/basic-auth stringData: username: user1 password: passw0rd -
kubernetes.io/ssh-auth:存放 SSH 私钥数据。
apiVersion: v1 kind: Secret metadata: name: git-ssh type: kubernetes.io/ssh-auth stringData: ssh-privatekey: | -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY----- -
kubernetes.io/tls:TLS 证书与私钥(字段固定为 tls.crt、tls.key)。
apiVersion: v1 kind: Secret metadata: name: tls-cert type: kubernetes.io/tls stringData: tls.crt: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- tls.key: | -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- -
bootstrap.kubernetes.io/token:集群 bootstrap 令牌,用于 kubeadm 加入节点。
apiVersion: v1 kind: Secret metadata: name: bootstrap-token-abcdef namespace: kube-system type: bootstrap.kubernetes.io/token stringData: description: "kubeadm bootstrap token" token-id: abcdef token-secret: 0123456789abcdef
3. Downward API
把 Pods 自身的元数据(例如 Pod 名称、命名空间、标签、注解、资源请求与限制等)暴露给容器,方式包括环境变量和挂载为文件。Downward API 不需要事先创建对象,由 kubelet 在 Pod 生命周期内自动提供。
-
环境变量注入 Pod 元数据(fieldRef)
apiVersion: v1 kind: Pod metadata: name: env-fieldref-demo spec: containers: - name: app image: busybox command: ["sh", "-c", "env && sleep 3600"] env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP -
环境变量注入资源请求/限制(resourceFieldRef)
apiVersion: v1 kind: Pod metadata: name: env-resource-demo spec: containers: - name: app image: busybox resources: requests: cpu: "250m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi" env: - name: CPU_LIMIT valueFrom: resourceFieldRef: containerName: app resource: limits.cpu - name: MEM_REQUEST valueFrom: resourceFieldRef: containerName: app resource: requests.memory command: ["sh", "-c", "echo $CPU_LIMIT $MEM_REQUEST && sleep 3600"] -
DownwardAPI 卷(以文件形式暴露元数据或资源值,可热更新)
apiVersion: v1 kind: Pod metadata: name: volume-downward-demo labels: app: demo spec: containers: - name: app image: busybox command: ["sh", "-c", "cat /etc/podinfo/* && sleep 3600"] volumeMounts: - name: podinfo mountPath: /etc/podinfo readOnly: true volumes: - name: podinfo downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels - path: "annotations" fieldRef: fieldPath: metadata.annotations - path: "requests_cpu" resourceFieldRef: containerName: app resource: requests.cpu - path: "limits_memory" resourceFieldRef: containerName: app resource: limits.memory -
投射卷(Projected Volume)结合 DownwardAPI 与其他来源
apiVersion: v1 kind: Pod metadata: name: projected-downward-demo spec: containers: - name: app image: busybox command: ["sh", "-c", "ls /projected && sleep 3600"] volumeMounts: - name: projected-vol mountPath: /projected readOnly: true volumes: - name: projected-vol projected: sources: - downwardAPI: items: - path: pod_name fieldRef: fieldPath: metadata.name - path: cpu_limit resourceFieldRef: containerName: app resource: limits.cpu - configMap: name: app-config - secret: name: app-secret
4. Volume
解决 Pod 容器「文件系统不持久、彼此隔离」的问题,让数据可以:在同一个 Pod 内共享、在容器重启后保留,甚至在不同 Pod / 节点之间持久存储。
-
Pod 使用 emptyDir 卷(生命周期随 Pod)
apiVersion: v1 kind: Pod metadata: name: emptydir-pod spec: containers: - name: app image: nginx:1.27 volumeMounts: - name: cache mountPath: /cache volumes: - name: cache emptyDir: {} -
Pod 使用 hostPath 卷(挂宿主机目录)
Kubernetes 中 hostPath 的 type 主要有以下几种(不区分大小写时写法类似,但推荐用官方写法):
-
DirectoryOrCreate
如果路径存在:必须是目录,否则报错。
如果路径不存在:在宿主机上创建一个空目录(权限 0755,属主为 kubelet 运行用户)。
-
Directory
路径必须已经存在并且是一个目录。
如果不存在或不是目录:Pod 启动失败。
-
FileOrCreate
如果路径存在:必须是文件,否则报错。
如果路径不存在:在宿主机上创建一个空文件(权限 0644,属主为 kubelet 运行用户)。
-
File
路径必须已经存在并且是一个普通文件。
如果不存在或不是文件:Pod 启动失败。
-
Socket
路径必须存在且是 Unix Domain Socket(如一些本地通信场景)。
否则 Pod 启动失败。
-
CharDevice
路径必须存在且是字符设备(如 /dev/null、串口设备等)。
否则 Pod 启动失败。
-
BlockDevice
路径必须存在且是块设备(如磁盘 /dev/sdb 等)。
否则 Pod 启动失败。
-
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: host-data
mountPath: /data # 挂载容器内部的路径
volumes:
- name: host-data
hostPath:
path: /var/data # 宿主机路径
type: DirectoryOrCreate
-
使用 PV + PVC 持久卷
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath: # 演示用,生产一般用云盘/NFS/CSI
path: /mnt/data/pv-example
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pvc-pod
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-example
5. PV/PVC+StatefulSet有状态服务
Kubernetes 的 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 负责为 Pod 提供持久化存储:
PV:管理员预先配置的存储资源,抽象了底层存储实现(如 NFS、iSCSI、CSI 驱动等),带有容量、访问模式、回收策略等属性。
PVC:应用侧对存储的请求,指定所需容量、访问模式、StorageClass 等;控制面会尝试把 PVC 绑定到满足条件的 PV,或通过 StorageClass 动态创建新的 PV。
Pod 使用 PVC:在 Pod 的 spec.volumes 中引用 PVC,容器通过 volumeMounts 挂载后即可读写。
生命周期:删除 PVC 时,PV 根据回收策略(Retain、Delete、Recycle)决定是否保留或清除实际存储;未被绑定的 PV 处于 Available 状态,可供其它 PVC 使用。
常见注意事项:确保访问模式匹配(例如 ReadWriteOnce vs ReadOnlyMany)、容量需要满足或高于 PVC 请求、StorageClass 的 allowVolumeExpansion 决定是否可扩容等。
要让 Kubernetes 的 PVC/PV 能够正常使用,需要在集群里部署与 PVC 兼容的存储插件(通常称为 CSI 驱动或传统的外部存储插件)。思路如下:
确认需求:确定应用需要的访问模式(RWO/RWX/ROX)、性能和容量要求,然后挑选合适的后端存储(NFS、iSCSI、Ceph RBD/CephFS、各云厂商块存储、分布式文件系统等)。
-
安装对应存储插件:
现代集群最常用的是 CSI(Container Storage Interface)驱动。通常可通过 Helm Chart、Operator 或云厂商提供的安装脚本部署。
-
例如:
NFS:可以部署 nfs-subdir-external-provisioner(Provisioner + NFS 服务已准备好)。
iSCSI:需要在节点上配置 iSCSI initiator,并部署提供 iSCSI Target 的 CSI(如 OpenEBS iSCSI)。
Ceph:常见方案是 Rook-Ceph Operator 或 ceph-csi(支持 RBD、CephFS)。
云厂商块存储:AWS EBS CSI、Azure Disk CSI、GKE PD CSI 等。
PV 访问模式(Access Modes)
PV 的访问模式定义了存储卷如何被挂载和访问:
1. ReadWriteOnce (RWO)
说明:卷可以被单个节点以读写方式挂载
特点:同一时间只能被一个节点挂载
适用场景:数据库、单实例应用
限制:不支持多节点同时读写
2. ReadOnlyMany (ROX)
说明:卷可以被多个节点以只读方式挂载
特点:多个节点可同时读取,但不能写入
适用场景:配置文件、静态资源分发
限制:所有挂载都是只读的
3. ReadWriteMany (RWX)
说明:卷可以被多个节点以读写方式挂载
特点:支持多节点同时读写
适用场景:共享存储、多实例应用
限制:需要底层存储系统支持(如 NFS、GlusterFS)
4. ReadWriteOncePod (RWOP) ⭐
说明:卷可以被单个 Pod 以读写方式挂载(Kubernetes v1.22+)
特点:确保整个集群中只有一个 Pod 可以读写挂载
适用场景:需要严格单写入者的应用
优势:比 RWO 更严格,提供更好的数据一致性保证
注: 需在每个node节点安装NFS服务器.
# 更新软件软
$ apt update && apt upgrade -y
# 安装NFS服务器
$ apt install -y nfs-kernel-server
$ mkdir /nfs-share
$ chmod 666 /nfs-share
$ chown nobody /nfs-share
$ cat /etc/exports
/nfs-share *(rw,sync,no_subtree_check,no_root_squash)
# Kubernetes NFS 共享配置
# 格式:共享目录 允许访问的网段(权限选项)
# 方式1:允许所有节点访问(开发环境)
/nfs-share/k8s-pv *(rw,sync,no_subtree_check,no_root_squash)
# 方式2:限制特定网段(生产环境推荐)
# /nfs-share/k8s-pv 10.0.0.0/8(rw,sync,no_subtree_check,no_root_squash)
# /nfs-share/k8s-pv 192.168.0.0/16(rw,sync,no_subtree_check,no_root_squash)
# 重启服务
$ systemctl restart nfs-server.service
# 检查
$ dpkg -l | grep nfs
$ showmount -e xxx (主机ip: Ex:192.168.61.141)
--------------------------------
node01 || node01
$ mkdir nfs-share && mkdir nfs-share/k8s-pv
# 挂载
$ mount -t nfs 192.168.61.141:/nfs-share/k8s-pv /nfs-share/k8s-pv/
# 解除挂载
$ umount /nfs-share/k8s-pv/
对于 StatefulSet,通常不直接创建 PVC,而是使用 volumeClaimTemplates,真正应用时在 StatefulSet 中定义模板即可。
PV清单文件
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo-retain
spec:
capacity:
storage: 1Gi
accessModes: [ReadWriteMany]
storageClassName: manual # 存储类名
persistentVolumeReclaimPolicy: Retain
nfs:
path: /nfs-share/k8s-pv
server: 192.168.61.141
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo-recycle
spec:
capacity:
storage: 1Gi
accessModes: [ReadWriteMany]
storageClassName: manual # 存储类名
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /nfs-share/data
server: 192.168.61.141
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo-delete
spec:
capacity:
storage: 1Gi
accessModes: [ReadWriteMany]
storageClassName: manual # 存储类名
persistentVolumeReclaimPolicy: Delete
nfs:
path: /nfs-share/tmp
server: 192.168.61.141
svc-headless清单文件
apiVersion: v1
kind: Service
metadata:
name: web-headless
labels:
app: web
spec:
clusterIP: None # statefulSet 无头服务
selector:
app: web
ports:
- port: 80
targetPort: http
statefulSet清单文件
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web-stateful
spec:
serviceName: web-headless
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 80
name: http
volumeMounts:
- name: www # 绑定的卷名称
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www # 绑定的卷名称
spec:
accessModes: [ReadWriteMany]
storageClassName: manual # 存储类名
resources:
requests:
storage: 1Gi
总结:
无状态服务:使用 ConfigMap/Secret 提供配置,数据写入外部存储(数据库、对象存储、消息队列等)。
有状态服务:使用 StatefulSet + PV/PVC,或使用 Operator 管理。
PVC 需手动删除
6. StorageClass
StorageClass 基于云供应商提供的服务, 是 Kubernetes 中用于定义存储类型的资源对象.
主要作用
动态存储供应:自动创建 PersistentVolume(PV)
存储分类:区分不同性能和特性的存储
简化管理:无需手动创建 PV
创建StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard # 指定 StorageClass
provisioner: kubernetes.io/aws-ebs # 存储供应者
parameters:
type: gp3
fsType: ext4
reclaimPolicy: Delete # 回收策略:Retain 或 Delete
volumeBindingMode: Immediate # 绑定模式:Immediate 或 WaitForFirstConsumer
allowVolumeExpansion: true # 是否允许卷扩容
- 在 PVC 中引用 StorageClass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard # 指定 StorageClass
resources:
requests:
storage: 10Gi