K8s 学习笔记(五):配置与存储

写在前面

本文是 K8s 学习笔记系列的第五篇,介绍配置管理(ConfigMap、Secret)和存储(PV/PVC、StorageClass)。前置知识:服务发现与网络(第四篇)。


一、ConfigMap

ConfigMap 用于存储非敏感的配置数据,让配置和镜像解耦。

1.1 创建 ConfigMap

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 从字面量创建
kubectl create configmap app-config \
  --from-literal=APP_ENV=production \
  --from-literal=APP_PORT=8080 \
  --from-literal=DB_HOST=mysql.prod

# 从文件创建
kubectl create configmap nginx-config --from-file=nginx.conf

# 从目录创建(每个文件变成一个 key)
kubectl create configmap app-config --from-file=./config/

# 从 YAML 创建
kubectl apply -f configmap.yaml

1.2 ConfigMap YAML

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  # 键值对
  APP_ENV: "production"
  APP_PORT: "8080"
  DB_HOST: "mysql.prod"

  # 完整配置文件
  application.yml: |
    server:
      port: 8080
    spring:
      datasource:
        url: jdbc:mysql://mysql.prod:3306/mydb

1.3 在 Pod 中使用

方式1:环境变量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
spec:
  containers:
  - name: app
    env:
    - name: APP_ENV
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: APP_ENV
    - name: DB_HOST
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DB_HOST

    # 或者全部加载为环境变量
    envFrom:
    - configMapRef:
        name: app-config

方式2:挂载为文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
spec:
  containers:
  - name: app
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
      readOnly: true

  volumes:
  - name: config-volume
    configMap:
      name: app-config

挂载后文件结构:

1
2
3
4
5
/etc/config/
├── APP_ENV             # 内容:production
├── APP_PORT            # 内容:8080
├── DB_HOST             # 内容:mysql.prod
└── application.yml     # 内容:完整 YAML

方式3:挂载单个文件

1
2
3
4
5
6
7
volumes:
- name: config-volume
  configMap:
    name: app-config
    items:                      # 只挂载指定 key
    - key: application.yml
      path: application.yml

1.4 更新 ConfigMap

1
2
3
4
5
# 直接编辑
kubectl edit configmap app-config

# 更新后,挂载为文件的 Pod 会自动刷新(有延迟,约1分钟)
# 通过环境变量注入的不会自动更新,需要重启 Pod

二、Secret

Secret 用于存储敏感信息(密码、Token、证书),数据以 base64 编码存储。

Secret 只是编码不是加密,生产环境建议开启 EncryptionConfiguration 或用外部密钥管理(Vault)。

2.1 创建 Secret

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 从字面量创建
kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password='P@ssw0rd'

# 从文件创建
kubectl create secret generic tls-secret \
  --from-file=tls.crt=./server.crt \
  --from-file=tls.key=./server.key

# 创建 Docker 仓库认证 Secret
kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=password

2.2 Secret YAML

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque                  # 通用类型
data:
  username: YWRtaW4=           # base64 编码的 "admin"
  password: UEBzc3cwcmQ=       # base64 编码的 "P@ssw0rd"

# 也可以用 stringData(明文,K8s 会自动编码)
stringData:
  username: admin
  password: P@ssw0rd

2.3 Secret 类型

1
2
3
4
5
6
Opaque                    — 通用(默认)
docker-registry           — Docker 仓库认证
tls                       — TLS 证书
basic-auth                — 基础认证
ssh-auth                  — SSH 认证
token                     — Token

2.4 在 Pod 中使用

 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
# 环境变量
env:
- name: DB_PASSWORD
  valueFrom:
    secretKeyRef:
      name: db-secret
      key: password

# 挂载为文件
volumeMounts:
- name: secret-volume
  mountPath: /etc/secrets
  readOnly: true
volumes:
- name: secret-volume
  secret:
    secretName: db-secret

# 拉取私有镜像
spec:
  imagePullSecrets:
  - name: regcred
  containers:
  - name: app
    image: registry.example.com/my-app:1.0

2.5 查看 Secret 内容

1
2
3
4
5
6
7
8
# 查看列表
kubectl get secrets

# 查看详情(不显示内容)
kubectl describe secret db-secret

# 解码查看内容
kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 --decode

三、Volume

Volume 解决容器数据持久化问题。容器重启后文件会丢失,Volume 让数据独立于容器生命周期。

3.1 Volume 类型

1
2
3
4
5
emptyDir     — 临时目录,Pod 删除后数据丢失(Pod 内容器共享)
hostPath     — 挂载宿主机目录(单节点,不适合多节点)
configMap    — 挂载 ConfigMap
secret       — 挂载 Secret
persistentVolumeClaim — 挂载持久化存储(推荐)

