ConfigMap 与 Secret

1. ConfigMap

1.1. 概述

ConfigMap 是 Kubernetes 中用于存储非机密配置数据的 API 对象,允许你将配置与应用程序代码分离,从而实现更灵活的应用程序部署。

ConfigMap 主要用于:

  • 存储环境变量。
  • 存储命令行参数。
  • 存储配置文件。
  • 存储任何需要与容器镜像分离的配置数据。

注意事项:

  • ConfigMap 必须在 Pod 创建之前存在。
  • ConfigMap 位于特定命名空间中,Pod 只能引用相同命名空间中的 ConfigMap。
  • 静态 Pod 不能引用 ConfigMap。
  • ConfigMap 文件大小限制为 1MB(ETCD 数据库限制)。

1.2. 创建 ConfigMap 示例

1.2.1. 使用 yaml 文件创建

配置数据在 data 字段下,key:value 形式保存,value 值需要是字符串(非字符串需加上引号转化为字符串)。

# cm-test.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: test1-config
  namespace: default
data:
  xxx: "111"
  yyy: "222"
  data.1: hello
  data.2: world
  config: |
    property.1=value-1
    property.2=value-2
    property.3=value-3
YAML

创建:

kubectl apply -f cm-test.yaml
Bash

查看:

$ kubectl get cm test1-config 
NAME           DATA   AGE
test1-config   5      75s

# 查看 ConfigMap 的详细数据
$ kubectl describe cm test1-config 
Name:         test1-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
config:
----
property.1=value-1
property.2=value-2
property.3=value-3


data.1:
----
hello

data.2:
----
world

xxx:
----
111

yyy:
----
222


BinaryData
====

Events:  <none>
Bash

在上述 yaml 文件中可以看到 config 字段后面有一个 | 符号,| 符号是一个 YAML 多行字符串标识符,它的作用是指示后面的内容是一个 保留换行符的多行字符串。常用标识符示例如下:

  • | :表示后面的值是一个多行字符串,并且保留换行符。
data:
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5   
    
 
# 实际内容,会被原样存储
enemy.types=aliens,monsters
player.maximum-lives=5
Bash
  • >:在 yaml 中表示折叠换行,内容最末尾的换行会保留,但文中部分只有空白行才会被识别为换行,原来的换行符都会被转换成空格。
description: >
  This is a long description
  that will be folded into
  a single line.
  
  
# 实际存储为
This is a long description that will be folded into a single line.
Bash
  • 上述两个符号搭配 + 或 – 号:+ 表示保留文字块末尾的换行,- 表示删除字符串末尾的换行。
value: |
  hello
  world
  
# {"value": "hello\nworld\n"}


value: |-
  hello
  world  
  
# {"value": "hello\nworld"}


value: |+
  hello
  world
  
   
# {"value": "hello\nworld\n\n"} (有多少个回车就有多少个\n)
Bash

综合示例:

# test1-config.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: test1-config
  namespace: default
data:
  config1: |
    property.1=value-1
    property.2=value-2
    property.3=value-3
    
    
  config2: |-
    hello
    world
    
    
  config3: |+
    hello
    world
    
    
  config4: >
    第一行
    
    第二行
    第三行


  config5: >-
    第一行
    
    第二行
    第三行
    
   
  config6: >+
    第一行
    
    第二行
    第三行
    
    
YAML

部署后查看:

kubectl get cm test1-config -o json

{
    "apiVersion": "v1",
    "data": {
        "config1": "property.1=value-1\nproperty.2=value-2\nproperty.3=value-3\n",
        "config2": "hello\nworld",
        "config3": "hello\nworld\n\n\n",
        "config4": "第一行\n第二行 第三行\n",
        "config5": "第一行\n第二行 第三行",
        "config6": "第一行\n第二行 第三行\n\n\n"
    },
    "kind": "ConfigMap",
    "metadata": {
        "annotations": {
            "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"data\":{\"config1\":\"property.1=value-1\\nproperty.2=value-2\\nproperty.3=value-3\\n\",\"config2\":\"hello\\nworld\",\"config3\":\"hello\\nworld\\n\\n\\n\",\"config4\":\"第一行\\n第二行 第三行\\n\",\"config5\":\"第一行\\n第二行 第三行\",\"config6\":\"第一行\\n第二行 第三行\\n\\n\\n\"},\"kind\":\"ConfigMap\",\"metadata\":{\"annotations\":{},\"name\":\"test1-config\",\"namespace\":\"default\"}}\n"
        },
        "creationTimestamp": "2025-08-14T02:37:50Z",
        "name": "test1-config",
        "namespace": "default",
        "resourceVersion": "1730632",
        "uid": "e7a71835-78ff-412f-a0a3-bd94db8883f8"
    }
}
Bash

