Kubernetes ConfigMap 与 Secret 完全指南(适用于 Kubernetes v1.35)

文档说明

  • 适用版本:Kubernetes v1.35.4
  • 前置知识:了解 Pod、Deployment 的基本概念
  • 目标:从零掌握 ConfigMap 和 Secret 的原理、配置与使用

第一章:为什么需要 ConfigMap 和 Secret?

在 Kubernetes 中,应用通常需要各种配置信息才能正常运行——数据库地址、日志级别、功能开关、密码等。如果把这些配置硬编码在容器镜像里:

  • 修改配置需要重新构建镜像,流程繁琐
  • 不同环境(开发/测试/生产)需要不同镜像,难以管理
  • 敏感信息(密码、密钥)暴露在镜像中,存在严重安全风险

ConfigMap 和 Secret 正是为了解决这些问题而设计的——它们将配置信息与容器镜像解耦,让你可以在不重新构建镜像的情况下修改应用配置。

资源类型用途数据特点
ConfigMap存储非敏感配置信息明文存储
Secret存储敏感信息(密码、Token、证书等)Base64 编码存储

第二章:ConfigMap 详解

2.1 什么是 ConfigMap?

ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。Pod 可以将其用作环境变量、命令行参数或者存储卷中的配置文件

核心价值:ConfigMap 将你的环境配置信息和容器镜像解耦,便于应用配置的修改。

2.2 ConfigMap 的核心特性

特性说明
存储方式键值对(Key-Value)
数据字段data(UTF-8 字符串)和 binaryData(Base64 编码的二进制数据)
大小限制每个 ConfigMap 最大 1 MiB
用途环境变量、配置文件挂载、命令行参数
不可变支持设置 immutable: true,创建后不可修改

⚠️ 注意:ConfigMap 不提供保密或者加密功能。如果你想存储的数据是机密的,请使用 Secret。

2.3 ConfigMap YAML 示例

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: default
data:
  # 简单键值对
  LOG_LEVEL: "info"
  DATABASE_HOST: "postgres-service.default.svc.cluster.local"
  DATABASE_PORT: "5432"
  FEATURE_NEW_UI: "true"
  
  # 多行配置文件内容(使用 |)
  app.properties: |
    server.port=8080
    server.timeout=30s
    cache.enabled=true
    
  # 配置文件内容(XML/JSON/YAML 格式均可)
  nginx.conf: |
    server {
        listen 80;
        server_name localhost;
        location / {
            root /usr/share/nginx/html;
        }
    }

字段说明

字段说明
apiVersion固定为 v1
kind固定为 ConfigMap
metadata.nameConfigMap 名称,必须是合法的 DNS 子域名
data存储配置数据,键名只能由字母、数字、-_. 组成

2.4 创建 ConfigMap 的四种方式

方式一:从字面值创建

kubectl create configmap app-config \
  --from-literal=LOG_LEVEL=info \
  --from-literal=DATABASE_HOST=postgres-service

方式二:从文件创建

# 文件内容成为值,文件名成为键
kubectl create configmap app-config --from-file=./app.properties

# 指定键名
kubectl create configmap app-config --from-file=config=./app.properties

方式三:从目录创建

# 目录下每个文件成为一个键值对
kubectl create configmap app-config --from-file=./config-dir/

方式四:从 YAML 文件创建(推荐)

kubectl apply -f configmap.yaml

2.5 在 Pod 中使用 ConfigMap

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

单个键注入

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-app
    image: my-app:v1
    env:
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: LOG_LEVEL
    - name: DATABASE_HOST
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DATABASE_HOST

批量注入所有键

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-app
    image: my-app:v1
    envFrom:
    - configMapRef:
        name: app-config   # 注入所有键作为环境变量
方式二:作为文件挂载(Volume)
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-app
    image: my-app:v1
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config   # 挂载到容器内的路径
  volumes:
  - name: config-volume
    configMap:
      name: app-config         # 引用 ConfigMap