3.2 emptyDir

Pod 内容器共享临时目录,Pod 删除后数据丢失:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
spec:
  containers:
  - name: app
    volumeMounts:
    - name: cache
      mountPath: /cache
  - name: sidecar
    volumeMounts:
    - name: cache
      mountPath: /cache
  volumes:
  - name: cache
    emptyDir: {}

3.3 hostPath

挂载宿主机目录(开发/测试用,不推荐生产):

1
2
3
4
5
volumes:
- name: data
  hostPath:
    path: /data/app           # 宿主机路径
    type: DirectoryOrCreate

四、持久化存储(PV/PVC)

PV(PersistentVolume)是集群级别的存储资源,PVC(PersistentVolumeClaim)是用户对存储的申请。

4.1 存储架构

1
2
3
4
5
6
7
管理员创建 PV(或由 StorageClass 动态创建)
用户创建 PVC(声明需要的存储大小和访问模式)
K8s 绑定 PVC 到合适的 PV
Pod 通过 PVC 使用存储

4.2 PV 示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-10gi
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce              # 单节点读写
  persistentVolumeReclaimPolicy: Retain   # 释放后保留数据
  storageClassName: standard
  hostPath:                    # 本地存储(测试用)
    path: /data/pv-10gi

4.3 PVC 示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-data
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard

4.4 在 Pod 中使用 PVC

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
spec:
  containers:
  - name: app
    volumeMounts:
    - name: data
      mountPath: /var/lib/data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: app-data

4.5 访问模式

1
2
3
4
ReadWriteOnce(RWO)    — 单节点读写(最常用)
ReadOnlyMany(ROX)     — 多节点只读
ReadWriteMany(RWX)    — 多节点读写(需要存储后端支持)
ReadWriteOncePod(RWOP) — 单 Pod 读写(K8s 1.27+)

4.6 回收策略

1
2
3
Retain    — 保留数据,需要手动清理(生产推荐)
Delete    — 自动删除 PV 和底层存储
Recycle   — 已废弃,用 Delete 替代

五、StorageClass

StorageClass 定义存储类型,支持动态创建 PV。

5.1 StorageClass 示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs    # 存储提供者
parameters:
  type: gp3
  fsType: ext4
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

5.2 PVC 动态分配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 不需要手动创建 PV,StorageClass 自动创建
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-data
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: fast-ssd     # 指定 StorageClass
  resources:
    requests:
      storage: 10Gi

5.3 minikube 的默认存储

1
2
3
4
5
6
7
8
9
# minikube 自带 standard StorageClass
kubectl get storageclass
# NAME                 PROVISIONER                RECLAIMPOLICY
# standard (default)   k8s.io/minikube-hostpath   Delete

# 创建 PVC 后自动创建 PV
kubectl apply -f pvc.yaml
kubectl get pv          # 自动创建的 PV
kubectl get pvc         # PVC 自动绑定

六、StatefulSet + PVC 模式

StatefulSet 配合 volumeClaimTemplates,每个 Pod 自动获得独立的持久化存储:

 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: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 3
  template:
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: standard
      resources:
        requests:
          storage: 10Gi
1
2
3
4
5
6
自动创建的 PVC:
mysql-data-mysql-0   → mysql-0 的存储
mysql-data-mysql-1   → mysql-1 的存储
mysql-data-mysql-2   → mysql-2 的存储

Pod 重建后,PVC 不会删除,Pod 自动绑定回原来的 PVC

七、开发者视角:配置管理最佳实践

7.1 配置分层

1
2
3
4
环境变量        → 非敏感配置(APP_ENV、APP_PORT)
ConfigMap      → 配置文件、环境变量(不同环境不同 ConfigMap)
Secret         → 密码、Token、证书
PVC            → 需要持久化的数据

7.2 应用适配

1
2
3
4
5
6
7
8
func main() {
    // 从环境变量读取配置
    dbHost := os.Getenv("DB_HOST")
    dbPassword := os.Getenv("DB_PASSWORD")
    
    // 本地开发用 .env 文件,K8s 用 ConfigMap/Secret 注入
    // 代码不需要感知配置来源
}

7.3 不同环境管理

1
2
3
4
5
dev 环境配置   → app-config-dev
staging 配置  → app-config-staging
prod 配置     → app-config-prod

部署时通过 -n 或 -f 指定对应的 ConfigMap

八、小结

本文学习了 K8s 的配置与存储:

  • ConfigMap:非敏感配置管理
  • Secret:敏感信息管理
  • Volume:容器存储
  • PV/PVC:持久化存储
  • StorageClass:动态存储分配
  • StatefulSet + PVC 模式
  • 配置管理最佳实践

下一篇将学习调度与扩缩:标签选择器、节点亲和性和 HPA。