一、K8s 存储核心组件分类

按用途和特性,K8s 存储相关组件可分为以下几类:

组件类型作用说明适用场景
ConfigMap存储非敏感配置数据(如配置文件、环境变量),以键值对形式存在应用配置文件(如 Nginx 配置、数据库连接地址)
Secret存储敏感数据(如密码、Token、证书),数据会被 Base64 编码(非加密)数据库密码、API 密钥、SSL 证书
Downward API将 Pod 自身的元数据(如名称、IP、标签)注入到容器内部容器需要知道自身在 K8s 中的信息(如 Pod 名称)
Volume为 Pod 提供临时或持久化存储空间,生命周期与 Pod 一致Pod 内多容器共享数据、临时文件存储
PV/PVCPV(PersistentVolume)是集群级别的持久化存储,PVC(PersistentVolumeClaim)是 Pod 对 PV 的 “申请”长期持久化数据(如数据库数据、用户上传文件)

二、详细讲解与实操练习

以下按组件类型逐一讲解,每个组件都包含:作用详解 → YAML 配置(带注释)→ 创建 → 验证 → 清理 步骤,确保环境干净。

1. ConfigMap(配置映射)

核心作用:存储非敏感的配置信息,让配置与容器镜像解耦(无需修改镜像就能更新配置)。数据形式:键值对(key: value)或配置文件内容。

(1)创建 ConfigMap(两种方式)
方式 1:通过 YAML 定义键值对(适合简单配置)

configmap-demo.yaml:

apiVersion: v1  # ConfigMap 属于核心组,API 版本 v1
kind: ConfigMap  # 资源类型:ConfigMap
metadata:
  name: app-config  # ConfigMap 名称(需唯一)
data:  # 配置数据(键值对形式)
  app.env: "production"  # 键:app.env,值:production(环境标识)
  log.level: "info"      # 键:log.level,值:info(日志级别)
  nginx.conf: |          # 键:nginx.conf,值:多行文本(Nginx 配置文件内容)
    server {
      listen 80;
      server_name localhost;
      location / {
        root /usr/share/nginx/html;
        index index.html;
      }
    }

配置说明:

  • data 字段是核心,支持单值(如 app.env)和多行文本(如 nginx.conf,用 | 标识)。
  • 多行文本适合存储完整的配置文件(如 Nginx、Redis 配置)。
方式 2:通过文件创建(适合已有配置文件)

如果有现成的配置文件(如 app.properties),可直接创建:

# 先创建一个配置文件
echo "max_connections=100" > app.properties
# 通过文件创建 ConfigMap(--from-file=文件名)
kubectl create configmap app-config-file --from-file=app.properties

(后续练习以方式 1 为例,方式 2 可自行测试)

(2)创建 ConfigMap
kubectl apply -f configmap-demo.yaml
(3)查看 ConfigMap 信息
kubectl get configmap app-config  # 查看基本信息
kubectl describe configmap app-config  # 查看详细数据
# 预期输出中会显示 data 下的所有键值对
(4)在 Pod 中使用 ConfigMap(3 种方式)

ConfigMap 中的数据可通过 环境变量、命令行参数、文件挂载 三种方式注入到 Pod 中。

方式 A:作为环境变量注入

pod-using-configmap-env.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-env-config
spec:
  containers:
  - name: nginx
    image: nginx:1.25
    env:  # 环境变量配置
    - name: ENV  # 容器内的环境变量名
      valueFrom:
        configMapKeyRef:
          name: app-config  # 引用的 ConfigMap 名称
          key: app.env     # 引用 ConfigMap 中的键
    - name: LOG_LEVEL  # 另一个环境变量
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: log.level

创建并验证:

kubectl apply -f pod-using-configmap-env.yaml
# 进入 Pod 查看环境变量
kubectl exec -it pod-env-config -- env | grep -E "ENV|LOG_LEVEL"
# 预期输出:
# ENV=production
# LOG_LEVEL=info
方式 B:作为命令行参数注入(基于环境变量)