挂载后的效果:ConfigMap 中的每个键(key)都会成为挂载目录下的一个文件,文件名就是键名,文件内容就是键值。

例如,上面的 ConfigMap 挂载到 /etc/config 后,会产生:

  • /etc/config/LOG_LEVEL → 内容为 info
  • /etc/config/DATABASE_HOST → 内容为 postgres-service.default.svc.cluster.local
  • /etc/config/app.properties → 内容为多行配置文本

挂载特定键为单个文件

volumes:
- name: config-volume
  configMap:
    name: app-config
    items:
    - key: app.properties
      path: application.properties   # 指定挂载后的文件名

2.6 不可变 ConfigMap(Immutable ConfigMap)

从 Kubernetes v1.19 开始,你可以将 ConfigMap 设置为不可变(Immutable)

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
immutable: true   # 设置为不可变
data:
  LOG_LEVEL: "info"

优点

  • 防止意外修改
  • 提高性能(kube-apiserver 不再需要监视不可变对象的变化)

注意:一旦设置为不可变,无法修改或删除该 ConfigMap(除非删除整个对象)。

第三章:Secret 详解

3.1 什么是 Secret?

Secret 是 Kubernetes 中用于存储敏感信息的对象,如密码、OAuth 令牌、SSH 密钥、TLS 证书等。

核心价值:Secret 将敏感内容与 Pod 分离,避免在源代码或容器镜像中暴露机密信息。

3.2 Secret 与 ConfigMap 的核心区别

对比维度ConfigMapSecret
设计用途非机密配置数据敏感信息(密码、Token、证书)
数据编码明文(UTF-8 字符串)Base64 编码
大小限制1 MiB1 MiB(默认)
静态加密不支持支持(需配置)
适用场景日志级别、端口号、功能开关数据库密码、API 密钥、TLS 证书

3.3 Secret 的类型

类型用途
Opaque通用类型,适用于大多数场景(密码、API 密钥等)
kubernetes.io/tls存储 TLS 证书和私钥
kubernetes.io/dockerconfigjson存储 Docker 仓库认证信息
kubernetes.io/basic-auth存储基本认证凭据(用户名/密码)
kubernetes.io/ssh-auth存储 SSH 认证凭据
kubernetes.io/service-account-token服务账户令牌(由 Kubernetes 自动创建)

3.4 Secret YAML 示例

使用 data 字段(Base64 编码)

Step 1:对敏感数据进行 Base64 编码

echo -n 'admin' | base64      # 输出:YWRtaW4=
echo -n 'MyP@ssw0rd' | base64 # 输出:TXlQQHNzdzByZA==

Step 2:编写 Secret YAML

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
data:
  username: YWRtaW4=              # Base64 编码后的 "admin"
  password: TXlQQHNzdzByZA==      # Base64 编码后的 "MyP@ssw0rd"
使用 stringData 字段(未编码,更便捷)

stringData 字段允许你直接写入未编码的字符串,Kubernetes 会在创建时自动进行 Base64 编码。

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
stringData:
  username: admin                 # 直接写明文,自动编码
  password: MyP@ssw0rd
  config.yaml: |                  # 也可以存储整个配置文件
    apiUrl: "https://api.example.com"
    timeout: 30

⚠️ 注意:当你检索 Secret 数据时,返回的是编码后的值,而不是 stringData 中提供的纯文本值。

3.5 创建 Secret 的三种方式

方式一:从字面值创建

kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password=MyP@ssw0rd

方式二:从文件创建

# 文件内容成为值,文件名成为键
kubectl create secret generic db-credentials \
  --from-file=./username.txt \
  --from-file=./password.txt

方式三:从 YAML 文件创建(推荐)

kubectl apply -f secret.yaml

创建 TLS Secret

kubectl create secret tls example-tls \
  --cert=./tls.crt \
  --key=./tls.key

3.6 在 Pod 中使用 Secret

