11. configMap 与 Secret

ConfigMap

在 Kubernetes(简称 K8s)里,我们经常需要给应用设置一些“可变配置”,比如数据库地址、服务端口、API 密钥之类的。为了方便管理这些配置信息,K8s 提供了一个叫 ConfigMap 的资源对象。

ConfigMap 的作用就是——把这些非机密的数据(比如配置参数)保存成“键值对”的形式,然后让容器在运行时可以读取到它们。
这些配置信息可以通过几种方式使用:

  • 当作 环境变量 提供给应用;
  • 当作 命令行参数 传给程序;
  • 或者直接 挂载成配置文件 存在容器里。

这样一来,我们就能把“程序逻辑”和“配置内容”分开(也就是“解耦”)。想改配置的时候,不用重新改代码、重新打镜像,只要更新 ConfigMap 就行,非常方便。

不过要注意,ConfigMap 不会对数据加密或保密
如果你要保存密码、Token 等敏感信息,那就应该用 Secret 资源或者其他安全工具,而不是 ConfigMap。

举个例子:
有个应用需要连接 Redis 数据库。我们当然不想把 Redis 地址写死在代码里,因为如果 Redis 换了位置,每次都得改代码、重新打包镜像。
这时候,用 ConfigMap 就很合适。我们可以:

  • 把 Redis 地址单独存在 ConfigMap 里;
  • 或者直接把整个 Redis 的配置文件放进去;
    然后让容器在启动时去读取。

从结构上看,ConfigMap 也是一种 K8s 资源对象,但它不像 Deployment、Pod 那样有个 spec 字段。
它主要用 databinaryData 这两个字段来保存内容:

  • data 用来放普通的文本(UTF-8 格式);
  • binaryData 用来放二进制内容(比如图片、压缩包等),会以 Base64 形式存储。

每个字段下面的“键名”(key)只能用字母、数字、-_.,并且同一个键不能同时出现在 databinaryData 里。

另外,从 Kubernetes v1.19 版本开始,还可以给 ConfigMap 加上一个 immutable(不可变)字段,这样创建之后就不能再被修改,防止误操作。

创建

yaml 创建

ConfigMap 资源对象使用 key-value 形式的键值对来配置数据,这些数据可以在 Pod 里面使用,如下所示的资源清单:

# cm-demo.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-demo
  namespace: default
data:
  data.1: hello
  data.2: world
  config: |
    property.1=value-1
    property.2=value-2
    property.3=value-3

---
# pod-cm-test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: cm-demo-pod
  namespace: default
spec:
  containers:
  - name: demo
    image: busybox
    command: ["/bin/sh", "-c", "env; cat /etc/config/config; sleep 3600"]
    envFrom:
    - configMapRef:
        name: cm-demo
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: cm-demo

验证:

# 创建
ubuntu@ubuntu:~/example/config_map$ kubectl apply -f ./cm-demo.yaml 
configmap/cm-demo created
pod/cm-demo-pod created
# 查看ConfigMap 详情
ubuntu@ubuntu:~/example/config_map$ kubectl get configmap cm-demo -n default -o yaml
apiVersion: v1
data:
  config: |
    property.1=value-1
    property.2=value-2
    property.3=value-3
  data.1: hello
  data.2: world
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"config":"property.1=value-1\nproperty.2=value-2\nproperty.3=value-3\n","data.1":"hello","data.2":"world"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"cm-demo","namespace":"default"}}
  creationTimestamp: "2025-11-12T06:33:47Z"
  name: cm-demo
  namespace: default
  resourceVersion: "408495"
  uid: 589410b7-60a3-427d-a2cb-da4153a77c7a
# 查看 Pod 状态
ubuntu@ubuntu:~/example/config_map$ kubectl  get pod  cm-demo-pod -n default
NAME          READY   STATUS    RESTARTS   AGE
cm-demo-pod   1/1     Running   0          27s

