K8S configmap & secret

K8s ConfigMap与Secret 完整进阶笔记

一、K8s配置资源核心概述

K8s提供ConfigMap和Secret两大核心配置资源,核心作用是解耦应用配置与容器镜像,实现配置与代码分离。无需重新打包镜像、重建Pod即可更新业务配置,彻底解决配置硬编码问题,适配集群多Pod统一配置管理场景。

两者核心定位区分:ConfigMap用于存储非敏感明文配置,Secret用于存储敏感加密类配置,是K8s集群核心的配置中心组件。

二、ConfigMap 普通配置资源详解

2.1 ConfigMap核心概念与使用限制

ConfigMap是K8s托管的普通配置资源,可将各类业务配置文件、键值对配置统一存储,通过挂载卷、环境变量的方式注入Pod,实现多Pod共享同一套配置,统一管理、批量更新。

核心使用限制(硬性规则):

1、Pod使用限制:仅通过Kubernetes API创建的Pod可使用ConfigMap,静态Pod无法绑定、无法使用;

2、资源大小限制:受ETCD存储机制约束,单个ConfigMap最大存储容量为1MB;

3、数据安全限制:仅存储明文普通配置,无加密能力,严禁存储密码、密钥、证书等敏感数据。

2.2 ConfigMap核心作用

集群多Pod业务场景中,若数十上百个Pod需要复用相同配置文件,无需逐个修改Pod配置。只需创建一份ConfigMap并关联所有目标Pod,即可实现全局统一配置下发。

ConfigMap支持配置动态更新,资源配置修改后,关联Pod的文件系统配置会自动同步,但Pod内运行的业务进程不会自动重启、重载配置,该特性后续会详细说明。

2.3 YAML多行文本特殊符号详解

ConfigMap的data字段支持多行文本配置,依靠YAML特殊符号控制文本换行、折叠格式,所有规则均配套实际案例与解析结果,是编写复杂配置的核心语法。

1、竖线符 |:保留文本原始内部换行,去除每行末尾空白与行尾空行,保留文本内部缩进

lines: |
我是第一行
我是第二行
  我是Egon
  我是第四行
我是第五行

解析结果:{"lines": "我是第一行\n我是第二行\n 我是Egon\n 我是第四行\n我是第五行\n"}

2、|- 符号:保留文本内部换行,删除文本末尾所有换行符

value: |-
hello
world

解析结果:{"value": "hello\nworld"}

3、|+ 符号:完整保留文本所有换行,包括末尾空行,有多少回车即保留多少换行符

value: |+
hello
world

解析结果:{"value": "hello\nworld\n\n"}

4、大于号 >:折叠换行,文本内普通换行转换为空格,仅空白行保留换行,文本末尾换行默认保留

lines: >
我是第一行
我也是第一行
我仍是第一行
我依旧是第一行
我是第二行
这么巧我也是第二行

解析结果:{"lines": "我是第一行 我也是第一行 我仍是第一行 我依旧是第一行\n我是第二行 这么巧我也是第二行\n"}

2.4 ConfigMap两种创建方式

2.4.1 YAML清单文件创建(精准自定义配置)

通过YAML文件自定义各类键值对、多行配置,支持普通键值与多行文本混合配置,是生产环境精准配置的常用方式。

apiVersion: v1
data:
  xxx: "111"
  yyy: "222"
  data.1: hello
  data.2: world
  config1: |
    property.1=value-1
    property.2=value-2
    property.3=value-3
  config2: |-
    hello
    world
  config3: |+
    hello
    world
  config4: >
    我是第一行
    我也是第一行
    我仍是第一行
    我依旧是第一行
    我是第二行
    这么巧我也是第二行
kind: ConfigMap
metadata:
  name: test1-config
  namespace: default

创建并查看格式化配置命令:

kubectl apply -f test1-config.yaml
kubectl get cm test1-config -o json

2.4.2 命令行快速创建(快速批量配置)

无需编写YAML文件,通过kubectl命令快速创建,支持目录、单个文件、字面量键值对三种创建模式,适配快速测试、批量配置场景。

1、指定目录创建:读取目录下所有配置文件,文件名为key、文件内容为value

# 准备配置目录与配置文件
mkdir /myconf && cd /myconf

cat > redis.conf << EOF
host=127.0.0.1
port=6379
EOF

cat > mysql.conf << EOF
host=127.0.0.1
port=3306
EOF

# 根据目录创建ConfigMap
kubectl create configmap test2-config --from-file=/myconf