方式一:作为环境变量注入
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-app
    image: my-app:v1
    env:
    - name: DB_USERNAME
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: username
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: password

批量注入所有键

envFrom:
- secretRef:
    name: db-credentials
方式二:作为文件挂载(Volume)
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-app
    image: my-app:v1
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secrets
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: db-credentials

挂载后的效果:Secret 中的每个键都会成为挂载目录下的一个文件。例如:

  • /etc/secrets/username → 内容为 admin
  • /etc/secrets/password → 内容为 MyP@ssw0rd

挂载特定键并指定文件权限

volumes:
- name: secret-volume
  secret:
    secretName: db-credentials
    defaultMode: 0400           # 文件权限(只读)
    items:
    - key: username
      path: db-user             # 重命名文件
      mode: 0600                # 单独指定权限

💡 推荐:使用卷挂载方式而非环境变量,因为环境变量可能在调试信息、日志中意外暴露。

3.7 Secret 的安全注意事项

⚠️ 重要安全警告

  1. 默认情况下,Secret 未加密地存储在 etcd 中。任何拥有 API 访问权限的人都可以检索或修改 Secret,任何有权访问 etcd 的人也可以。

  2. Secret 的 Base64 编码不是加密。它只是编码,不是加密。

  3. 授予对 Secret 的 list 访问权限,意味着允许获取 Secret 的内容

  4. 如果一个用户可以创建使用某 Secret 的 Pod,则该用户也可以看到该 Secret 的值

生产环境安全建议

建议说明
启用静态加密配置 etcd 对 Secret 数据进行加密存储
最小权限访问使用 RBAC 严格控制对 Secret 的访问权限
使用单独的命名空间隔离不同团队/应用的 Secret 访问
使用短期 Secret尽量使用有效期短的凭证
保护 etcd 访问仅允许集群管理员访问 etcd
etcd 通信加密多个 etcd 实例之间配置加密的 SSL/TLS 通信

第四章:ConfigMap 与 Secret 的更新与生效机制

4.1 更新 ConfigMap/Secret 后,Pod 会怎样?

使用方式更新后是否自动生效说明
环境变量注入不会生效环境变量在 Pod 启动时已固定,需重启 Pod 才能生效
卷挂载(Volume)会自动更新文件内容会更新,但应用进程不会自动重启

关键点:即使 ConfigMap/Secret 作为卷挂载的文件内容自动更新了,容器内的进程不会自动重启。如果你的应用需要重新加载配置,需要实现配置热加载机制(如发送 SIGHUP 信号)或滚动重启 Pod。

4.2 如何触发 Pod 重启?

当 ConfigMap/Secret 更新后需要 Pod 重启时,常用方法:

方法一:使用滚动更新

kubectl rollout restart deployment/my-app

方法二:使用 Helm 的 --recreate-pods

helm upgrade my-app ./chart --recreate-pods

方法三:修改 Pod 注解(触发滚动更新)

在 Deployment 的 template 中添加一个会随 ConfigMap 变化而变化的注解:

spec:
  template:
    metadata:
      annotations:
        config-hash: "{{ .Values.configHash }}"   # 随 ConfigMap 变化而变化

第五章:完整实战示例

5.1 场景:部署一个使用 ConfigMap 和 Secret 的 Web 应用

Step 1:创建 ConfigMap(应用配置)

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: web-app-config
data:
  LOG_LEVEL: "info"
  API_TIMEOUT: "30"
  FEATURE_FLAG_DEBUG: "false"
  app-settings.json: |
    {
      "cache": {
        "enabled": true,
        "ttl": 300
      },
      "rateLimit": {
        "requestsPerSecond": 100
      }
    }

Step 2:创建 Secret(数据库密码)

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: web-app-secret
type: Opaque
stringData:
  DB_PASSWORD: "SecurePassword123"
  API_KEY: "sk-1234567890abcdef"

