7Kubernetes 实战

配置与 Secret

配置管理

ConfigMapSecret环境变量

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第7章:配置、Secret和ConfigMap(Configuration, Secrets, and ConfigMaps)

一、导读

1.1 本章学习目标

将配置与镜像解耦是容器化最佳实践。本章讲解 Kubernetes 的两种核心配置资源:ConfigMap(非敏感配置)和 Secret(敏感数据)。你将学习配置的三种注入方式、热更新机制、以及 Secret 的安全注意事项。

本章的核心学习目标包括:

  • 掌握 ConfigMap 的创建和使用:存储非敏感配置数据。
  • 掌握 Secret 的创建和使用:存储密码、Token、证书等敏感数据。
  • 理解三种配置注入方式:环境变量、命令行参数、Volume 挂载。
  • 理解配置热更新:哪些方式支持自动更新,哪些需要重启。
  • 了解 Secret 的安全增强:加密存储、RBAC 控制、外部 Secret 管理。
  • 掌握最佳实践:配置管理的设计原则。

1.2 为什么本章如此重要

将配置硬编码在镜像中是反模式——同一个镜像需要在不同环境(开发、测试、生产)中使用不同的配置。Kubernetes 的 ConfigMap 和 Secret 将配置从镜像中解耦,使得同一个镜像可以在不同环境中运行。

Secret 的安全管理更是生产环境的重中之重。数据库密码、API Key、TLS 证书等敏感数据需要加密存储、严格访问控制。理解 Secret 的工作原理和安全限制,是保障系统安全的基础。

1.3 核心问题引导

ConfigMap 和 Secret 有什么区别?为什么需要分开?

环境变量注入和 Volume 挂载注入各有什么优缺点?

ConfigMap 更新后,使用环境变量注入的 Pod 能自动获取新值吗?

Secret 的 Base64 编码是加密吗?如何增强 Secret 的安全性?

如何在 Git 中安全地存储 Secret?


二、核心概念详解

2.1 ConfigMap

ConfigMap 存储非敏感的配置数据,以键值对形式保存。

2.1.1 创建 ConfigMap

bash
# 从字面量创建
kubectl create configmap app-config \
  --from-literal=DATABASE_URL=postgres://db:5432/myapp \
  --from-literal=LOG_LEVEL=info

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

# 从 env 文件创建
kubectl create configmap app-env --from-env-file=config.env
yaml
# YAML 定义
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_URL: "postgres://db:5432/myapp"
  LOG_LEVEL: "info"
  CACHE_TTL: "300"
  config.yaml: |
    server:
      port: 8080
      timeout: 30s
    cache:
      ttl: 300s
      max_size: 1000

2.1.2 在 Pod 中使用 ConfigMap

方式一:环境变量

yaml
spec:
  containers:
    - name: app
      image: myapp:1.0
      env:
        - name: DATABASE_URL
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: DATABASE_URL
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: LOG_LEVEL
yaml
# 注入所有键值对
spec:
  containers:
    - name: app
      envFrom:
        - configMapRef:
            name: app-config

方式二:Volume 挂载

yaml
spec:
  containers:
    - name: app
      volumeMounts:
        - name: config-volume
          mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: app-config
# 每个 key 变成一个文件,value 变成文件内容
# /etc/config/DATABASE_URL 内容为 "postgres://db:5432/myapp"
# /etc/config/config.yaml 内容为 YAML 配置
yaml
# 挂载特定 key 到特定路径
spec:
  containers:
    - name: app
      volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
  volumes:
    - name: config-volume
      configMap:
        name: nginx-config
        items:
          - key: nginx.conf
            path: nginx.conf

方式三:命令行参数

yaml
spec:
  containers:
    - name: app
      image: myapp:1.0
      command: ["python", "app.py"]
      args:
        - "--log-level"
        - "$(LOG_LEVEL)"
        - "--cache-ttl"
        - "$(CACHE_TTL)"
      env:
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: LOG_LEVEL

2.2 Secret

Secret 存储敏感数据,与 ConfigMap 类似但有一些安全增强。

2.2.1 创建 Secret

bash
# 从字面量创建
kubectl create secret generic db-secret \
  --from-literal=DB_PASSWORD=password123 \
  --from-literal=DB_USER=admin

# 创建 TLS Secret
kubectl create secret tls tls-secret \
  --cert=tls.crt \
  --key=tls.key

# 创建 Docker Registry Secret
kubectl create secret docker-registry registry-secret \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=pass
yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  DB_PASSWORD: cGFzc3dvcmQxMjM=  # base64 编码
  DB_USER: YWRtaW4=              # base64 编码
stringData:
  API_KEY: "sk-abc123"  # 明文,K8s 自动 base64 编码

