1. 概述

在 Kubernetes 中,ConfigMapSecret 是两种用于将应用配置和敏感信息从代码中解耦的核心资源类型。它们各自有不同的用途和行为特点。

本文将重点介绍 ConfigMap 与 Secret 在使用场景、创建方式、数据编码、挂载方式等方面的区别,并通过示例代码展示其典型用法,帮助你更好地理解两者之间的差异和适用场景。


2. 创建与数据编码

ConfigMap 的创建

ConfigMap 用于存储非敏感的配置信息,支持多种格式的键值对。以下是一个典型的 ConfigMap 定义:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-configmap
data:
  string-value: "Hello, world!"
  number-value: "42"
  boolean-value: "true"
  multiline-value: |
    This is a multiline value
    that spans multiple lines
  list-value: |
    - item1
    - item2
    - item3
  object-value: |
    key1: value1
    key2: value2
  json-value: |-
    {
      "key": "value",
      "array": [1, 2, 3],
      "nested": {
        "innerKey": "innerValue"
      }
    }
  yaml-value: |-
    key: value
    array:
      - 1
      - 2
      - 3
    nested:
      innerKey: innerValue

✅ 所有值都以明文形式存储在 data 字段下。

创建该 ConfigMap:

kubectl apply -f my-config.yaml

查看某个键值:

kubectl get configmap my-configmap -o jsonpath='{.data.string-value}'

输出:

Hello, world!

Secret 的创建

Secret 用于存储敏感信息,例如密码、密钥等。它支持 Base64 编码的 data 字段和明文的 stringData 字段。

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  string-value: SGVsbG8sIHdvcmxkIQ==
  number-value: NDI=
  boolean-value: dHJ1ZQ==
  multiline-value: |
    VGhpcyBpcyBhIG1pbmxpbmUgdmFsdWUgZXZlcnkgdGhhdCBzcGFuIG11bHRpcGxlIGxpbmVzCg==
  json-value: eyAiY29tcGxleCI6ICIxMjM0NSIsICJzdHJpbmciOiAiSGVsbG8sIHdvcmxkISIsICJuZXN0ZWQiOiB7ICJpbnN0YW5jZSI6IDEsICJzdHJpbmciOiAxLCAibmVzdGVkIjogeyAiaW5uZXJLZXkiOiAiSW5uZXJWYWx1ZSJ9fX0=
  binary-value: YmFzZTY0IHN0cmluZwo=
stringData:
  list-value: |
    item1
    item2
    item3
  object-value: |
    key1: value1
    key2: value2
    key3: value3
  yaml-value: |
    key: value
    string: Hello, world!
    nested:
      innerKey: innerValue

⚠️ 注意:stringData 是明文,Kubernetes 会自动将其转换为 Base64 并存入 data 字段。

创建 Secret:

kubectl apply -f my-secret.yaml

获取并解码 Secret:

kubectl get secret my-secret -o jsonpath='{.data.string-value}' | base64 -d

输出:

Hello, world!

3. 作为环境变量注入容器

ConfigMap 和 Secret 都可以作为环境变量注入容器中。

以下是一个 Pod 定义文件,将 Secret 和 ConfigMap 的值分别注入为环境变量:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
    - name: ubuntu-container
      image: ubuntu
      command: ["sleep", "infinity"]
      env:
        - name: SECRET_VALUE
          valueFrom:
            secretKeyRef:
              name: my-secret
              key: string-value
        - name: CONFIG_VALUE
          valueFrom:
            configMapKeyRef:
              name: my-configmap
              key: number-value

创建 Pod:

kubectl apply -f pod.yaml

查看环境变量:

kubectl exec my-pod -- env | grep -i VALUE

输出:

CONFIG_VALUE=42
SECRET_VALUE=Hello, world!

✅ Secret 的值即使是以 Base64 编码存储,注入容器时也会自动解码。


4. 内置类型与用途

4.1 Opaque Secret

Opaque Secret 是最通用的 Secret 类型,适合存储任意敏感信息。

例如,存储 MySQL 的用户名和密码:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  username: bXktcHJvdG9jb2xvcmVk
  password: bXktcGFzc3dvcmQ=
  root-password: bXktcm9vdC1wYXNzd29yZA==

然后在 Pod 中引用这些值:

env:
  - name: MYSQL_USER
    valueFrom:
      secretKeyRef:
        name: mysql-secret
        key: username
  - name: MYSQL_PASSWORD
    valueFrom:
      secretKeyRef:
        name: mysql-secret
        key: password
  - name: MYSQL_ROOT_PASSWORD
    valueFrom:
      secretKeyRef:
        name: mysql-secret
        key: root-password

创建资源并验证:

kubectl apply -f mysql-secret.yaml -f mysql-pod.yaml
kubectl exec -it mysql-pod -- mysql -uroot -pmy-root-password -e "SELECT VERSION();"

输出:

+-----------+
| VERSION() |
+-----------+
| 8.0.33    |
+-----------+

✅ 成功使用 Secret 注入数据库凭证。

4.2 TLS Secret

TLS Secret 用于存储 TLS 证书和私钥。可以使用 kubectl create secret tls 命令创建:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt
kubectl create secret tls my-tls-secret --cert=tls.crt --key=tls.key

在 Pod 中挂载该 Secret:

volumes:
  - name: tls-volume
    secret:
      secretName: my-tls-secret
volumeMounts:
  - name: tls-volume
    mountPath: /etc/tls
    readOnly: true

验证挂载结果:

kubectl exec tls-pod -- ls /etc/tls/

输出:

tls.crt
tls.key

✅ 成功挂载 TLS Secret。


5. 自动挂载

只有特定类型的 Secret(如 service-account-token)支持自动挂载功能。

定义一个 ServiceAccount 并启用自动挂载:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account

---
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-pod
spec:
  serviceAccountName: my-service-account
  containers:
    - name: ubuntu-container
      image: ubuntu
      command: ["sleep", "infinity"]
  automountServiceAccountToken: true

创建资源:

kubectl apply -f sa-ubuntu.yaml

验证自动挂载的 Token:

kubectl exec ubuntu-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token

✅ Token 成功被自动挂载。


6. 功能对比总结

对比维度 ConfigMap Secret
数据分类 存储非敏感信息 存储敏感信息
数据编码 明文 Base64 编码
类型与用途 无特定类型,用于配置 支持多种类型(如 Opaque、TLS)
API 支持 支持通用操作 支持更丰富的类型操作
挂载方式 只能显式挂载 支持 service-account-token 自动挂载

7. 总结

本文通过多个示例详细对比了 Kubernetes 中 ConfigMap 与 Secret 的差异,包括:

  • 创建方式与数据编码方式的不同
  • 环境变量注入时的行为差异
  • 挂载方式及自动挂载的支持情况
  • 各自的内置类型与典型使用场景

✅ 总结:ConfigMap 更适合用于存储非敏感的配置数据,而 Secret 更适合用于处理敏感信息,尤其在安全性要求较高的场景中具有不可替代的优势。在实际项目中,应根据需求选择合适的资源类型。


原始标题:Understanding ConfigMaps and Secrets in Kubernetes