# 查看配置
kubectl get cm test2-config -o yaml

2、指定单个文件创建:精准绑定单个配置文件,可多次叠加--from-file参数绑定多文件

kubectl create configmap test3-config --from-file=/myconf/mysql.conf
kubectl get cm test3-config -o yaml

3、字面量键值对创建:直接通过命令行传入键值对,无需本地配置文件

kubectl create configmap test4-config --from-literal=db.host=localhost --from-literal=db.port=3306
kubectl get cm test4-config -o yaml

2.5 ConfigMap三种Pod关联使用方式

2.5.1 环境变量注入方式

将ConfigMap的键值对注入为容器环境变量,支持单个键精准注入、整个ConfigMap批量注入,适合简单键值对配置。

apiVersion: v1
kind: Pod
metadata:
  name: testcm1-pod
spec:
  containers:
  - name: testcm1
    image: busybox
    command: [ "/bin/sh", "-c", "tail -f /dev/null" ]
    env:
    # 精准注入单个键值对
    - name: DB_HOST
      valueFrom:
        configMapKeyRef:
          name: test4-config
          key: db.host
    - name: DB_PORT
      valueFrom:
        configMapKeyRef:
          name: test4-config
          key: db.port
    # 批量注入整个ConfigMap
    envFrom:
    - configMapRef:
        name: test2-config

查看容器环境变量配置:

kubectl logs -f testcm1-pod

2.5.2 容器命令变量引用方式

将注入的环境变量直接用于容器启动命令,实现配置动态调用,适配启动参数依赖配置的场景。

apiVersion: v1
kind: Pod
metadata:
  name: testcm2-pod
spec:
  containers:
  - name: testcm2
    image: busybox
    command: [ "/bin/sh", "-c", "echo $(DB_HOST) $(DB_PORT)" ]
    env:
    - name: DB_HOST
      valueFrom:
        configMapKeyRef:
          name: test4-config
          key: db.host
    - name: DB_PORT
      valueFrom:
        configMapKeyRef:
          name: test4-config
          key: db.port

执行查看变量输出结果:

kubectl logs -f testcm2-pod

2.5.3 数据卷挂载方式(生产最常用)

将ConfigMap以数据卷形式挂载到容器指定目录,支持完整挂载、子路径自定义挂载,是唯一支持配置热更新的使用方式。

1、完整挂载示例:将整个ConfigMap配置挂载到指定目录

apiVersion: v1
kind: Pod
metadata:
  name: testcm3-pod
spec:
  volumes:
  - name: my-volume
    configMap:
      name: test3-config
  containers:
  - name: testcm3
    image: busybox
    command: [ "/bin/sh", "-c", "cat /etc/config/mysql.conf" ]
    volumeMounts:
    - name: my-volume
      mountPath: /etc/config

2、子路径自定义挂载示例:按需挂载指定配置文件,自定义容器内文件路径

apiVersion: v1
kind: Pod
metadata:
  name: testcm4-pod
spec:
  volumes:
  - name: my-volume
    configMap:
      name: test2-config
      items:
      - key: mysql.conf
        path: path1/to/msyql.conf
      - key: redis.conf
        path: path2/to/redis.conf
  containers:
  - name: testcm4
    image: busybox
    command: [ "/bin/sh","-c","cat /etc/config/path1/to/msyql.conf ;sleep 10 ;cat /etc/config/path2/to/redis.conf" ]
    volumeMounts:
    - name: my-volume
      mountPath: /etc/config

2.6 ConfigMap热更新机制详解

2.6.1 原生热更新特性与缺陷

原生热更新机制:当ConfigMap以数据卷挂载方式关联Pod时,通过kubectl edit、apply等方式更新ConfigMap配置后,无需重启Pod,集群会自动同步更新Pod容器内的配置文件内容,实现文件层级的热更新。

核心致命缺陷:集群仅更新Pod文件系统中的配置文件,不会主动通知、重启业务进程。绝大多数应用仅在启动时读取一次配置,运行过程中不会主动监听、重载配置文件,因此单纯更新ConfigMap无法让业务生效,必须手动重启Pod或重载应用配置。

原生解决方案:手动删除重建Pod、编写监控脚本监听文件变更并重载服务,操作繁琐、无法自动化。

2.6.2 全自动热更新方案(Reloader组件)

通过部署Stakater Reloader组件,实现ConfigMap/Secret变更→自动滚动重启Deployment→应用加载新配置的全自动化流程,是生产标准热更新方案。

