在现代应用架构中,合理地管理与分离配置项是实现高可维护性和高可扩展性的基础。应用程序本身通常专注于实现业务逻辑,而具体的运行参数(如数据库地址、日志级别、服务端口等)则应当以独立、可变的方式进行管理。这些与业务解耦的参数即为“配置”。
如果将所有配置硬编码在应用程序内部,则每当不同环境(如开发、测试、生产)需要调整配置,便需为每个环境单独构建和部署不同的镜像。这不仅导致了镜像管理的复杂度提升、变更流程变慢,还会埋下潜在的安全隐患(如敏感信息内嵌镜像)。此外,紧耦合的配置还限制了应用的灵活性,增加了运维风险。
Kubernetes 针对上述问题,提供了 ConfigMap 这一原生对象,用于实现应用配置的专业化与标准化管理。ConfigMap 能够将各类非敏感的配置信息(如环境变量、配置文件片段等)独立存储,并以多种方式灵活地注入到容器中。

传统的配置管理方式通常将应用和配置绑定。例如,一个企业可能为开发(Dev)、测试(Test)、生产(Prod)环境分别维护多套镜像,仅因配置细节不同(如数据库连接串、日志级别等)。这种做法存在如下弊端:
因此,解耦应用与配置,采用集中、可变的配置管理机制,是现代云原生应用的基础能力。
Kubernetes 的 ConfigMap 对象专门用于管理非敏感且可变的配置信息。它通过键值对的形式存储配置,支持将配置信息以环境变量、配置文件等多种方式传递给 Pod。在部署阶段,应用镜像无需更改,即可通过挂载不同的 ConfigMap,适配不同环境和场景,实现“一次构建,多环境部署”。
这样,每个环境只需维护独立的 ConfigMap 对象来覆盖对应的配置项,不仅降低了镜像管理难度,也极大提升了灵活性和安全性。
请注意,ConfigMap 仅适用于存放非敏感数据。针对密码、API 密钥、证书等敏感信息,建议使用 Kubernetes 的 Secret 对象进行安全管理,后续学习中我们会详细介绍。
创建 ConfigMap 的方式非常灵活,主要有两种:声明式(Declarative)和命令式(Imperative)。
在生产环境中,我们总是推荐使用 YAML 文件来定义和管理 Kubernetes 对象,这被称为声明式方法。它就像是给 Kubernetes 一张“配置清单”,让它去确保实际状态和清单一致。
下面是一个简单的 ConfigMap 定义文件 my-configmap.yaml:
|apiVersion: v1 kind: ConfigMap metadata: name: app-settings data: # 简单的键值对 log_level: "info" database_url: "mysql-prod.default.svc.cluster.local" # 也可以把整个配置文件作为值 nginx.conf: | server { listen 80; server_name example.com; root /usr/share/nginx/html; }
这个 YAML 文件定义了一个名为 app-settings 的 ConfigMap,它包含两个简单的键值对和一个完整的 Nginx 配置文件。那个 | 符号告诉 YAML,后面缩进的所有内容都属于 nginx.conf 这个键的值。
然后,你只需要一个命令就可以应用这个配置:
|$ kubectl apply -f my-configmap.yaml
有时为了快速测试或临时任务,我们不想专门创建一个 YAML 文件。这时可以使用命令式方法,直接通过 kubectl 命令创建 ConfigMap。
你可以从字面量(literal values)创建:
|$ kubectl create configmap my-app-config-literal --from-literal=theme=dark --from-literal=language=chinese
这条命令会创建一个名为 my-app-config-literal 的 ConfigMap,包含 theme 和 language 两个键。
你也可以从一个或多个文件创建。假设你有一个 config.properties 文件:
|$ kubectl create configmap my-app-config-file --from-file=config.properties
Kubernetes 会使用文件名 config.properties 作为键,文件的内容作为值,来创建一条数据。
创建好 ConfigMap 之后,我们还需要让 Pod 里的容器能够“读取”到这些配置。这通常有三种方式。
这是最常见和直接的方式。你可以将 ConfigMap 中的某个键值对,直接注入为容器内部的一个环境变量。
想象一下,这就像在容器启动时,给它贴了一张“便利贴”,上面写着“数据库地址是 xxx”。
|apiVersion: v1 kind: Pod metadata: name: my-app-pod spec: containers: - name: my-app-container image: my-app env: - name: LOG_LEVEL # 环境变量的名称 valueFrom: configMapKeyRef: name: app-settings # ConfigMap 的名字
这个 Pod 启动后,容器 my-app-container 内部就会有一个名为 LOG_LEVEL 的环境变量,其值为 info。
这种方式非常简单,但有一个特点:它是静态的。也就是说,如果 Pod 已经运行起来了,你再去修改 ConfigMap,容器内的环境变量是不会自动更新的。
这是最强大和灵活的方式。你可以把整个 ConfigMap 挂载成一个目录,里面的每一个键值对都会成为一个文件(键是文件名,值是文件内容)。
这就像是给了容器一个“共享文件夹”,里面存放着所有配置文件。应用可以直接去读取这些文件。
|apiVersion: v1 kind: Pod metadata: name: my-nginx-pod spec: containers: - name: my-nginx image: nginx volumeMounts: - name: nginx-config-volume mountPath: /etc/nginx/conf.d # 挂载到容器的这个目录下 volumes: - name: nginx-config-volume
在这个例子里,app-settings 这个 ConfigMap 里的 nginx.conf 条目,会被创建为 /etc/nginx/conf.d/default.conf 文件,Nginx 服务器启动时就会自动加载这个配置。
通过卷挂载的方式有一个巨大的优势:它是动态的!当你更新了 ConfigMap 中的内容后,Kubernetes 会在一段时间后自动更新挂载到容器中的文件。这对于需要动态更新配置的应用来说,非常有用。
至于第三种方式,通过容器启动命令的参数来使用,它本质上也是利用了环境变量,只是用法稍有不同,我们在这里就不做过多赘述了,掌握以上两种方式足以应对绝大多数场景。