
一、ConfigMap
1. 开发的痛点问题
传统容器部署会将应用配置、环境变量直接写入Dockerfile或打包进镜像,配置与镜像深度耦合。任意微小的配置修改都需要重新构建、推送镜像,还要重建Pod,流程繁琐且运维效率低下。同时项目需要适配开发、测试、生产等多套运行环境,不同环境的配置各不相同,在多环境下还需要维护多套不同的镜像,容易造成镜像冗余混乱。
集群内多个业务Pod存在大量通用配置,但传统模式需要在每个Deployment中单独配置环境变量,重复度高。公共配置更新时需逐一修改所有业务清单,容易出现遗漏、配置不一致的问题。同时,没有统一的配置视图,无法集中管理和快速查询集群公共参数。
若将大量业务配置直接写在Pod资源清单中,会导致配置文件臃肿杂乱、可读性差,容易出现格式错误引发Pod异常。不同的服务、命名空间需要相同配置时,只能复制粘贴,无法直接复用一份配置模板。
Web类应用需要适配开发、测试、生产等多套环境,不同环境的数据库、中间件等配置差异较大。传统模式没有标准化配置方案,迁移至Kubernetes后,甚至需要人工进入Pod手动改配置,操作麻烦、容错率低,无法满足线上业务稳定运行的需求。
2. ConfigMap概述
ConfigMap是Kubernetes内置的配置管理资源,专门用于存放环境变量、启动参数、脚本、JSON/Properties等非敏感明文配置,相当于专属的配置存储目录。核心作用是实现容器镜像与业务配置解耦,支持配置独立管理、动态更新,无需修改镜像、重新打包重构应用。
ConfigMap仅支持存储普通明文数据,不适合用于存放密码、密钥等敏感信息,对应敏感数据需使用Secret。可被Pod、Deployment、StatefulSet挂载使用,主要有两种使用方式:注入环境变量、挂载为容器内文件。
ConfigMap不适用于承载大规模数据,其存储内容上限为1MiB。若业务所需存储数据超出该限制,建议改用存储卷挂载、独立数据库或文件服务。
3. ConfigMap使用事项
ConfigMap需要提前创建,若重建Pod时引用了不存在的ConfigMap,Pod会持续处于Pending状态,无法正常启动。
ConfigMap具备命名空间隔离特性,Pod仅能调用相同命名空间下的ConfigMap,无法跨命名空间引用其它命名空间的配置资源。
日常运维中,通常基于YAML文件声明式创建ConfigMap;Pod引用ConfigMap通常是volume挂载方式。
采用volume方式挂载ConfigMap后,更新或删除ConfigMap内容,容器挂载目录下配置文件会自动同步变更。实现配置热更新,无需重启Pod即可生效。
二、ConfigMap创建
1. 从目录创建ConfigMap
[Step1] 新建目录用于存储配置文件。
root@k8s-master:~# mkdir -p /configfile/configmap[Step2] 新建配置文件,模拟服务后端相关参数配置。
root@k8s-master:~# vim /configfile/configmap/server.properties
# 写入下列内容
port=8080
timeout=3000
max.connection=200
log.level=info[Step3] 新建配置文件,模拟用户功能参数配置。
root@k8s-master:~# vim /configfile/configmap/user.properties
# 写入下列内容
register.enable=true
vip.discount=0.8
token.expire=86400
avatar.default=system_01[Step4] 使用kubectl结合“--from-file”参数创建ConfigMap时,指定目录内的全部文件都会自动生成键值对存入ConfigMap。其中键对应文件名称,值对应文件完整内容。
root@k8s-master:~# kubectl create configmap game-config --from-file=/configfile/configmap/[Step5] 验证:查看当前命名空间下所有的ConfigMap,可以看到上述创建的ConfigMap资源。
root@k8s-master:~# kubectl get configmaps
[Step6] 验证:查看当前命名空间下名为game-config的ConfigMap详情,可以看到该ConfigMap的完整配置信息。
root@k8s-master:~# kubectl describe configmaps game-config
2. 从文件创建ConfigMap
--from-file参数支持重复传入,可一次性读取多个文件来构建ConfigMap。
[Step1] 新建配置文件,模拟聊天服务后台相关参数配置。
root@k8s-master:~# vim chat-server.properties
# 写入下列内容
server.port=9000
max.online.user=10000
msg.cache.time=3600
heartbeat.interval=30
log.level=warn[Step2] 新建配置文件,模拟服务后端相关参数配置。
root@k8s-master:~# vim chat-user.properties
# 写入下列内容
register.allow=true
nickname.max.length=16
avatar.upload.size=5242880
token.valid.hour=24
friend.max.count=500[Step3] 新建配置文件,模拟聊天客户端界面相关参数配置。
root@k8s-master:~# vim chat-ui.properties
# 写入下列内容
theme.default=light
msg.font.size=14
msg.show.time=true
chat.bubble.color=#f5f5f5
notification.enable=true[Step4] 使用kubectl结合“--from-file”参数指定多个文件创建ConfigMap。
root@k8s-master:~# kubectl create configmap chat-config --from-file=chat-server.poroperties \
> --from-file=chat-ui.properties \
> --from-file=chat-user.properties[Step5] 验证:查看当前命名空间下所有的ConfigMap,可以看到上述创建的ConfigMap资源。
root@k8s-master:~# kubectl get configmaps
[Step6] 验证:查看当前命名空间下名为chat-config的ConfigMap详情,可以看到该ConfigMap的完整配置信息。
root@k8s-master:~# kubectl get configmaps chat-config
3. 从literal值创建ConfigMap
通过目录、文件方式创建ConfigMap,需要提前编写本地配置文件。Kubernetes提供了无需本地文件的快速创建方式,通过“--from-literal”参数可以直接传入键值对从而生成配置。
[Step1] 使用kubectl结合“--from-literal”参数指定键值对形式创建ConfigMap。
root@k8s-master:~# kubectl create configmap db-config \
> --from-literal=db.host=127.0.0.1 \
> --from-literal=db.port=3306 \
> --from-literal=db.name=root[Step2] 验证:查看当前命名空间下所有的ConfigMap,可以看到上述创建的ConfigMap资源。
root@k8s-master:~# kubectl get configmaps
[Step3] 验证:查看当前命名空间下名为db-config的ConfigMap详情,可以看到该ConfigMap的完整配置信息。
root@k8s-master:~# kubectl describe configmaps db-config
4. 从YAML文件创建ConfigMap
ConfigMap和Deployment、Pod等资源对象一致,支持通过YAML配置文件完成资源创建。
[Step1] 本地新建YAML清单,定义ConfigMap资源描述模板。
root@k8s-master:~# vim network-sec-config.yml
# 写入下列内容
apiVersion: v1 # 固定语法
kind: ConfigMap # 资源类型
metadata:
name: network-sec-config
data:
# 单行键值对,类似使用 --from-iterial
vpn-addr-pool: "172.16.0.0/16"
vpn-encryption: "AES-256-GCM"
max-conn: "200"
# 多行键值对,类似使用 --from-file
security-policy.conf: |
login-verify-code = on
access-timeout = 1800[Step2] 根据YAML清单向Kubernetes集群声明式地创建ConfigMap资源。
root@k8s-master:~# kubectl create -f network-sec-config.yml[Step3] 验证:查看当前命名空间下所有的ConfigMap,可以看到上述创建的ConfigMap资源。
root@k8s-master:~# kubectl get configmaps
[Step4] 验证:查看当前命名空间下名为network-sec-config的ConfigMap详情,可以看到该ConfigMap的完整配置信息。
root@k8s-master:~# kubectl describe configmaps network-sec-config
三、ConfigMap使用
1. 通过环境变量使用ConfigMap
可以直接将ConfigMap里的配置参数,直接给到容器内部程序当作环境变量使用,一共有两种使用方法:
env:按需单独创建环境变量,只引用ConfigMap中的某一项配置;
envFrom:一键导入,会将ConfigMap中的全部配置批量转换为容器环境变量。
[Step1] 本地新建YAML清单,定义Pod资源描述模板,并引用network-sec-config和db-config。
root@k8s-master:~# vim busybox-configmap.yml
# 写入下列内容
apiVersion: v1 # 固定语法
kind: Pod # 资源类型
metadata:
name: busybox-configmap
spec:
containers:
- name: busybox-configmap
image: busybox:latest
imagePullPolicy: IfNotPresent
args: ["/bin/sh","-c","sleep 1000"]
# 单个环境变量注入配置,仅读取ConfigMap中的某一个键的值
env:
- name: max-conn # 环境变量的名称
valueFrom: # 变量值来源于外部
configMapKeyRef: # 数据源指定为ConfigMap的单个键
name: network-sec-config # 引用的ConfigMap名称
key: max-conn # ConfigMap的内部的键名
# 批量注入环境变量,读取整个ConfigMap中的所有键值对
envFrom:
- configMapRef: # 引用完整的ConfigMap
name: db-config # 引用的ConfigMap名称[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。
root@k8s-master:~# kubectl create -f busybox-configmap.yml[Step3] 验证:基于文件内定义的资源清单,查询集群中该资源的运行状态与基础信息。
root@k8s-master:~# kubectl get -f busybox-configmap.yml
[Step4] 验证:登录busybox-configmap,全局过滤环境变量,可以顺利看到注入的环境变量。
root@k8s-master:~# kubectl exec -it busybox-configmap -- /bin/sh
/ # env | grep -E "max-conn|db"
2. 通过Volume使用ConfigMap
采用Volume挂载ConfigMap的方式,与存储管理中的emptyDir、hostPath卷的使用逻辑相似。
ConfigMap挂载完成后会在容器内自动生成独立目录,目录下会自动生成对应配置文件。
其中ConfigMap的键作为文件名称,对应的值即为文本内容。
[Step1] 本地新建YAML清单,定义Pod资源描述模板,并引用network-sec-config。
root@k8s-master:~# vim busybox-network-pod.yml
# 写入下列内容
apiVersion: v1 # 固定语法
kind: Pod # 资源类型
metadata:
name: busybox-network-pod
spec:
containers:
- name: busybox-network-pod
image: busybox:latest
imagePullPolicy: IfNotPresent
args: ["/bin/sh","-c","sleep 1000"]
volumeMounts: # 存储卷挂载配置
- name: network-sec-config # Volume卷名称
mountPath: "/mnt/network-sec-config" # 容器内挂载目录
readOnly: true # 挂载目录为只读
volumes: # 定义存储卷
# 自定义存储卷名称,与[containers.volumeMounts.name]对应
- name: network-sec-config
configMap: # 指定卷的数据源为ConfigMap资源
# 绑定集群中名为network-sec-config的ConfigMap
name: network-sec-config[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。
root@k8s-master:~# kubectl create -f busybox-network-pod.yml[Step3] 验证:基于文件内定义的资源清单,查询集群中该资源的运行状态与基础信息。
root@k8s-master:~# kubectl get -f busybox-network-pod.yml
[Step4] 验证:登录busybox-network-pod,可以在预先挂载的目录下查看自动生成的配置文件,读取文件内容可以获取ConfigMap内对应的键值信息。
root@k8s-master:~# kubectl exec -it busybox-network-pod -- /bin/sh
/ # ls -a /mnt/network-sec-config/
/ # cat /mnt/network-sec-config/security-policy.conf
[Step5] 在线编辑ConfigMap,添加一行。
root@k8s-master:~# kubectl edit configmaps network-sec-config
# 在security-policy.conf添加下列内容
log.level = warn
[Step6] 登录busybox-network-pod,查看挂载目录下security-policy.conf文件内容,可以看到已热更新。
root@k8s-master:~# kubectl exec -it busybox-network-pod -- /bin/sh
/ # cat /mnt/network-sec-config/security-policy.conf
四、Secret
1. Secret概述
Secret是Kubernetes内置核心资源,专门用于存储敏感数据,例如密码、token、数据库账号、私钥等。ConfigMap适合存放明文普通数据,Secret用于保管不能直接暴露的私密信息,二者使用方式高度相似,但是Secret有基础脱敏保护机制。
Secret的核心定位是避免敏感数据硬编码写在Pod/YAML中,不将账号密码直接暴露在命令行、日志、镜像内。同时精细化权限控制,限制谁能够读取私密数据。在创建、查看和编辑Pod的流程中Secret暴露风险较小,系统会对Secret对象采取额外的预防措施,例如避免将其写入磁盘中可能的位置。只有Pod请求的Secret在其容器内才是可见的,一个Pod无法访问另外一个Pod的Secret。
和ConfigMap挂载机制一致,Secret通过Volume方式挂载后,修改或删除数据,容器挂载目录中的数据会自动同步更新,实现配置热更新,无需重启Pod即可生效。
2. 数据存储机制
Secret存入etcd时仅对数据做Base64转码,非加密。仅用于隐藏明文展示,不具备数据防护能力。任何人在获取Secret YAML后,通过下列命令即可还原原始敏感内容。
echo "编码字符串" | base64 -d在生产环境中建议开启etcd静态加密,避免etcd数据泄露造成全部Secret明文泄露。同时,搭配RBAC权限管控,限制普通开发人员查看、解密Secret资源。ApiServer与kubelet、客户端之间采用HTTPS加密通信,Secret在传输链路中不会以明文形式抓包窃取。
五、Secret创建
1. 通过kubectl命令创建Secret
[Step1] 分别创建两个文件,存储用户名和密码。
root@k8s-master:~# echo -n "admin" > username.txt
root@k8s-master:~# echo -n "admin@123" > password.txt[Step2] 使用kubectl命令创建Secret,指定Secret名称为login-user-passwd。其中generic参数表示从本地的文件、目录或实际值(literal value)读取。
root@k8s-master:~# kubectl create secret generic login-user-passwd \
> --from-file=./username.txt \
> --from-file=./password.txt[Step3] 验证:查看当前命名空间下所有Secret,可以看到上述创建的资源。其中Opaque为通用Secret类型,内部数据采用Base64编码存储。
root@k8s-master:~# kubectl get secrets
[Step4] 验证:查看当前命名空间下名为login-user-passwd的Secret详情,对比ConfigMap可以发现,Secret不会直接显示原始明文数据。
root@k8s-master:~# kubectl describe secrets login-user-passwd
[Step5] 可以获取Secret并输出YAML,查看Base64编码内容。然后复制编码字符串,手动解密
root@k8s-master:~# kubectl get secrets login-user-passwd -o yaml
root@k8s-master:~# echo "YWRtaW5AMTIz" | base64 -d
2. 使用YAML创建Secret
[Step1] 为了规避YAML文件中的值被直接看到,因此需要先用Base64编码后再写入YAML。
root@k8s-master:~# echo "admin" | base64
root@k8s-master:~# echo "admin@123" | base64
[Step2] 本地新建YAML清单,定义Secret资源描述模板。
root@k8s-master:~# vim admin-secret.yml
# 写入下列内容
apiVersion: v1 # 固定语法
kind: Secret # 资源类型
metadata:
name: admin-secret
type: Opaque # 指定Secret类型
# 存放Base64编码后的敏感数据,禁止直接填写明文
data:
username: YWRtaW4K
password: YWRtaW5AMTIzCg==[Step3] 根据YAML清单向Kubernetes集群声明式地创建Secret资源。
root@k8s-master:~# kubectl create -f admin-secret.yml[Step4] 验证:查看当前命名空间下所有Secret,可以看到上述创建的资源。
root@k8s-master:~# kubectl get secrets
[Step5] 验证:查看当前命名空间下名为admin-secret的Secret详情,同样无法直接显示原始明文数据。
root@k8s-master:~# kubectl describe secrets admin-secret
六、Secret使用
1. 通过Volume方式使用Secret
通过Volume挂载Secret的使用逻辑与ConfigMap类似。
Secret挂载至容器后会生成独立目录,内部每一组键值对应一个文件:键为文件名,值为文件内容。
Secret挂载至Pod时会自动解码,因此在容器内部是明文显示。
[Step1] 本地新建YAML清单,定义Pod资源描述模板,并引用admin-secret。
root@k8s-master:~# vim admin-secret-pod.yml
# 写入下列内容
apiVersion: v1 # 固定语法
kind: Pod # 资源类型
metadata:
name: admin-secret-pod
spec:
containers:
- name: admin-secret-pod
image: busybox
imagePullPolicy: IfNotPresent
args: ["/bin/sh","-c","sleep 1000"]
volumeMounts: # 存储卷挂载配置
- name: admin-secret # Volume卷名称
mountPath: "/etc/secret" # 容器内挂载目录
readOnly: true # 挂载目录为只读
volumes: # 定义存储卷
# 自定义存储卷名称,与[containers.volumeMounts.name]对应
- name: admin-secret
secret: # 指定卷的数据源为Secret资源
# 绑定集群中名为admin-secret的Secret
secretName: admin-secret[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。
root@k8s-master:~# kubectl create -f admin-secret-pod.yml[Step3] 验证:基于文件内定义的资源清单,查询集群中该资源的运行状态与基础信息。
root@k8s-master:~# kubectl get -f admin-secret-pod.yml
[Step4] 验证:登录admin-secret-pod,可直接读取挂载目录下的文件,获取解码后的明文密钥内容
root@k8s-master:~# kubectl exec -it admin-secret-pod -- /bin/sh
/ # cat /etc/secret/username
/ # cat /etc/secret/password
[Step5] 新建键值条目,首先将api_token明文进行Base64编码,然后在线编辑Secret方式新增。
root@k8s-master:~# echo "7s9KdF2n8GpR5tXbQa3zYcV0mN1jL4hU" | base64
root@k8s-master:~# kubectl edit secrets admin-secret
# 在data添加下列内容
N3M5S2RGMm44R3BSNXRYYlFhM3pZY1YwbU4xakw0aFUK
[Step6] 登录admin-secret-pod,查看挂载目录下security-policy.conf文件内容,可以看到已热更新。
root@k8s-master:~# kubectl exec -it admin-secret-pod -- /bin/sh
/ # cat /etc/secret/api_token
2. 仅挂载指定值
在挂载Secret的时候可以指定items,只将Secret中的某些参数传递到Pod。
[Step1] 本地新建YAML清单,定义Pod资源描述模板,并引用admin-secret。
root@k8s-master:~# vim username-secret-pod.yml
# 写入下列内容
apiVersion: v1 # 固定语法
kind: Pod # 资源类型
metadata:
name: username-secret-pod
spec:
containers:
- name: username-secret-pod
image: busybox:latest
imagePullPolicy: IfNotPresent
args: ["/bin/sh","-c","sleep 1000"]
volumeMounts: # 存储卷挂载配置
- name: admin-secret # Volume卷名称
mountPath: "/etc/secret" # 容器内挂载目录
readOnly: true # 挂载目录为只读
volumes: # 定义存储卷
# 自定义存储卷名称,与[containers.volumeMounts.name]对应
- name: admin-secret
secret: # 指定卷的数据源为Secret资源
# 绑定集群中名为admin-secret的Secret
secretName: admin-secret
# 自定义映射规则,仅提取Secret内指定key,并自定义容器内文件名
items:
- key: username # 映射规则名称
# 将Secret中key=username的值,在挂载目录中生成文件my-username
path: my-username[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。
root@k8s-master:~# kubectl create -f username-secret-pod.yml[Step3] 验证:基于文件内定义的资源清单,查询集群中该资源的运行状态与基础信息。
root@k8s-master:~# kubectl get -f username-secret-pod.yml
[Step4] 验证:登录username-secret-pod,查看挂载目录可以发现仅挂载username。读取该文件可以直接获取解码后的明文密钥内容。
root@k8s-master:~# kubectl exec -it username-secret-pod -- /bin/sh
/ # ls -a /etc/secret/
/ # cat /etc/secret/my-username
[Step5] 先对新的username进行Base64编码,然后在线编辑Secret更新。
root@k8s-master:~# echo "user01" | base64
root@k8s-master:~# kubectl edit secrets admin-secret
# 将data.usename内容修改为下列值
username: dXNlcjAxCg==
[Step6] 登录username-secret-pod,查看挂载目录下my-username文件内容,可以看到已热更新。
root@k8s-master:~# kubectl exec -it username-secret-pod -- /bin/sh
/ # cat /etc/secret/my-username