1、完整部署流程

# 下载Reloader部署清单
wget --no-check-certificate https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml

# 适配集群环境并部署
sed -i 's#RELEASE-NAME#config#g' reloader.yaml
kubectl apply -f reloader.yaml

2、Reloader完整资源清单(权限+部署,无删减)

# ServiceAccount 账号配置
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    meta.helm.sh/release-namespace: "default"
    meta.helm.sh/release-name: "reloader"
  labels:
    app: reloader-reloader
    chart: "reloader-1.0.97"
    release: "reloader"
    heritage: "Helm"
    app.kubernetes.io/managed-by: "Helm"
  name: reloader-reloader
  namespace: default
---
# ClusterRole 集群权限配置
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    meta.helm.sh/release-namespace: "default"
    meta.helm.sh/release-name: "reloader"
  labels:
    app: reloader-reloader
    chart: "reloader-1.0.97"
    release: "reloader"
    heritage: "Helm"
    app.kubernetes.io/managed-by: "Helm"
  name: reloader-reloader-role
rules:
- apiGroups: [""]
  resources: ["secrets", "configmaps"]
  verbs: ["list", "get", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "daemonsets", "statefulsets"]
  verbs: ["list", "get", "update", "patch"]
- apiGroups: ["extensions"]
  resources: ["deployments", "daemonsets"]
  verbs: ["list", "get", "update", "patch"]
- apiGroups: ["batch"]
  resources: ["cronjobs"]
  verbs: ["list", "get"]
- apiGroups: ["batch"]
  resources: ["jobs"]
  verbs: ["create"]
- apiGroups: [""]
  resources: ["events"]
  verbs: ["create", "patch"]
---
# ClusterRoleBinding 权限绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    meta.helm.sh/release-namespace: "default"
    meta.helm.sh/release-name: "reloader"
  labels:
    app: reloader-reloader
    chart: "reloader-1.0.97"
    release: "reloader"
    heritage: "Helm"
    app.kubernetes.io/managed-by: "Helm"
  name: reloader-reloader-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: reloader-reloader-role
subjects:
- kind: ServiceAccount
  name: reloader-reloader
  namespace: default
---
# Deployment 组件部署
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    meta.helm.sh/release-namespace: "default"
    meta.helm.sh/release-name: "reloader"
  labels:
    app: reloader-reloader
    chart: "reloader-1.0.97"
    release: "reloader"
    heritage: "Helm"
    app.kubernetes.io/managed-by: "Helm"
    group: com.stakater.platform
    provider: stakater
    version: v1.0.97
  name: reloader-reloader
  namespace: default
spec:
  replicas: 1
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: reloader-reloader
      release: "reloader"
  template:
    metadata:
      labels:
        app: reloader-reloader
        chart: "reloader-1.0.97"
        release: "reloader"
        heritage: "Helm"
        app.kubernetes.io/managed-by: "Helm"
        group: com.stakater.platform
        provider: stakater
        version: v1.0.97
    spec:
      containers:
      - image: "registry.cn-shanghai.aliyuncs.com/egon-k8s-test/reloader:v1.0.97"
        imagePullPolicy: IfNotPresent
        name: reloader-reloader
        ports:
        - name: http
          containerPort: 9090
        livenessProbe:
          httpGet:
            path: /live
            port: http
          timeoutSeconds: 5
          failureThreshold: 5
          periodSeconds: 10
          initialDelaySeconds: 10
        readinessProbe:
          httpGet:
            path: /metrics
            port: http
          timeoutSeconds: 5
          failureThreshold: 5
          periodSeconds: 10
          initialDelaySeconds: 10
        securityContext:
          runAsNonRoot: true
          runAsUser: 65534
          seccompProfile:
            type: RuntimeDefault
      serviceAccountName: reloader-reloader

3、业务开启自动热更新:在Deployment注解中添加自动监听配置

metadata:
  annotations:
    reloader.stakater.com/auto: "true"

4、完整测试案例(Nginx配置热更新)

第一步:创建Nginx配置文件与ConfigMap

cat > www.conf << EOF
server {
server_name myapp.egon.com;
listen 80;
root /data/web/html;
}
EOF

kubectl create configmap nginx-config --from-file=./www.conf

第二步:部署关联ConfigMap的Nginx业务

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web-test
  name: web-test
  annotations:
    reloader.stakater.com/auto: "true"