Step 3:部署应用并注入配置

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: app
        image: my-web-app:v1
        ports:
        - containerPort: 8080
        
        # 环境变量注入(ConfigMap + Secret)
        env:
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: web-app-config
              key: LOG_LEVEL
        - name: API_TIMEOUT
          valueFrom:
            configMapKeyRef:
              name: web-app-config
              key: API_TIMEOUT
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: web-app-secret
              key: DB_PASSWORD
        - name: API_KEY
          valueFrom:
            secretKeyRef:
              name: web-app-secret
              key: API_KEY
        
        # 配置文件挂载(ConfigMap)
        volumeMounts:
        - name: config-volume
          mountPath: /app/config
          readOnly: true
        
        # 敏感信息挂载(Secret)
        - name: secret-volume
          mountPath: /app/secrets
          readOnly: true
      
      volumes:
      - name: config-volume
        configMap:
          name: web-app-config
      - name: secret-volume
        secret:
          secretName: web-app-secret
          defaultMode: 0400

Step 4:部署

kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f deployment.yaml

Step 5:验证

# 查看 ConfigMap
kubectl get configmap web-app-config
kubectl describe configmap web-app-config

# 查看 Secret(注意:值会以 Base64 显示)
kubectl get secret web-app-secret
kubectl describe secret web-app-secret

# 进入 Pod 验证挂载
kubectl exec -it <pod-name> -- cat /app/config/LOG_LEVEL
kubectl exec -it <pod-name> -- cat /app/secrets/DB_PASSWORD

第六章:最佳实践总结

6.1 ConfigMap 最佳实践

  1. ConfigMap 只用于非敏感数据:敏感信息请使用 Secret
  2. 注意 1 MiB 大小限制:大配置文件考虑使用存储卷或外部配置服务
  3. 使用 immutable 保护关键配置:对于生产环境不应变更的配置,设置为不可变
  4. 配置与代码分离:不要在镜像中硬编码环境相关的配置
  5. 合理组织 ConfigMap:按功能或应用拆分,避免单个 ConfigMap 过大

6.2 Secret 最佳实践

  1. 启用 etcd 静态加密:生产环境必须配置
  2. 使用 RBAC 最小权限原则:严格限制谁可以访问 Secret
  3. 优先使用卷挂载而非环境变量:降低泄露风险
  4. 避免在日志或调试信息中暴露 Secret
  5. 使用短期凭证:尽可能使用有效期短的凭据
  6. 不要将 Secret 提交到 Git 仓库:使用 stringData 时同样注意

6.3 通用最佳实践

实践说明
ConfigMap 和 Secret 必须在同一 NamespacePod 只能引用同 Namespace 的 ConfigMap/Secret
先创建 ConfigMap/Secret,再创建 Pod否则 Pod 会因找不到配置而启动失败
使用有意义的命名app-configdb-credentials,便于识别
版本管理将 ConfigMap/Secret 的 YAML 文件纳入 Git 管理(Secret 需加密)
监控和审计监控 Secret 的访问,配置审计规则

附录:快速索引

需求命令/配置
查看所有 ConfigMapkubectl get configmap
查看所有 Secretkubectl get secret
查看 ConfigMap 详情kubectl describe configmap <name>
查看 Secret 详情(Base64)kubectl describe secret <name>
解码 Secret 值kubectl get secret <name> -o jsonpath='{.data.password}' | base64 -d
创建 ConfigMap(字面值)kubectl create configmap <name> --from-literal=key=value
创建 Secret(字面值)kubectl create secret generic <name> --from-literal=key=value
创建 TLS Secretkubectl create secret tls <name> --cert=./cert.crt --key=./key.key
从 YAML 创建kubectl apply -f <file>.yaml
删除 ConfigMap/Secretkubectl delete configmap <name> / kubectl delete secret <name>
触发 Pod 重启kubectl rollout restart deployment/<name>
设置 ConfigMap 不可变immutable: true

文档版本:v1.0
适用环境:Kubernetes v1.35+ / v1 API
前置条件:已部署 Kubernetes 集群并配置 kubectl

更多推荐