1.2.2. 命令行创建

在 Kubernetes 中,可以使用 kubectl create configmap 命令通过多种方式创建 ConfigMap。

  • –from-literal:直接指定键值对。
kubectl create configmap db-config \
  --from-literal=DB_HOST=mysql \
  --from-literal=DB_PORT=3306
  
# 查看
kubectl get configmap db-config -o yaml
apiVersion: v1
data:
  DB_HOST: mysql
  DB_PORT: "3306"
kind: ConfigMap
metadata:
  creationTimestamp: "2025-08-14T03:42:24Z"
  name: db-config
  namespace: default
  resourceVersion: "1732245"
  uid: 7bbccdea-86b9-4ed9-a629-b0e71dc6aad3
Bash
  • –from-file:基于指定的文件或目录创建,文件名为 key,文件内容为 value,也可以单独指定 key。
    • –from-file 可以多次使用。
    • –from-file 指定目录时,会将目录下所有文件以 key:value 形式导入到 ConfigMap 中。
    • 指定键名:kubectl create configmap my-config --from-file=my-key=path/to/file
  • –from-env-file:表示基于指定的 env 文件创建 ConfigMap。
    • env 文件为一组环境变量的配置数据,文件每行都为 key=value 的格式,等号两边不能有空格。
    • 创建 ConfigMap 时:
      • 忽略以 # 开头的注释行。
      • 忽略空行。
      • 对文本的内容不做转义处理。
    • 示例如下:

env.file:

DB_HOST=mysql


# 注释
DB_PORT=3306
DB_NAME=mydb
TeX

创建:

kubectl create configmap db-env-config --from-env-file=env.file
Bash

查看:

kubectl get cm db-env-config -o yaml
apiVersion: v1
data:
  DB_HOST: mysql
  DB_NAME: mydb
  DB_PORT: "3306"
kind: ConfigMap
metadata:
  creationTimestamp: "2025-08-14T04:04:21Z"
  name: db-env-config
  namespace: default
  resourceVersion: "1735188"
  uid: 5c84c915-c8dd-4fbd-baa0-a0970ae3259d
Bash

1.2.3. 创建不可修改的 ConfigMap

从 Kubernetes v1.19 版本开始,ConfigMap 新增了 immutable 字段,用于设置配置数据不可修改,即 ConfigMap 资源对象一旦创建成功后就不可修改,如需修改,则只能通过先删除再重建来实现。

这样做的好处包括:

  • 防止意外更新 ConfigMap 对应用带来的异常影响。
  • 减少 API Server 监控 ConfigMap 的变化所带来的性能损耗。
  • immutable 字段的配置示例如下:
apiVersion: v1 
kind: ConfigMap 
metadata:
...
data:
...
immutable: true
YAML

1.3. 在 Pod 中使用 ConfigMap

容器应用通过以下几种方式使用 ConfigMap:

  • 将 ConfigMap 中的内容设置为容器内的环境变量。
  • 同样将 ConfigMap 中的内容设置为容器内的环境变量,并作为命令行参数使用。
  • 通过 Volume 将 ConfigMap 中的内容挂载为容器中的文件或目录。

1.3.1. 作为环境变量

单个环境变量注入:

apiVersion: v1
kind: Pod
metadata:
  name: env-pod
spec:
  containers:
  - name: my-container
    image: busybox
    command: ["/bin/sh", "-c", "tail -f /dev/null"]
    env:
    - name: SPECIAL_LEVEL  # 容器中的环境变量名
      valueFrom:
        configMapKeyRef:
          name: special-config  # ConfigMap 名称
          key: SPECIAL_LEVEL   # ConfigMap 中的键
          optional: false      # 可选,如果为 true 则 ConfigMap 或键不存在时不会报错
YAML

全部键值作为环境变量注入:

apiVersion: v1
kind: Pod
metadata:
  name: envfrom-pod
spec:
  containers:
  - name: my-container
    image: busybox
    command: ["/bin/sh", "-c", "tail -f /dev/null"]
    envFrom:
    - configMapRef:
        name: special-config  # 将整个 ConfigMap 的所有键值作为环境变量
        optional: false
YAML

1.3.2. 作为命令行参数

apiVersion: v1
kind: Pod
metadata:
  name: args-pod