pod-using-configmap-cmd.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-cmd-config
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    env:  # 先定义环境变量
    - name: ENV
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: app.env
    command: ["/bin/sh", "-c", "echo '当前环境:$ENV'"]  # 命令行中引用环境变量

创建并验证:

kubectl apply -f pod-using-configmap-cmd.yaml
# 查看 Pod 日志(命令输出)
kubectl logs pod-cmd-config
# 预期输出:当前环境:production
方式 C:作为文件挂载到容器

pod-using-configmap-file.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-file-config
spec:
  containers:
  - name: nginx
    image: nginx:1.25
    volumeMounts:  # 挂载存储卷到容器内的目录
    - name: config-volume  # 存储卷名称(与下面 volumes.name 对应)
      mountPath: /etc/config  # 容器内的挂载路径(会自动创建)
  volumes:  # 定义存储卷,关联 ConfigMap
  - name: config-volume
    configMap:
      name: app-config  # 关联的 ConfigMap 名称

配置说明:

  • ConfigMap 中的每个键会被挂载为 /etc/config 目录下的一个文件,文件内容为对应的值。
  • 例如:app.env 键会生成 /etc/config/app.env 文件,内容为 production。

创建并验证:

kubectl apply -f pod-using-configmap-file.yaml
# 进入 Pod 查看挂载的文件
kubectl exec -it pod-file-config -- ls /etc/config  # 列出文件
kubectl exec -it pod-file-config -- cat /etc/config/nginx.conf  # 查看 nginx 配置
# 预期输出:ConfigMap 中定义的 nginx.conf 内容
(5)清理资源
# 删除 Pod
kubectl delete pod pod-env-config pod-cmd-config pod-file-config
# 删除 ConfigMap
kubectl delete configmap app-config
# 验证:kubectl get configmap,po 确认无相关资源
2. Secret(密钥)

核心作用:存储敏感数据(如密码、Token),与 ConfigMap 类似,但数据会被 Base64 编码(注意:Base64 是编码而非加密,生产环境需配合加密插件使用)。数据形式:键值对,值需为 Base64 编码(或通过 YAML 自动编码)。

(1)创建 Secret(两种方式)
方式 1:通过 YAML 定义(自动编码)

secret-demo.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: app-secret  # Secret 名称
type: Opaque  # 类型:默认 Opaque(通用密钥),其他类型如 kubernetes.io/tls(证书)
data:  # 敏感数据(值会被自动 Base64 编码)
  db.password: "cGFzc3dvcmQxMjM="  # 原始值:password123(已手动 Base64 编码)
  api.token: "dG9rZW4xMjM="        # 原始值:token123(已手动 Base64 编码)
stringData:  # 可选:直接写原始值(K8s 会自动转为 Base64 编码,推荐用这个)
  db.username: "admin"  # 原始值:admin(无需手动编码)

配置说明:

  • data:值必须是 Base64 编码后的字符串(可通过 echo -n "password123" | base64 生成)。
  • stringData:直接写原始值,K8s 会自动编码,更方便(推荐使用)。
  • type: Opaque:表示通用密钥,其他类型如 kubernetes.io/tls 用于存储 TLS 证书。
方式 2:通过命令行创建(自动编码)
kubectl create secret generic app-secret-cli \
  --from-literal=db.password=password123 \
  --from-literal=db.username=admin
# --from-literal:直接指定键值对(自动编码)

(后续练习以方式 1 为例)

(2)创建 Secret
kubectl apply -f secret-demo.yaml
(3)查看 Secret 信息
kubectl get secret app-secret  # 查看基本信息
kubectl describe secret app-secret  # 查看键(值会隐藏,显示为 <non-sensitive>)
# 查看原始数据(解码 Base64):
kubectl get secret app-secret -o jsonpath='{.data.db\.username}' | base64 -d
# 预期输出:admin(解码后的值)
(4)在 Pod 中使用 Secret(与 ConfigMap 类似)

