Lesson 12:ConfigMap 与 Secret 配置管理

admin 发布于 8 天前 7 次阅读


学习目标

  • 理解配置与代码分离的工程意义
  • 掌握 ConfigMap 的创建方式与挂载方式
  • 理解 Secret 的类型与 Base64 编码(≠加密)
  • 掌握配置热更新机制

1. 为什么要分离配置?

将数据库地址、端口号、API Key 等配置硬编码在容器镜像中是一个严重的反模式:

  • 修改配置就要重新构建镜像
  • 同一个镜像无法在开发/测试/生产环境间复用
  • 敏感信息(密码、密钥)泄露在镜像层中

ConfigMap 存储非敏感配置,Secret 存储敏感配置。两者都可以通过环境变量或挂载文件的方式注入到 Pod 中。


2. ConfigMap

创建方式

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 从命令行键值对创建
kubectl create configmap app-config --from-literal=DB_HOST=mysql-service --from-literal=DB_PORT=3306

预期输出

bashconfigmap/app-config created
bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 查看 ConfigMap 列表
kubectl get configmap app-config

预期输出

bashNAME         DATA   AGE
app-config   2      0s

输出解读DATA 2 表示这个 ConfigMap 中有 2 个键值对(DB_HOST 和 DB_PORT)。

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 查看 ConfigMap 的详细内容
kubectl describe configmap app-config

预期输出

bashName:         app-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
DB_HOST:
----
mysql-service
DB_PORT:
----
3306

BinaryData
====

Events:  <none>

输出解读Data 部分清晰列出了每个键和对应的值。BinaryData 为空,表示没有二进制数据。ConfigMap 支持存储纯文本和二进制数据两种格式。

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 以 YAML 格式查看(观察存储结构)
kubectl get configmap app-config -o yaml

预期输出

yamlapiVersion: v1
data:
  DB_HOST: mysql-service
  DB_PORT: "3306"
kind: ConfigMap
metadata:
  creationTimestamp: "2026-04-23T09:01:49Z"
  name: app-config
  namespace: default
  resourceVersion: "166379"
  uid: f3ebf66d-36b9-48a3-9ad1-305d9183ff5c

输出解读:ConfigMap 的 YAML 结构非常简单——data 字段下就是纯粹的键值对。注意 DB_PORT 的值 "3306" 带了引号,因为 YAML 中所有 ConfigMap 的值都是字符串类型

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 清理
kubectl delete configmap app-config

其他创建方式

bash# 从文件创建(将整个文件内容作为一个键值对)
kubectl create configmap nginx-conf --from-file=nginx.conf

# 从 YAML 声明式创建(推荐用于生产环境,可纳入 Git 管理)
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DB_HOST: "mysql-service"
  DB_PORT: "3306"
  app.properties: |
    server.port=8080
    logging.level=INFO
EOF

参数解读| 符号是 YAML 的多行文本语法。app.properties 的值是一个完整的多行配置文件内容,Pod 挂载后会生成一个名为 app.properties 的文件。

使用方式

yaml# 方式 1:作为环境变量注入(所有键值对变成容器的环境变量)
spec:
  containers:
  - name: app
    envFrom:
    - configMapRef:
        name: app-config    # 容器内可直接用 $DB_HOST、$DB_PORT

# 方式 2:作为文件挂载(每个键变成一个文件)
spec:
  containers:
  - name: app
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config    # 容器内 /etc/config/DB_HOST、/etc/config/DB_PORT
  volumes:
  - name: config-volume
    configMap:
      name: app-config

设计选择

  • 环境变量方式:简单直接,适合少量配置项。缺点是 ConfigMap 更新后不会自动刷新,需要重启 Pod
  • Volume 挂载方式:适合配置文件(如 nginx.conf)。优点是 ConfigMap 更新后约 30-60 秒自动刷新,无需重启 Pod

3. Secret

核心区别