spec:
  containers:
  - name: my-container
    image: busybox
    command: ["/bin/sh", "-c", "echo $(SPECIAL_LEVEL) && tail -f /dev/null"]   # 作为命令行参数使用
    env:
    - name: SPECIAL_LEVEL
      valueFrom:
        configMapKeyRef:
          name: special-config
          key: SPECIAL_LEVEL
YAML

1.3.3. 作为卷挂载

完整挂载整个 ConfigMap:

apiVersion: v1
kind: Pod
metadata:
  name: volume-pod
spec:
  containers:
  - name: my-container
    image: nginx
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config  # ConfigMap 内容将挂载到此目录
  volumes:
  - name: config-volume
    configMap:
      name: special-config    # 要挂载的 ConfigMap 名称
      optional: false
YAML

挂载特定键:

apiVersion: v1
kind: Pod
metadata:
  name: specific-key-pod
spec:
  containers:
  - name: my-container
    image: nginx
    volumeMounts:
    - name: config-volume
      mountPath: /etc/special-key  # 单个键将挂载到此路径
      subPath: special-key        # 指定要挂载的子路径
  volumes:
  - name: config-volume
    configMap:
      name: special-config
      items:                    # 指定要包含的键
      - key: SPECIAL_KEY        # ConfigMap 中的键名
        path: special-key       # 挂载后的文件名
YAML

设置文件权限:

apiVersion: v1
kind: Pod
metadata:
  name: permission-pod
spec:
  containers:
  - name: my-container
    image: nginx
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: special-config
      defaultMode: 0600        # 设置文件权限为 600
      items:
      - key: config-file
        path: my-config
        mode: 0644            # 设置特定文件的权限为 644
YAML

1.4. ConfigMap 热更新

在 Kubernetes 中,当你对 ConfigMap 进行更新或删除重建时,如果 ConfigMap 被挂载为 Volume 到了 Pod 内,那么这些更新是可以被反映到 Pod 文件系统上的文件内容中的,这也就是我们所说的”热更新”。

  • Kubernetes 会定期检查并更新挂载的内容。
  • 更新周期由 kubelet 的 --sync-frequency 参数控制(默认 1 分钟)。

测试示例如下:

# configmap-update.yaml
apiVersion: v1
data:
  mysql.conf: |
    host=127.0.0.1
    port=3306
  redis.conf: |
    host=127.0.0.1
    port=6379
kind: ConfigMap
metadata:
  name: cm-demo
  namespace: default

---
apiVersion: v1
kind: Pod
metadata:
  name: testcm5-pod
spec:
  volumes:
  - name: my-volume
    configMap:
      name: cm-demo
  containers:
  - name: testcm5
    image: busybox
    command: [ "/bin/sh","-c","sleep 10000" ]
    volumeMounts:
    - name: my-volume
      mountPath: /etc/config
YAML

创建:

kubectl apply -f configmap-update.yaml
Bash

查看:

kubectl exec -it testcm5-pod -- sh

/ # cat /etc/config/
..2025_08_14_08_11_00.3823437720/  mysql.conf
..data/                            redis.conf
/ # cat /etc/config/mysql.conf 
host=127.0.0.1
port=3306
Bash

更新 ConfigMap:

 kubectl edit cm cm-demo  # 将配置改动一下
 
apiVersion: v1
data:
  mysql.conf: |
    host=127.0.0.1
    port=99999
Bash

查看验证:

/ # cat /etc/config/mysql.conf 
host=127.0.0.1
port=99999
Bash

注意:这里的热更新只是配置文件更新了,这并不意味着运行在 Pod 中的应用会自动知道这些更改。事实上,很多的应用在启动时只会读取一次配置文件,而在运行时不会再对配置文件做任何检查。这就意味着,即使配置文件的内容被更新了,这些应用也不会感知到这种变化,必须重启应用才能加载新的配置。

1.5. 实现应用自动加载更新的配置

我们可以通过 Reloader 来实现应用的配置文件热更新,Reloader 是一个 Kubernetes 控制器(Controller),它会监视集群中的 ConfigMap 和 Secret 资源。当这些资源被修改时,Reloader 会自动触发引用它们的 DeploymentStatefulSet 或 DaemonSet 进行滚动更新(Rolling Update),使 Pod 加载新的配置。

项目下载地址:

wget https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
Bash

部署 Reloader 后,只需要在需要在 DeploymentStatefulSet 或 DaemonSet 等控制器的注解部分加上 reloader.stakater.com/auto: "true" ,或指定具体的 ConfigMap/Secret 则可以实现自动加载新配置。

示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  annotations:
    # 当名为 "my-config" 的 ConfigMap 更新时重启 Pod
    reloader.stakater.com/auto: "true"
    # 或指定具体 ConfigMap/Secret
    reloader.stakater.com/search: "my-config"