Secret 也可通过 环境变量 或 文件挂载 注入到 Pod 中(敏感数据推荐用文件挂载,避免环境变量泄露)。

方式 A:作为环境变量注入

pod-using-secret-env.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-env-secret
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    env:
    - name: DB_USER  # 环境变量名
      valueFrom:
        secretKeyRef:
          name: app-secret  # 引用的 Secret 名称
          key: db.username  # 引用的键
    - name: DB_PASS
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: db.password
    command: ["/bin/sh", "-c", "echo '用户名:$DB_USER,密码:$DB_PASS'; sleep 3600"]

创建并验证:

kubectl apply -f pod-using-secret-env.yaml
kubectl logs pod-env-secret
# 预期输出:用户名:admin,密码:password123
方式 B:作为文件挂载(推荐)

pod-using-secret-file.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-file-secret
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret  # 挂载路径(权限默认是 0400,更安全)
      readOnly: true  # 只读挂载(敏感数据不允许修改)
  volumes:
  - name: secret-volume
    secret:
      secretName: app-secret  # 关联的 Secret 名称

创建并验证:

kubectl apply -f pod-using-secret-file.yaml
# 进入 Pod 查看挂载的文件
kubectl exec -it pod-file-secret -- ls /etc/secret
kubectl exec -it pod-file-secret -- cat /etc/secret/db.username
# 预期输出:admin
(5)清理资源
kubectl delete pod pod-env-secret pod-file-secret
kubectl delete secret app-secret
# 验证:确认资源已删除
3. Downward API(向下 API)

核心作用:将 Pod 自身的元数据(如名称、IP、标签、注解)注入到容器内部,让容器知道自己在 K8s 中的 “身份信息”。注入方式:环境变量 或 文件挂载。

(1)通过环境变量注入 Pod 元数据

pod-downward-api-env.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-downward-env
  labels:  # Pod 的标签(后续会被注入)
    app: demo
    env: test
  annotations:  # Pod 的注解(后续会被注入)
    author: "k8s learner"
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    env:
    # 注入 Pod 名称
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name  # 元数据路径:Pod 名称
    # 注入 Pod IP
    - name: POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP  # 状态路径:Pod IP
    # 注入 Pod 标签(需用 configMapKeyRef 嵌套)
    - name: POD_LABELS
      valueFrom:
        configMapKeyRef:
          name: pod-info  # 临时 ConfigMap 名称(由 downwardAPI 生成)
          key: labels
    command: ["/bin/sh", "-c", "echo 'Pod 名称:$POD_NAME,IP:$POD_IP,标签:$POD_LABELS'; sleep 3600"]
  # 定义 downwardAPI 存储卷(用于注入标签、注解等复杂元数据)
  volumes:
  - name: pod-info
    downwardAPI:
      items:
      - path: "labels"  # 生成的文件名
        fieldRef:
          fieldPath: metadata.labels  # 注入 Pod 标签

配置说明:

  • 简单元数据(如名称、IP)可直接通过 fieldRef 注入环境变量。
  • 复杂元数据(如标签、注解)需先通过 downwardAPI 存储卷生成文件,再通过环境变量引用。
(2)创建并验证
kubectl apply -f pod-downward-api-env.yaml
kubectl logs pod-downward-env
# 预期输出(IP 可能不同):
# Pod 名称:pod-downward-env,IP:10.244.1.20,标签:app=demo,env=test
(3)通过文件挂载注入 Pod 元数据