# 查看日志
ubuntu@ubuntu:~/example/config_map$ kubectl logs --tail 2000 cm-demo-pod -n default
data.2=world
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=cm-demo-pod
SHLVL=1
HOME=/root
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
config=property.1=value-1
property.2=value-2
property.3=value-3

KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
data.1=hello
property.1=value-1
property.2=value-2
property.3=value-3

# 或者进入容器查看
ubuntu@ubuntu:~/example/config_map$  kubectl exec -it cm-demo-pod -n default -- sh
/ # cd /etc/config/
/etc/config # ls
config  data.1  data.2
/etc/config # cat /etc/config/config
property.1=value-1
property.2=value-2
property.3=value-3
/etc/config # 

ConfigMap 中每个 key 可以同时用于:

  1. 环境变量(envFrom / env)
  2. 挂载卷文件(volumeMounts / volumes)

目录创建

ubuntu@ubuntu:~/example/config_map$ cd ./cm-test-dir/

ubuntu@ubuntu:~/example/config_map/cm-test-dir$ ls
mysql.conf  redis.conf

ubuntu@ubuntu:~/example/config_map/cm-test-dir$ cat ./redis.conf 
host=127.0.0.1
prot=6379

ubuntu@ubuntu:~/example/config_map/cm-test-dir$ cat ./mysql.conf 
host=127.0.0.1
prot=3306

# 使用 from-file 关键字来创建包含这个目录下面所以配置文件的 ConfigMap
ubuntu@ubuntu:~/example/config_map/cm-test-dir$ kubectl create configmap cm-demo1 --from-file=/home/ubuntu/example/config_map/cm-test-dir

# 查看配置
ubuntu@ubuntu:~/example/config_map/cm-test-dir$ kubectl describe configmap cm-demo1 
Name:         cm-demo1
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
mysql.conf:
----
host=127.0.0.1\r
prot=3306

redis.conf:
----
host=127.0.0.1\r
prot=6379


BinaryData
====

Events:  <none>
# 查看json格式的
ubuntu@ubuntu:~/example/config_map/cm-test-dir$ kubectl get configmap cm-demo1 -n default -o json
{
    "apiVersion": "v1",
    "data": {
        "mysql.conf": "host=127.0.0.1\r\nprot=3306",
        "redis.conf": "host=127.0.0.1\r\nprot=6379"
    },
    "kind": "ConfigMap",
    "metadata": {
        "creationTimestamp": "2025-11-12T07:03:23Z",
        "name": "cm-demo1",
        "namespace": "default",
        "resourceVersion": "414963",
        "uid": "128f4aec-bd35-4721-ac1c-40513d46e600"
    }
}
# 删除
# ubuntu@ubuntu:~/example/config_map$ kubectl delete cm cm-demo1 
# configmap "cm-demo1" deleted

文件创建

除了通过文件目录进行创建,我们也可以使用指定的文件进行创建 ConfigMap

ubuntu@ubuntu:~/example/config_map/cm-test-dir$ kubectl create configmap cm-demo2 --from-file=/home/ubuntu/example/config_map/cm-test-dir/redis.conf
# 查看配置 
ubuntu@ubuntu:~/example/config_map$  kubectl describe configmap cm-demo2
Name:         cm-demo2
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
redis.conf:
----
host=127.0.0.1\r
prot=6379


BinaryData
====

Events:  <none>
# 查看json格式的
ubuntu@ubuntu:~/example/config_map$  kubectl get configmap cm-demo2 -n default -o json
{
    "apiVersion": "v1",
    "data": {
        "redis.conf": "host=127.0.0.1\r\nprot=6379"
    },
    "kind": "ConfigMap",
    "metadata": {
        "creationTimestamp": "2025-11-12T10:33:28Z",
        "name": "cm-demo2",
        "namespace": "default",
        "resourceVersion": "458987",
        "uid": "071efc03-82ed-4a40-9f92-905b42c3040f"
    }
}

直接命令传递