Bash

2. Secret

2.1. 概述

Secret 是 Kubernetes 中用于存储和管理敏感信息的对象,如密码、OAuth 令牌、SSH 密钥等。与 ConfigMap 类似,但专门设计用于敏感数据。

Secret 与 ConfigMap 的主要区别:

特性SecretConfigMap
数据类型敏感信息非敏感配置
存储方式默认 base64 编码明文存储
安全特性可加密存储 (etcd)无额外加密
典型用途密码、密钥、令牌应用配置、环境变量

Secret 常用类型,例如:

  • Opaque (默认) :base64 编码格式的 Secret,通用类型,用于任意用户定义的敏感数据。
  • kubernetes.io/tls:存放证书以及私钥。
  • kubernetes.io/dockerconfigjson :用来存储私有 docker registry 的认证信息,类型标识为 docker-registry。

2.2. Opaque 类型

特点:

  • 可以存储任意键值对数据,适用于非结构化敏感信息(如密码、SSH 密钥、API 密钥等)。
  • 可以自定义键名。
  • 不会对内容做格式校验(纯存储)。

Secret 资源提供了 2 个可用字段:data 和 stringData。

  • data 字段的数据必须是 base64 编码的任意数据。
  • stringData 字段允许 Secret 使用未编码的字符串。

2.2.1. data 字段的使用

首先将明文转换成 base64 编码:

echo -n 'pingk' | base64   # 结果是 cGluZ2s=
echo -n '123456' | base64 # 结果是 MTIzNDU2
Bash

创建一个 Secret:

# opaque-data-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: opaque-data-secret
data:
  username: cGluZ2s=
  password: MTIzNDU2
YAML

部署后查看:

$ kubectl get secrets opaque-data-secret 
NAME                 TYPE     DATA   AGE
opaque-data-secret   Opaque   2      45s


$ kubectl describe secrets opaque-data-secret 
Name:         opaque-data-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  6 bytes
username:  5 bytes


$ kubectl get secrets opaque-data-secret -o yaml 
apiVersion: v1
data:
  password: MTIzNDU2
  username: cGluZ2s=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"password":"MTIzNDU2","username":"cGluZ2s="},"kind":"Secret","metadata":{"annotations":{},"name":"opaque-data-secret","namespace":"default"}}
  creationTimestamp: "2025-08-14T12:07:20Z"
  name: opaque-data-secret
  namespace: default
  resourceVersion: "1799963"
  uid: cc05f59c-5d55-4203-bdbb-9a7e907fa656
type: Opaque
Bash

2.2.2. stringData 字段的使用

某些场景下想将非 base64 编码的字符串放入 Secret 中,就需要用到 stringData 字段。

创建一个 Secret:

# opaque-stringData-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: opaque-stringdata-secret
type: Opaque
stringData:
  username: pingk
  password: "123456"
 
 
  
# 多行文本形式同 configmap
stringData:
  config.yaml: |
    username: pingk
    password: 123456
YAML

部署后查看:

# 可以看到自动编码为了 base64
kubectl get secrets opaque-stringdata-secret -o yaml
apiVersion: v1
data:
  password: MTIzNDU2
  username: cGluZ2s=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"opaque-stringdata-secret","namespace":"default"},"stringData":{"password":"123456","username":"pingk"},"type":"Opaque"}
  creationTimestamp: "2025-08-14T12:22:44Z"
  name: opaque-stringdata-secret
  namespace: default
  resourceVersion: "1802033"
  uid: 4766141e-53d1-43c0-a75a-db8759542fb2
type: Opaque
Bash

2.2.3. 命令行创建方式

直接指定键值对:

kubectl create secret generic my-secret \
  --from-literal=username=admin \
  --from-literal=password='123456'
  
# generic:表示通用类型
# 会自动编码 base64
Bash

从文件创建:

kubectl create secret generic ssh-key-secret \
  --from-file=ssh-privatekey=~/.ssh/id_rsa \
  --from-file=ssh-publickey=~/.ssh/id_rsa.pub
Bash

2.2.4. 引用 Secret

创建好 Secret 对象后,有两种方式来使用它:

  • 以环境变量的形式。
  • 以 Volume 的形式挂载。

挂载卷的方式:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - image: busybox
        name: busybox
        command: ["/bin/sh","-c","sleep 10000"]
        # 挂载到容器内,挂载为一个目录
        volumeMounts:
        - name: xxx
          mountPath: /etc/my-secret
      # 卷声明    
      volumes:
      - name: xxx
        secret:
          secretName: test-secret