pod-downward-api-file.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-downward-file
  labels:
    app: demo
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    volumeMounts:
    - name: pod-info-volume
      mountPath: /etc/podinfo  # 挂载路径,元数据会生成文件
    command: ["/bin/sh", "-c", "sleep 3600"]
  volumes:
  - name: pod-info-volume
    downwardAPI:
      items:
      - path: "pod_name"  # 文件名:pod_name
        fieldRef:
          fieldPath: metadata.name  # 文件内容:Pod 名称
      - path: "namespace"  # 文件名:namespace
        fieldRef:
          fieldPath: metadata.namespace  # 文件内容:Pod 所在命名空间
      - path: "annotations"  # 文件名:annotations
        fieldRef:
          fieldPath: metadata.annotations  # 文件内容:Pod 注解

创建并验证:

kubectl apply -f pod-downward-api-file.yaml
# 进入 Pod 查看挂载的文件
kubectl exec -it pod-downward-file -- ls /etc/podinfo
kubectl exec -it pod-downward-file -- cat /etc/podinfo/pod_name
# 预期输出:pod-downward-file
(4)清理资源
kubectl delete pod pod-downward-env pod-downward-file
# 验证:确认 Pod 已删除
4. Volume(存储卷)

核心作用:为 Pod 提供存储空间,解决容器内文件临时存储的问题(容器重启后数据丢失)。特点:Volume 的生命周期与 Pod 一致(Pod 删除,Volume 也删除),支持多种类型(如 emptyDir、hostPath、nfs 等)。

(1)emptyDir(临时存储卷)

作用:在 Pod 启动时创建,所有容器可共享,Pod 删除时数据丢失(适合临时缓存、多容器共享数据)。

pod-volume-emptydir.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-emptydir
spec:
  containers:
  - name: container1
    image: busybox:1.36
    volumeMounts:
    - name: shared-volume  # 挂载存储卷
      mountPath: /data1    # 容器 1 的挂载路径
    command: ["/bin/sh", "-c", "echo 'hello from container1' > /data1/message; sleep 3600"]
  - name: container2
    image: busybox:1.36
    volumeMounts:
    - name: shared-volume  # 同一个存储卷
      mountPath: /data2    # 容器 2 的挂载路径
    command: ["/bin/sh", "-c", "cat /data2/message; sleep 3600"]  # 读取容器 1 写入的文件
  volumes:  # 定义 emptyDir 存储卷
  - name: shared-volume
    emptyDir: {}  # 空配置,表示使用默认临时存储

创建并验证:

kubectl apply -f pod-volume-emptydir.yaml
# 查看 container2 的日志(应能读到 container1 写入的内容)
kubectl logs pod-emptydir -c container2  # -c 指定容器
# 预期输出:hello from container1
(2)hostPath(节点路径卷)

作用:将节点(Node)上的文件或目录挂载到 Pod 中,数据会保存在节点上(Pod 重启后数据不丢失,但节点故障会丢失)。

pod-volume-hostpath.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-hostpath
spec:
  containers:
  - name: nginx
    image: nginx:1.25
    volumeMounts:
    - name: node-log  # 挂载存储卷
      mountPath: /host/log  # 容器内的挂载路径
  volumes:
  - name: node-log
    hostPath:
      path: /var/log  # 节点上的实际路径(挂载节点的日志目录)
      type: Directory  # 类型:目录(确保节点上存在该目录)

创建并验证:

kubectl apply -f pod-volume-hostpath.yaml
# 进入 Pod 查看节点的日志文件(实际是挂载的节点 /var/log 目录)
kubectl exec -it pod-hostpath -- ls /host/log
# 应能看到节点上的日志文件(如 syslog、messages 等)
(3)清理资源
kubectl delete pod pod-emptydir pod-hostpath
# 验证:确认 Pod 已删除
5. PV & PVC(持久化存储)

核心问题:Volume 的生命周期与 Pod 绑定,无法长期保存数据。PV 和 PVC 解决了这个问题:

  • PV(PersistentVolume):集群管理员提前创建的 “存储资源”(如磁盘、NFS 共享目录),生命周期独立于 Pod。
  • PVC(PersistentVolumeClaim):用户(Pod)对 PV 的 “申请”,类似 “租房:PV 是房子,PVC 是租房合同”。