# 创建
ubuntu@ubuntu:~/example/config_map$ kubectl create configmap cm-demo3 --from-literal=db.host=localhost --from-literal=db.port=3307
configmap/cm-demo3 created
# 查看
ubuntu@ubuntu:~/example/config_map$ kubectl get configmap cm-demo3 -n default -o json
{
    "apiVersion": "v1",
    "data": {
        "db.host": "localhost",
        "db.port": "3307"
    },
    "kind": "ConfigMap",
    "metadata": {
        "creationTimestamp": "2025-11-13T06:44:07Z",
        "name": "cm-demo3",
        "namespace": "default",
        "resourceVersion": "528382",
        "uid": "dad923f5-9500-469f-93c7-31a65376e379"
    }
}

使用

​ ConfigMap 创建成功了,那么我们应该怎么在 Pod 中来使用呢?我们可以使用四种方式来使用 ConfigMap 配置 Pod中的容器:

  • 在容器命令和参数内
  • 容器的环境变量
  • 在只读卷里面添加一个文件,让应用来读取
  • 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap

​ 这些不同的方法适用于不同的数据使用方式,对前三个方法,kubelet 会使用 ConfigMap 中的数据在 Pod 中启动容器。第四种方法需要编写代码才能读取 ConfigMap 数据。

环境变量

# testcm1-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: testcm1-pod
  namespace: default
spec:
  containers:
  - name: demo
    image: busybox
    command: ["/bin/sh", "-c", "env; sleep 3600"]

    env:
    - name: DB_HOST
      valueFrom:
        configMapKeyRef:
          name: cm-demo3
          key: db.host
    - name: DB_PORT
      valueFrom:
        configMapKeyRef:
          name: cm-demo3
          key: db.port

    envFrom:
      - configMapRef:
          name: cm-demo1

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl logs testcm1-pod
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=testcm1-pod
DB_PORT=3307
SHLVL=1
HOME=/root
mysql.conf=host=127.0.0.1
prot=3306
redis.conf=host=127.0.0.1
prot=6379
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
DB_HOST=localhost
ubuntu@ubuntu:~/example/config_map$ 

数据卷

# testcm3-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: testcm3-pod
  namespace: default