YAML

环境变量的方式:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - image: busybox
        name: busybox
        args: ["sleep", "36000"]
        env:
        - name: USER
          valueFrom:
            secretKeyRef:
              name: test-secret
              key: username
              optional: false  # 可选,默认就是false
        - name: PASSWORD
          valueFrom:
            secretKeyRef:
              name: test-secret
              key: password
        - name: CONFIG
          valueFrom:
            secretKeyRef:
              name: demo-secret
              key: config.yaml
YAML

2.2. tls 类型

特点:

  • 专门用于存储 TLS 证书和私钥
  • 必须包含两个固定字段
    • tls.crt:证书文件(PEM 编码)
    • tls.key:私钥文件(PEM 编码)
  • Kubernetes 会验证证书和私钥的格式

2.2.1. 创建方式

yaml 文件创建:

apiVersion: v1
kind: Secret
metadata:
  name: tls-secret
type: kubernetes.io/tls
data:
  tls.crt: <base64-encoded-cert>  # 证书内容(base64 编码)
  tls.key: <base64-encoded-key>   # 私钥内容(base64 编码)
YAML

命令行创建:

kubectl create secret tls tls-secret \
  --cert=path/to/cert.pem \
  --key=path/to/key.pem
Bash

2.2.2. 使用示例

在 Ingress 中启用 HTTPS:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  tls:
  - hosts:
    - example.com
    secretName: tls-secret  # 引用 TLS Secret
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80
YAML

在 Service 中启用 TLS:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
  - name: https
    port: 443
    targetPort: 8443
  selector:
    app: my-app
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        image: my-app:latest
        ports:
        - containerPort: 8443
        volumeMounts:
        - name: tls-secret
          mountPath: "/etc/tls"
          readOnly: true
      volumes:
      - name: tls-secret
        secret:
          secretName: tls-secret  # 挂载 TLS Secret
YAML

Pod 直接挂载 TLS 文件:

spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: tls
      mountPath: "/etc/nginx/ssl"
  volumes:
  - name: tls
    secret:
      secretName: tls-secret  # 挂载到 Pod
      items:
      - key: tls.crt
        path: server.crt  # 证书重命名为 server.crt
      - key: tls.key
        path: server.key  # 私钥重命名为 server.key
YAML

2.3. dockerconfigjson 类型

dockerconfigjson 是 Kubernetes 中一种特殊类型的 Secret,专门用于存储 Docker 镜像仓库的认证信息。它允许 Kubernetes 在拉取私有镜像时自动提供认证凭据。

2.3.1. 创建方式

yaml 文件创建:

# 创建完整的 config.json
cat > config.json <<EOF
{
  "auths": {
    "registry.example.com": {
      "username": "myuser",
      "password": "S3cr3tP@ss",
      "auth": "dXNlcm5hbWU6cGFzc3dvcmQ=",
      "email": "myuser@example.com"
    }
  }
}
EOF

# 转换为 base64
cat config.json | base64 -w 0


# 创建 Secret YAML
apiVersion: v1
kind: Secret
metadata:
  name: my-registry-secret
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <base64-encoded-config.json>
Bash

命令行创建:

kubectl create secret docker-registry <secret-name> \
  --docker-server=<registry-server> \
  --docker-username=<username> \
  --docker-password=<password> \
  --docker-email=<email>
Bash

2.3.2. 使用示例

在创建 Pod 拉取镜像时使用:

apiVersion: v1
kind: Pod
metadata:
  name: private-pod
spec:
  containers:
  - name: private-app
    image: registry.example.com/private/image:latest
  imagePullSecrets:
  - name: my-registry-secret    # 指定 dockerconfigjson Secret
YAML

为 ServiceAccount 添加 pull secret:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
imagePullSecrets:
- name: my-registry-secret

# ServiceAccount 添加 imagePullSecrets 后,所有使用该 ServiceAccount 的 Pod 都可以直接引用私有镜像仓库,而无需在每个 Pod 中单独指定 imagePullSecrets
YAML

2.4. Secret 热更新

Secret 的热更新机制与 ConfigMap 相同。

2.5. Secret 标记不可变

apiVersion: v1
kind: Secret
metadata:
 ...
data:
 ...
immutable: true  # 标记为不可变
YAML

2.6. 总结

同样 Secret 文件大小限制为 1MB(ETCD 的要求);Secret 虽然采用 Base64 编码,但是我们还是可以很方便解码获取到原始信息,所以对于非常重要的数据还是需要慎重考虑,可以考虑使用 Vault 来进行加密管理。

上一篇
下一篇