spec: 
  replicas: 1
  selector: 
    matchLabels:
      app: web-test 
  template: 
    metadata:
      labels:
        app: web-test
    spec:
      containers:
      - image: nginx:1.18
        name: nginx
        volumeMounts:
        - name: nginxconf
          mountPath: /etc/nginx/conf.d/
          readOnly: true
      volumes:
      - name: nginxconf
        configMap:
          name: nginx-config

第三步:测试热更新,修改ConfigMap配置,验证Pod自动重启、配置生效

# 修改配置端口为8081
kubectl edit cm nginx-config

# 查看Pod是否自动重启
kubectl get pods -o wide

# 测试访问新端口
curl 容器IP:8081

三、Secret 敏感配置资源详解

3.1 Secret核心概念与作用

Secret是K8s用于存储敏感数据的专属配置资源,专门存放密码、Token、私钥、SSL证书、私有镜像仓库凭证等机密信息,避免敏感数据硬编码在镜像、Pod配置中,提升集群业务安全性。

核心特性:

1、编码存储:数据默认以Base64编码存储,集群查询不直接暴露明文,容器内使用时自动解码;
2、配置解耦:敏感配置独立托管,更新配置无需重新打包镜像、重构业务;
3、大小限制:单Secret最大1MB,与ConfigMap一致,受ETCD存储约束;
4、安全说明:Base64仅为编码而非加密,etcd中原始数据为明文,需严格管控Master节点与etcd访问权限,超高敏感数据需搭配Vault加密工具。

3.2 Secret四大核心类型

1、Opaque:默认通用类型,支持自定义键值对,用于存储账号密码、自定义敏感配置;
2、kubernetes.io/tls:专属证书类型,用于存储HTTPS、SSL证书与私钥,适配域名加密访问场景;
3、kubernetes.io/dockerconfigjson:私有镜像仓库认证类型,存储Docker仓库登录凭证,用于拉取私有镜像;
4、kubernetes.io/service-account-token:服务账号令牌类型,用于Pod与APIServer通信的认证凭证,1.24版本后采用动态令牌机制。

3.3 Opaque类型Secret实操详解

Opaque是最常用的通用Secret类型,支持data、stringData两个核心字段,适配绝大多数敏感配置场景。

3.3.1 核心字段区别

1、data字段:必须传入Base64编码后的字符串,适合固定、无需频繁修改的敏感数据;
2、stringData字段:直接传入明文字符串,集群创建资源后自动完成Base64编码,无需手动转换,适合快速编写配置。

Base64编码/解码命令:

# 明文转Base64编码
echo -n 'egon' | base64
echo -n '123456' | base64

# Base64解码为明文
echo -n '编码内容' | base64 -d

3.3.2 两种字段创建案例

1、data字段创建(手动编码)

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  username: ZWdvbg==
  password: MTIzNDU2
type: Opaque

2、stringData字段创建(直接写明文)

apiVersion: v1
kind: Secret
metadata:
  name: demo-secret
type: Opaque
stringData:
  config.yaml: |
    apiUrl: "https://my.api.com/api/v1"
    username: egon
    password: 123

3.3.3 Secret两种Pod注入方式

1、数据卷挂载方式:挂载到容器目录,文件自动解码为明文,支持配置热更新(仅文件层级);

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","cat /etc/my-secret;sleep 10000"]
        volumeMounts:
        - name: xxx
          mountPath: /etc/my-secret
      volumes:
      - name: xxx
        secret:
          secretName: test-secret

2、环境变量注入方式:注入为容器环境变量,不支持热更新,修改Secret后必须重启Pod生效;

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: BIG_SB
          valueFrom:
            secretKeyRef:
              name: test-secret
              key: username
        - name: BIG_NB
          valueFrom:
            secretKeyRef:
              name: test-secret
              key: password
        - name: BIG_CONFIG
          valueFrom:
            secretKeyRef:
              name: demo-secret
              key: config.yaml

补充:Secret热更新规则与ConfigMap一致,仅文件同步更新,业务进程不生效,需依赖Reloader组件自动重启Pod。

3.4 dockerconfigjson类型Secret(私有镜像仓库认证)

该类型Secret专门用于存储私有Docker镜像仓库的登录凭证,让Kubelet可以拉取集群私有镜像,是私有仓库部署的核心配置。

1、命令行快速创建私有仓库Secret

# 定义私有仓库信息
export DOCKER_REGISTRY_SERVER=10.0.0.100
export DOCKER_USER=root
export DOCKER_PASSWORD=root@123
export DOCKER_EMAIL=root@123.com