注意:Base64 不是加密!任何人都可以解码。Secret 的安全性依赖于:

  • etcd 的加密(需要配置 encryption at rest)
  • RBAC 控制访问权限
  • 网络隔离

2.2.2 在 Pod 中使用 Secret

yaml
spec:
  containers:
    - name: app
      env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: DB_PASSWORD
      volumeMounts:
        - name: secret-volume
          mountPath: /etc/secrets
          readOnly: true
  volumes:
    - name: secret-volume
      secret:
        secretName: db-secret
        defaultMode: 0400  # 只读权限

2.2.3 Secret 类型

  • Opaque:通用类型(默认)
  • kubernetes.io/tls:TLS 证书
  • kubernetes.io/dockerconfigjson:Docker Registry 认证
  • kubernetes.io/service-account-token:ServiceAccount Token
  • kubernetes.io/basic-auth:Basic 认证

2.3 配置热更新

2.3.1 更新行为对比

注入方式ConfigMap 更新后Secret 更新后
环境变量不更新(需重启 Pod)不更新(需重启 Pod)
Volume 挂载自动更新(有延迟)自动更新(有延迟)
命令行参数不更新(需重启 Pod)不更新(需重启 Pod)

Volume 挂载方式的更新延迟:kubelet 定期同步(默认1分钟),更新不是实时的。

2.3.2 触发滚动更新

bash
# 更新 ConfigMap 后手动触发滚动更新
kubectl rollout restart deployment/my-app

# 使用 annotation 自动触发
kubectl patch deployment my-app -p \
  '{"spec":{"template":{"metadata":{"annotations":{"configmap-version":"'$(date +%s)'"}}}}}'

2.4 Secret 安全增强

2.4.1 etcd 加密

yaml
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
  containers:
    - command:
        - --encryption-provider-config=/etc/kubernetes/encryption-config.yaml
yaml
# encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-encoded-key>
      - identity: {}  # 回退到不加密

2.4.2 RBAC 控制

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: secret-reader-binding
subjects:
  - kind: ServiceAccount
    name: my-app
roleRef:
  kind: Role
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

2.4.3 外部 Secret 管理

  • Sealed Secrets:加密 Secret 后可以安全存储到 Git
  • Vault:HashiCorp Vault 集成
  • External Secrets Operator:从外部 Secret 管理系统同步到 K8s
yaml
# Sealed Secret 示例
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: db-secret
spec:
  encryptedData:
    DB_PASSWORD: AgBy3...(加密后的数据)
    DB_USER: AgCx7...

三、实战案例

3.1 完整的多环境配置

yaml
# configmap-dev.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_URL: "postgres://dev-db:5432/myapp_dev"
  LOG_LEVEL: "debug"
  CACHE_TTL: "60"
---
# configmap-prod.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_URL: "postgres://prod-db:5432/myapp_prod"
  LOG_LEVEL: "warn"
  CACHE_TTL: "600"
yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: app
          image: myapp:1.0
          env:
            - name: DATABASE_URL
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: DATABASE_URL
            - name: LOG_LEVEL
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: LOG_LEVEL
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: DB_PASSWORD
bash
# 开发环境
kubectl apply -f configmap-dev.yaml -n development
kubectl apply -f deployment.yaml -n development

# 生产环境
kubectl apply -f configmap-prod.yaml -n production
kubectl apply -f deployment.yaml -n production

四、本章小结

ConfigMap 存储非敏感配置,Secret 存储敏感数据。

三种注入方式:环境变量(简单但不热更新)、Volume 挂载(支持热更新)、命令行参数。

Secret 的 Base64 不是加密,需要配合 etcd 加密和 RBAC 控制。

外部 Secret 管理工具(Sealed Secrets、Vault)可以安全地将 Secret 存储到 Git。

配置与镜像解耦是容器化最佳实践,同一个镜像可以在不同环境运行。


五、思考与练习

思考题

为什么环境变量方式不支持热更新?Volume 挂载方式为什么支持?

如果 ConfigMap 不存在,Pod 能启动吗?如果 Secret 不存在呢?

如何实现 ConfigMap 更新后自动重启 Pod?有哪些方案?

Sealed Secrets 的加密原理是什么?为什么可以安全存储到 Git?

在多团队共享集群时,如何防止团队 A 读取团队 B 的 Secret?

练习题

创建 ConfigMap 和 Secret,分别通过环境变量和 Volume 挂载注入到 Pod。

更新 ConfigMap,观察 Volume 挂载方式的自动更新行为。

使用 Sealed Secrets 加密 Secret 并存储到 Git。

配置 RBAC 限制某个 ServiceAccount 只能访问特定的 Secret。

7/8配置与
0%