spec:
  containers:
  - name: demo
    image: busybox
    command: ["/bin/sh", "-c", "cat /etc/config/redis.conf; sleep 3600"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config

  volumes:
  - name: config-volume
    configMap:
      name: cm-demo2

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl logs testcm3-pod
host=127.0.0.1

当然我们也可以在 ConfigMap 值被映射的数据卷里去控制路径,如下 Pod 定义:

# testcm4-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: testcm4-pod
  namespace: default
spec:
  containers:
  - name: demo
    image: busybox
    command: ["/bin/sh", "-c", "cat /etc/config/path/to/mysql.conf; sleep 3600"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config

  volumes:
  - name: config-volume
    configMap:
      name: cm-demo1
      items: 
        - key: mysql.conf
          path: path/to/mysql.conf

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl logs testcm4-pod
host=127.0.0.1

​ 另外需要注意的是,当 ConfigMap 以数据卷的形式挂载进 Pod 的时,这时更新 ConfigMap(或删掉重建ConfigMap),Pod 内挂载的配置信息会热更新。kubelet 组件会在每次周期性同步时检查所挂载的 ConfigMap 是否为最新。这时可以增加一些监测配置文件变更的脚本,然后重加载对应服务就可以实现应用的热更新。以环境变量方式使用的ConfigMap 数据不会被自动更新,更新这些数据需要重新启动 Pod。

subPath

​ 上面我们介绍了可以将 ConfigMap 以数据卷的形式挂载到容器中去,但是如果原本容器目录下已经有一些文件或者数据,将数据挂载进去后便会覆盖容器目录下的数据,这个时候我们可以指定 volumeMounts.subPath 属性来指定卷内的子路径,而不是其根路径。

subPath 用于指定在挂载卷(volume)中的一个子路径,只将该子路径的内容挂载到容器内。

ConfigMap 定义(nginx-config.yaml

# nginx-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  nginx.conf: |
    user nginx;
    worker_processes 1;
    error_log /var/log/nginx/error.log warn;
    pid /var/run/nginx.pid;

    events {
        worker_connections 1024;
    }

    http {
        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for"';
        access_log /var/log/nginx/access.log main;

        sendfile on;
        keepalive_timeout 65;
        include /etc/nginx/conf.d/*.conf;
    }

错误示例(直接挂载整个目录)

# nginx-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: web
        image: nginx:1.7.9
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config
          mountPath: /etc/nginx
          subPath: nginx.conf
      volumes:
      - name: config
        configMap:
          name: nginx-config
          items:
          - key: nginx.conf
            path: nginx.conf

正确使用

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: web
        image: nginx:1.7.9
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config
          mountPath: /etc/nginx/nginx.conf   # ✅ 挂载单个文件
          subPath: nginx.conf                # ✅ 使用 subPath 避免目录覆盖
      volumes:
      - name: config
        configMap:
          name: nginx-config
          items:
          - key: nginx.conf
            path: nginx.conf

验证:

# 创建
ubuntu@ubuntu:~/example/config_map$ kubectl apply -f ./nginx-config.yaml 
configmap/nginx-config created
ubuntu@ubuntu:~/example/config_map$ kubectl apply -f ./nginx-test.yaml 
deployment.apps/nginx created
# 查看信息
ubuntu@ubuntu:~/example/config_map$ kubectl get pods -l app=nginx
NAME                     READY   STATUS             RESTARTS         AGE
nginx-646b4b5d75-2wqvv   0/1     CrashLoopBackOff   10 (2m42s ago)   29m
# 发现覆盖了
ubuntu@ubuntu:~/example/config_map$ kubectl logs -f nginx-646b4b5d75-2wqvv
2025/11/13 09:05:22 [emerg] 1#0: open() "/etc/nginx/mime.types" failed (2: No such file or directory) in /etc/nginx/nginx.conf:11
nginx: [emerg] open() "/etc/nginx/mime.types" failed (2: No such file or directory) in /etc/nginx/nginx.conf:11

# 修改yaml 加上 subPath: nginx.conf
ubuntu@ubuntu:~/example/config_map$ kubectl get pods -l app=nginx
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6447696fc6-q82hm   1/1     Running   0          4s
ubuntu@ubuntu:~/example/config_map$ 

​ 除此之外我们还可以使用带有扩展环境变量的 subPath,通过使用subPathExpr 字段可以基于 downward API 环境变量来构造 subPath 目录名,不过需要注意 subPath 和 subPathExpr 属性是互斥的。

使用 subPathExpr 动态创建目录保存日志

​ 在 Kubernetes 中,我们经常希望在宿主机上为每个 Pod 创建独立的日志目录,以便管理和查看。可以通过 subPathExpr 配合 Downward API 实现这一功能。

核心思路

  1. 使用 Downward API 获取 Pod 名称。
  2. 将宿主机目录(hostPath)挂载到容器内的日志目录,同时通过 subPathExpr 动态生成子目录。
  3. 容器日志最终保存在宿主机的子目录中。
# sub_path_expr.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod1
spec:
  containers:
    - name: container1
      image: busybox
      env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
      command:
        - sh
        - -c
        - while true; do echo 'Hello' >> /logs/hello.txt; sleep 1; done
      volumeMounts:
        - name: log
          mountPath: /logs
          subPathExpr: $(POD_NAME)  # 使用 Downward API 环境变量创建子目录
  restartPolicy: Never
  volumes:
    - name: log
      hostPath:
        path: /var/log

工作流程

  1. 创建 Pod 后,Kubernetes 通过 Downward API 获取 Pod 名称 pod1,并设置环境变量 POD_NAME=pod1
  2. subPathExpr: $(POD_NAME) 会在宿主机 /var/log 下创建一个名为 pod1 的目录。
  3. 容器 /logs 目录挂载到宿主机 /var/log/pod1
  4. 容器内写入 /logs/hello.txt 的日志文件最终保存在宿主机 /var/log/pod1/hello.txt

注意:subPathExpr 使用的是小括号 $(),而不是大括号 ${}

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl get pods -o wide
NAME                     READY   STATUS             RESTARTS      AGE     IP             NODE    NOMINATED NODE   READINESS GATES
pod1                     1/1     Running            0             79s     10.244.1.142   node2   <none>           <none>
# 去宿主机查看日志
ubuntu@ubuntu:~$ tail -f /var/log/pod1/hello.txt 
Hello

不可变更的 ConfigMap

Kubernetes 自 v1.21 起将 Immutable Secrets 和 ConfigMaps 作为稳定特性提供。
通过在 ConfigMap 或 Secret 中设置:

immutable: true

即可将其标记为不可变更(immutable)。

示例 immu-cm.yaml

# immu-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: immu-cm
data:
  mysql.conf: |-
    host=127.0.0.1
    port=3306
immutable: true

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl apply -f immu-cm.yaml
configmap/immu-cm created
# 修改文件后重新应用
ubuntu@ubuntu:~/example/config_map$ kubectl apply -f immu-cm.yaml
The ConfigMap "immu-cm" is invalid: data: Forbidden: field is immutable when `immutable` is set

Secret

Secret 的作用

Secret 是 Kubernetes 中用于存储敏感信息的资源对象。与 ConfigMap(明文配置) 不同,Secret 专门用于存储保密数据,例如:

  • 密码
  • OAuth Token
  • SSH Key
  • 私有仓库认证信息

相比把敏感数据直接写进 Pod、YAML 或镜像里,使用 Secret 更安全、更灵活。

Secret 类型(内置类型一览)

Secret 类型 说明
Opaque 默认类型,数据为 Base64 编码(可轻易 decode,安全性较弱)
kubernetes.io/dockercfg ~/.dockercfg 的序列化形式
kubernetes.io/dockerconfigjson 私有 Docker Registry 的认证信息 (~/.docker/config.json)
kubernetes.io/service-account-token ServiceAccount 自动挂载到 /run/secrets/...
kubernetes.io/ssh-auth SSH 身份认证密钥
kubernetes.io/basic-auth HTTP Basic Auth 凭据
bootstrap.kubernetes.io/token 用于集群引导的 token

自定义 Secret 类型

你也可以给 type 字段设置任意非空字符串,K8s 不限制命名规则。
如果 type 为空,则自动视为 Opaque。

安全性

默认情况下 Secret 是未加密存储在 etcd 中的。

这意味着:

  • 任何能访问 API Server 的用户可能查看或修改 Secret

  • 任何能访问 etcd 的用户可直接读取明文 Secret

  • 任何在命名空间具有 创建 Pod 权限 的用户,都能通过挂载 Pod 获取该命名空间所有 Secret

    因此,默认 Secret 并不绝对安全,需要额外措施增强安全性。

Opaque Secret

Secret 资源包含 2 个键值对: data 和 stringData,data 字段用来存储 base64 编码的任意数据,提供stringData 字段是为了方便,它允许 Secret 使用未编码的字符串。data 和 stringData 的键必须由字母、数字、-,_ 或 . 组成。

比如我们来创建一个用户名为 admin,密码为 admin321 的 Secret 对象

# secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: YWRtaW4zMjE=

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl apply -f secret-demo.yaml
secret/mysecret created
ubuntu@ubuntu:~/example/config_map$ kubectl get secret
NAME       TYPE     DATA   AGE
mysecret   Opaque   2      6s
ubuntu@ubuntu:~/example/config_map$ kubectl describe secret  mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  8 bytes
username:  5 bytes
# 查看明文
ubuntu@ubuntu:~/example/config_map$ kubectl get secret mysecret -o yaml
apiVersion: v1
data:
  password: YWRtaW4zMjE=
  username: YWRtaW4=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"password":"YWRtaW4zMjE=","username":"YWRtaW4="},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"type":"Opaque"}
  creationTimestamp: "2025-11-17T03:55:59Z"
  name: mysecret
  namespace: default
  resourceVersion: "661149"
  uid: b1a4fbf4-7914-42c6-ab7e-c56976f59423
type: Opaque
ubuntu@ubuntu:~/example/config_map$ 

对于某些场景,你可能希望使用 stringData 字段,这字段可以将一个非 base64 编码的字符串直接放入 Secret中, 当创建或更新该 Secret 时,此字段将被编码。

比如当我们部署应用时,使用 Secret 存储配置文件, 你希望在部署过程中,填入部分内容到该配置文件。例如,如果你的应用程序使用以下配置文件:

apiUrl: "https://my.api.com/api/v1"
username: "<user>"
password: "<password>"

那么我们就可以使用以下定义将其存储在 Secret 中:

# mysecret2.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret2
type: Opaque
stringData:
  config.yaml: |
    apiUrl: "https://my.api.com/api/v1"
    username: admin
    password: admin@123

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl apply -f mysecret2.yaml 
secret/mysecret2 created
ubuntu@ubuntu:~/example/config_map$ kubectl get secret mysecret2 -o yaml
apiVersion: v1
data:
  config.yaml: YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6IGFkbWluCnBhc3N3b3JkOiBhZG1pbkAxMjMK
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"mysecret2","namespace":"default"},"stringData":{"config.yaml":"apiUrl: \"https://my.api.com/api/v1\"\nusername: admin\npassword: admin@123\n"},"type":"Opaque"}
  creationTimestamp: "2025-11-17T06:08:31Z"
  name: mysecret2
  namespace: default
  resourceVersion: "689609"
  uid: 73e80db4-4238-4da2-8d44-1cb3f7c6f8fc
type: Opaque

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

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

环境变量

首先我们来测试下环境变量的方式,同样的,我们来使用一个简单的 busybox 镜像来测试下:

# secret1-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: secret1-pod
spec:
  containers:
    - name: secret1
    image: busybox
    command: ["/bin/sh", "-c", "env"]
    env:
      - name: USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl apply -f secret1-pod.yaml
pod/secret1-pod created
# 查看日志
ubuntu@ubuntu:~/example/config_map$ kubectl logs secret1-pod
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=secret1-pod
SHLVL=1
HOME=/root
USERNAME=admin
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
PASSWORD=admin321

Volume 挂载

# secret2-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: secret2-pod
spec:
  containers:
    - name: secret2
      image: busybox
      command: ["/bin/sh", "-c", "ls /etc/secrets"]
      volumeMounts:
        - name: secrets
          mountPath: /etc/secrets
          readOnly: true
  volumes:
    - name: secrets
      secret:
        secretName: mysecret
        # optional: defaultMode: 0440   # 若需修改文件权限取消注释并设置
        # optional: true               # 若 Secret 可能不存在且希望 Pod 仍能启动,可设置 optional: true

验证:

ubuntu@ubuntu:~/example/config_map$ kubectl apply -f ./secret2-pod.yaml 
pod/secret2-pod created
ubuntu@ubuntu:~/example/config_map$ kubectl logs secret2-pod
password
username

Secret vs ConfigMap

Secret 和 ConfigMap这两种资源对象的异同点:

相同点

  • key/value 的形式
  • 属于某个特定的命名空间
  • 可以导出到环境变量
  • 可以通过目录/文件形式挂载
  • 通过 volume 挂载的配置信息均可热更新

不同点

  • Secret 可以被 ServerAccount 关联
  • Secret 可以存储 docker register 的鉴权信息,用在 ImagePullSecret 参数中,用于拉取私有仓库的镜像
  • Secret 支持 Base64 加密
  • Secret 分为 kubernetes.io/service-account-token、kubernetes.io/dockerconfigjson、Opaque等多种类型,而 Configmap 不区分类型

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

posted @ 2025-11-17 18:15  beamsoflight  阅读(0)  评论(0)    收藏  举报