# 创建仓库认证Secret
kubectl create secret docker-registry myregistrykey \
--docker-server=$DOCKER_REGISTRY_SERVER \
--docker-username=$DOCKER_USER \
--docker-password=$DOCKER_PASSWORD \
--docker-email=$DOCKER_EMAIL

# 查看Secret详情
kubectl describe secret myregistrykey
kubectl get secret myregistrykey -o yaml

2、Pod/Deployment引用私有仓库凭证

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: test
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: test
    spec:
      containers:
      - image: 192.168.1.100:5000/test:v1
        name: alpine
        args: ["sleep","36000"]
      # 引用私有仓库认证Secret
      imagePullSecrets:
      - name: myregistrykey

3、全局生效配置(ServiceAccount绑定)

无需每个Pod单独配置imagePullSecrets,直接绑定ServiceAccount,所有引用该SA的Pod自动生效私有仓库认证。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: default
imagePullSecrets:
- name: myregistrykey

核心注意点:imagePullSecrets凭证仅Kubelet组件可读取使用,业务容器无法获取仓库账号密码,安全性更高。

3.5 service-account-token 令牌机制详解

service-account-token是绑定服务账号(SA)的专属Secret,用于Pod与K8s APIServer通信的身份认证,1.24版本前后机制差异极大。

3.5.1 K8s 1.24旧版本机制缺陷

1、每创建一个ServiceAccount,集群自动生成固定Secret令牌,长期绑定无法动态更新;
2、大规模集群中大量SA会生成大量冗余Secret,占用集群资源、影响扩容;
3、JWT令牌无过期时间,一旦泄露会长期存在风险,易被非法冒用、提权。

3.5.2 K8s 1.24+ 新版令牌投影机制

1、创建ServiceAccount不再自动生成Secret,Pod引用SA时,集群动态临时生成令牌;
2、Kubelet自动监控令牌有效期,临近过期时自动轮换刷新,无需人工干预;
3、支持自定义令牌过期时间,最小可设置10分钟,大幅降低泄露风险;
4、令牌默认挂载路径:/var/run/secrets/kubernetes.io/serviceaccount,包含ca.crt、namespace、token三个认证文件。

新版自定义令牌挂载案例:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  serviceAccountName: build-robot
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /var/run/secrets/tokens
      name: vault-token
  volumes:
  - name: vault-token
    projected:
      sources:
      - serviceAccountToken:
          path: vault-token
          expirationSeconds: 600
          audience: vault

效果:令牌每10分钟自动更新,无需重建Pod、无需手动维护,安全性、扩展性大幅提升。

3.6 资源不可变配置(ConfigMap/Secret通用)

ConfigMap和Secret均支持immutable不可变属性,开启后资源的data字段禁止任何修改操作,仅支持删除重建,可防止核心配置被误修改,提升集群稳定性。

metadata:
  immutable: true

生效规则:已挂载旧配置的存量Pod继续使用旧配置,新创建Pod会加载删除重建后的最新配置。

四、ConfigMap与Secret 完整对比总结

4.1 相同点

1、存储格式:均采用key/value键值对格式存储配置数据;
2、资源隔离:均归属命名空间管理,仅同命名空间资源可相互引用;
3、使用方式:均支持环境变量注入、数据卷挂载两种Pod关联方式;
4、热更新特性:数据卷挂载模式均支持集群文件层级热更新,环境变量模式均不支持;
5、资源限制:单资源最大存储1MB,遵循ETCD集群存储规范;
6、高级特性:均支持immutable不可变配置,防止配置误改。

4.2 不同点

1、数据安全:ConfigMap存储明文普通配置,无安全防护;Secret通过Base64编码存储敏感数据,规避明文泄露风险;
2、资源类型:ConfigMap无细分类型,仅通用配置功能;Secret细分Opaque、tls、dockerconfigjson、service-account-token多类专属类型;
3、专属能力:Secret支持ServiceAccount绑定、私有镜像拉取(imagePullSecrets),ConfigMap无此类安全认证能力;
4、适用场景:ConfigMap适配所有非敏感业务配置(配置文件、通用参数);Secret适配密码、证书、镜像凭证、集群认证等敏感场景;
5、安全层级:ConfigMap完全明文展示,无防护;Secret默认编码展示,普通用户无法直接读取明文,需解码查看。

posted @ 2026-07-14 11:02  cuckooyang  阅读(25)  评论(0)    收藏  举报