k8s 存储
一、K8s 存储核心组件分类
按用途和特性,K8s 存储相关组件可分为以下几类:
| 组件类型 | 作用说明 | 适用场景 |
|---|---|---|
| ConfigMap | 存储非敏感配置数据(如配置文件、环境变量),以键值对形式存在 | 应用配置文件(如 Nginx 配置、数据库连接地址) |
| Secret | 存储敏感数据(如密码、Token、证书),数据会被 Base64 编码(非加密) | 数据库密码、API 密钥、SSL 证书 |
| Downward API | 将 Pod 自身的元数据(如名称、IP、标签)注入到容器内部 | 容器需要知道自身在 K8s 中的信息(如 Pod 名称) |
| Volume | 为 Pod 提供临时或持久化存储空间,生命周期与 Pod 一致 | Pod 内多容器共享数据、临时文件存储 |
| PV/PVC | PV(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 | 数据库数据、用户文件持久化 |
更多推荐


所有评论(0)