(1)创建 PV(以 hostPath 为例,生产环境常用 NFS、云存储等)

pv-demo.yaml:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-demo  # PV 名称
spec:
  capacity:  # 存储容量
    storage: 1Gi  # 1GB
  accessModes:  # 访问模式
    - ReadWriteOnce  # 只能被一个节点以读写方式挂载
  persistentVolumeReclaimPolicy: Retain  # 回收策略:Retain(保留数据,手动清理)
  hostPath:  # 存储类型:hostPath(节点路径,仅用于测试)
    path: /data/pv  # 节点上的实际路径(需提前在节点创建:mkdir -p /data/pv)

配置说明:

  • accessModes
    

    :

    • ReadWriteOnce(RWO):单节点读写。
    • ReadOnlyMany(ROX):多节点只读。
    • ReadWriteMany(RWX):多节点读写(如 NFS 支持)。
  • persistentVolumeReclaimPolicy:PV 回收策略(Retain 保留数据,Delete 自动删除,Recycle 清空数据)。

提前在节点创建目录(所有节点或调度目标节点):

# 进入节点执行(或通过 kubectl debug 临时进入)
mkdir -p /data/pv
(2)创建 PVC(申请 PV)

pvc-demo.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo  # PVC 名称
spec:
  accessModes:
    - ReadWriteOnce  # 需与 PV 的 accessModes 匹配
  resources:
    requests:
      storage: 1Gi  # 申请 1GB 存储(需 ≤ PV 的 capacity)

说明:PVC 会自动匹配满足条件(容量、访问模式)的 PV,绑定后即可使用。

(3)创建使用 PVC 的 Pod

pod-using-pvc.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-pvc
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    volumeMounts:
    - name: pv-storage  # 挂载存储卷
      mountPath: /data  # 容器内挂载路径
    command: ["/bin/sh", "-c", "echo '持久化数据' > /data/test.txt; sleep 3600"]
  volumes:
  - name: pv-storage
    persistentVolumeClaim:
      claimName: pvc-demo  # 关联的 PVC 名称
(4)创建并验证持久化效果
# 1. 创建 PV
kubectl apply -f pv-demo.yaml
# 2. 创建 PVC(会自动绑定到 PV)
kubectl apply -f pvc-demo.yaml
# 3. 创建 Pod
kubectl apply -f pod-using-pvc.yaml

# 查看 PV 和 PVC 状态(确认绑定)
kubectl get pv pv-demo  # STATUS 应为 Bound
kubectl get pvc pvc-demo  # STATUS 应为 Bound

# 验证数据写入
kubectl exec -it pod-pvc -- cat /data/test.txt  # 预期输出:持久化数据

# 测试持久化:删除 Pod 后重建,数据仍存在
kubectl delete pod pod-pvc
kubectl apply -f pod-using-pvc.yaml  # 重建 Pod
kubectl exec -it pod-pvc -- cat /data/test.txt  # 仍能看到数据
(5)清理资源
# 1. 先删除 Pod(否则 PV 无法删除)
kubectl delete pod pod-pvc
# 2. 删除 PVC
kubectl delete pvc pvc-demo
# 3. 删除 PV(如果回收策略是 Retain,需手动清理节点数据)
kubectl delete pv pv-demo
# 4. 清理节点上的残留数据(在节点执行)
rm -rf /data/pv

三、总结

存储组件核心作用生命周期典型用法
ConfigMap存储非敏感配置独立于 Pod环境变量、配置文件挂载
Secret存储敏感数据(Base64 编码)独立于 Pod密码、证书挂载
Downward API注入 Pod 元数据与 Pod 一致容器获取自身名称、IP 等信息
Volume为 Pod 提供临时 / 共享存储与 Pod 一致emptyDir 多容器共享、hostPath 节点存储
PV/PVC长期持久化存储(生命周期独立于 Pod)PV 独立于 Pod数据库数据、用户文件持久化

更多推荐