Secret 与 ConfigMap 结构相同,但有以下区别:

  • 数据以 Base64 编码存储(注意:Base64 不是加密,只是编码!任何人都能解码
  • 挂载到 Pod 后存放在 tmpfs(内存文件系统)中,不写入磁盘
  • 可以通过 RBAC 对 Secret 的访问进行细粒度控制

常见类型

类型用途
Opaque通用密钥(默认类型)
kubernetes.io/tlsTLS 证书和私钥
kubernetes.io/dockerconfigjson私有镜像仓库认证

创建与查看

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 创建一个包含数据库密码的 Secret
kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password='S3cur3P@ss!'

预期输出

bashsecret/db-secret created
bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

kubectl get secret db-secret

预期输出

bashNAME        TYPE     DATA   AGE
db-secret   Opaque   2      0s

输出解读TYPE: Opaque 是通用类型的 Secret。DATA: 2 表示包含 2 个键值对。注意 kubectl get 不会显示 Secret 的实际值——这是一层基本的安全保护。

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# describe 也只显示字节数,不显示实际值
kubectl describe secret db-secret

预期输出

bashName:         db-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  11 bytes
username:  5 bytes

输出解读:只显示了 password: 11 bytes(11 个字节 = S3cur3P@ss! 的长度)和 username: 5 bytes(5 个字节 = admin 的长度),而不是明文值。

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 用 -o yaml 可以看到 Base64 编码后的值
kubectl get secret db-secret -o yaml

预期输出

yamlapiVersion: v1
data:
  password: UzNjdXIzUEBzcyE=
  username: YWRtaW4=
kind: Secret
metadata:
  creationTimestamp: "2026-04-23T09:01:57Z"
  name: db-secret
  namespace: default
type: Opaque

安全警告UzNjdXIzUEBzcyE= 看起来像加密,但其实只是 Base64 编码。任何人都可以轻松解码:

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# Base64 解码验证——一行命令就能还原明文!
echo "UzNjdXIzUEBzcyE=" | base64 -d

预期输出

bashS3cur3P@ss!

重要认知:这就是为什么说 Base64 ≠ 加密。在生产环境中,如果需要真正的加密保护,应该启用 etcd 的静态加密(Encryption at Rest)或使用外部密钥管理系统(如 HashiCorp Vault)。

在 Pod 中使用 Secret

yaml# 作为环境变量引用单个键
spec:
  containers:
  - name: app
    env:
    - name: DB_PASSWORD        # 环境变量名
      valueFrom:
        secretKeyRef:
          name: db-secret      # Secret 的名字
          key: password         # Secret 中的键名
bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 清理
kubectl delete secret db-secret

动手实验

实验 12.1:ConfigMap 热更新验证

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 创建 ConfigMap
kubectl create configmap test-config --from-literal=message="Hello V1"

预期输出

bashconfigmap/test-config created
bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 创建 Pod,通过 Volume 挂载 ConfigMap,每 5 秒读取并打印配置内容
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: config-demo
spec:
  containers:
  - name: app
    image: docker.m.daocloud.io/library/busybox
    command: ['sh', '-c', 'while true; do cat /etc/config/message; echo; sleep 5; done']
    volumeMounts:
    - name: config-vol
      mountPath: /etc/config
  volumes:
  - name: config-vol
    configMap:
      name: test-config
EOF

kubectl wait --for=condition=Ready pod/config-demo --timeout=60s

预期输出

bashpod/config-demo created
pod/config-demo condition met
bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 查看初始日志——应该输出 "Hello V1"
kubectl logs config-demo --tail=3

预期输出

bashHello V1
bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 修改 ConfigMap 的值为 "Hello V2"
kubectl patch configmap test-config -p '{"data":{"message":"Hello V2"}}'

预期输出

bashconfigmap/test-config patched
bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 等待约 60 秒后再次查看日志
sleep 65
kubectl logs config-demo --tail=3

预期输出

bashHello V1
Hello V1
Hello V2

输出解读:你可以清晰地看到日志从 Hello V1 自动变成了 Hello V2——我们没有重启 Pod,ConfigMap 的修改通过 Volume 挂载自动传播到了容器内部。这就是热更新的威力。K8s 的 kubelet 会定期(默认每 60 秒)同步 ConfigMap 的最新值到挂载的 Volume 中。

bash# === 在 Master 节点 (172.16.11.104) 上执行 ===

# 清理
kubectl delete pod config-demo
kubectl delete configmap test-config

预期输出

bashpod "config-demo" deleted
configmap "test-config" deleted

检查点

  •  能用三种方式创建 ConfigMap(命令行、文件、YAML)
  •  理解环境变量注入 vs Volume 挂载的热更新差异
  •  知道 Secret 的 Base64 编码不等于加密
  •  能在 Pod 中引用 Secret 的值
  •  能通过修改 ConfigMap 观察到 Pod 内配置自动更新
此作者没有提供个人介绍。
最后更新于 2026-04-27