ConfigMap
ConfigMap 是一个 API 对象,用于以键值对的形式存储非机密数据。Pod 可以将 ConfigMap 作为环境变量、命令行参数或 卷 中的配置文件使用。
ConfigMap 允许你将特定环境的配置与你的容器镜像解耦,从而使你的应用程序易于移植。
注意
ConfigMap 不提供保密或加密。如果你想要存储的数据是机密的,请使用 Secret 而不是 ConfigMap,或者使用额外的(第三方)工具来保护你的数据隐私。动机
使用 ConfigMap 将配置数据与应用程序代码分开设置。
例如,假设你正在开发一个应用程序,你可以在自己的计算机上运行(用于开发),也可以在云端运行(处理实际流量)。你编写的代码会查找名为 DATABASE_HOST
的环境变量。在本地,你将该变量设置为 localhost
。在云端,你将其设置为引用一个 Kubernetes Service,该服务将数据库组件公开给你的集群。这使得你可以在云端获取正在运行的容器镜像,并在需要时在本地调试完全相同的代码。
注意
ConfigMap 不适合存储大量数据。ConfigMap 中存储的数据不能超过 1 MiB。如果需要存储超过此限制的设置,你可能需要考虑挂载一个卷,或者使用单独的数据库或文件服务。ConfigMap 对象
ConfigMap 是一个API 对象,它允许你存储配置以供其他对象使用。与大多数具有 spec
的 Kubernetes 对象不同,ConfigMap 具有 data
和 binaryData
字段。这些字段接受键值对作为其值。data
字段和 binaryData
字段都是可选的。data
字段旨在包含 UTF-8 字符串,而 binaryData
字段旨在包含 base64 编码的二进制数据。
ConfigMap 的名称必须是有效的 DNS 子域名。
data
或 binaryData
字段下的每个键必须由字母数字字符、-
、_
或 .
组成。存储在 data
中的键不能与 binaryData
字段中的键重叠。
从 v1.19 开始,你可以向 ConfigMap 定义添加一个 immutable
字段,以创建不可变 ConfigMap。
ConfigMaps 和 Pods
你可以编写一个引用 ConfigMap 的 Pod spec
,并根据 ConfigMap 中的数据配置该 Pod 中的容器。Pod 和 ConfigMap 必须位于相同的命名空间中。
这是一个 ConfigMap 示例,其中一些键具有单个值,另一些键的值看起来像配置格式的片段。
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
# property-like keys; each key maps to a simple value
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# file-like keys
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
有四种不同的方式可以使用 ConfigMap 来配置 Pod 中的容器
- 在容器命令和参数中
- 作为容器的环境变量
- 在只读卷中添加一个文件,供应用程序读取
- 编写代码在 Pod 内部运行,使用 Kubernetes API 读取 ConfigMap
这些不同的方法适用于对所消耗数据进行不同建模的方式。对于前三种方法,当 kubelet 启动 Pod 的容器时,它会使用 ConfigMap 中的数据。
第四种方法意味着你必须编写代码来读取 ConfigMap 及其数据。但是,由于你直接使用 Kubernetes API,你的应用程序可以订阅在 ConfigMap 更改时获取更新,并在发生更改时做出反应。通过直接访问 Kubernetes API,这种技术还允许你访问不同命名空间中的 ConfigMap。
这是一个 Pod 示例,它使用 game-demo
中的值来配置 Pod
apiVersion: v1
kind: Pod
metadata:
name: configmap-demo-pod
spec:
containers:
- name: demo
image: alpine
command: ["sleep", "3600"]
env:
# Define the environment variable
- name: PLAYER_INITIAL_LIVES # Notice that the case is different here
# from the key name in the ConfigMap.
valueFrom:
configMapKeyRef:
name: game-demo # The ConfigMap this value comes from.
key: player_initial_lives # The key to fetch.
- name: UI_PROPERTIES_FILE_NAME
valueFrom:
configMapKeyRef:
name: game-demo
key: ui_properties_file_name
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
# You set volumes at the Pod level, then mount them into containers inside that Pod
- name: config
configMap:
# Provide the name of the ConfigMap you want to mount.
name: game-demo
# An array of keys from the ConfigMap to create as files
items:
- key: "game.properties"
path: "game.properties"
- key: "user-interface.properties"
path: "user-interface.properties"
ConfigMap 不区分单行属性值和多行文件式值。重要的是 Pod 和其他对象如何使用这些值。
对于这个示例,定义一个卷并将其挂载到 demo
容器内作为 /config
会创建两个文件:/config/game.properties
和 /config/user-interface.properties
,尽管 ConfigMap 中有四个键。这是因为 Pod 定义在 volumes
部分指定了一个 items
数组。如果你完全省略 items
数组,ConfigMap 中的每个键都会变成一个与键同名的文件,你将得到 4 个文件。
使用 ConfigMaps
ConfigMaps 可以作为数据卷挂载。ConfigMaps 也可以由系统的其他部分使用,而无需直接暴露给 Pod。例如,ConfigMaps 可以保存系统其他部分应用于配置的数据。
使用 ConfigMaps 最常见的方式是配置在同一命名空间中的 Pod 中运行的容器的设置。你也可以单独使用 ConfigMap。
例如,你可能会遇到插件或操作员,它们根据 ConfigMap 调整其行为。
从 Pod 中将 ConfigMap 作为文件使用
要在 Pod 的卷中消耗 ConfigMap:
- 创建 ConfigMap 或使用现有 ConfigMap。多个 Pod 可以引用同一个 ConfigMap。
- 修改你的 Pod 定义,在
.spec.volumes[]
下添加一个卷。给卷命名,并设置.spec.volumes[].configMap.name
字段以引用你的 ConfigMap 对象。 - 向需要 ConfigMap 的每个容器添加一个
.spec.containers[].volumeMounts[]
。指定.spec.containers[].volumeMounts[].readOnly = true
和.spec.containers[].volumeMounts[].mountPath
到一个未使用的目录名,你希望 ConfigMap 出现在其中。 - 修改你的镜像或命令行,以便程序在该目录中查找文件。ConfigMap
data
映射中的每个键都成为mountPath
下的文件名。
这是一个在卷中挂载 ConfigMap 的 Pod 示例
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
configMap:
name: myconfigmap
你想要使用的每个 ConfigMap 都需要在 .spec.volumes
中引用。
如果 Pod 中有多个容器,则每个容器都需要自己的 volumeMounts
块,但每个 ConfigMap 只需要一个 .spec.volumes
。
挂载的 ConfigMap 会自动更新
当卷中当前使用的 ConfigMap 更新时,投影的键也会最终更新。kubelet 在每次定期同步时都会检查挂载的 ConfigMap 是否是新的。然而,kubelet 使用其本地缓存来获取 ConfigMap 的当前值。缓存的类型可以通过 KubeletConfiguration 结构中的 configMapAndSecretChangeDetectionStrategy
字段进行配置。ConfigMap 可以通过 watch(默认)、基于 ttl 或通过将所有请求直接重定向到 API 服务器进行传播。因此,从 ConfigMap 更新到新键投影到 Pod 的总延迟可能与 kubelet 同步周期 + 缓存传播延迟一样长,其中缓存传播延迟取决于所选的缓存类型(它分别等于 watch 传播延迟、缓存的 ttl 或零)。
作为环境变量使用的 ConfigMaps 不会自动更新,需要重启 Pod。
注意
使用 ConfigMap 作为 subPath 卷挂载的容器将不会收到 ConfigMap 更新。将 ConfigMap 用作环境变量
要在 Pod 中将 ConfigMap 用于环境变量:
- 对于 Pod 规范中的每个容器,为每个要使用的 ConfigMap 键将一个环境变量添加到
env[].valueFrom.configMapKeyRef
字段。 - 修改你的镜像和/或命令行,以便程序在指定的en环境变量中查找值。
这是一个将 ConfigMap 定义为 Pod 环境变量的示例
以下 ConfigMap (myconfigmap.yaml) 存储了两个属性:username 和 access_level
apiVersion: v1
kind: ConfigMap
metadata:
name: myconfigmap
data:
username: k8s-admin
access_level: "1"
以下命令将创建 ConfigMap 对象
kubectl apply -f myconfigmap.yaml
以下 Pod 将 ConfigMap 的内容作为环境变量使用
apiVersion: v1
kind: Pod
metadata:
name: env-configmap
spec:
containers:
- name: app
command: ["/bin/sh", "-c", "printenv"]
image: busybox:latest
envFrom:
- configMapRef:
name: myconfigmap
envFrom
字段指示 Kubernetes 从其嵌套的源创建环境变量。内部的 configMapRef
通过名称引用 ConfigMap,并选择其所有键值对。将 Pod 添加到集群,然后检索其日志以查看 printenv 命令的输出。这应该确认 ConfigMap 中的两个键值对已设置为环境变量
kubectl apply -f env-configmap.yaml
kubectl logs pod/ env-configmap
输出类似于:
...
username: "k8s-admin"
access_level: "1"
...
有时,Pod 不需要访问 ConfigMap 中的所有值。例如,你可能有一个只使用 ConfigMap 中的 username 值的其他 Pod。对于这种情况,你可以改用 env.valueFrom
语法,它允许你选择 ConfigMap 中的单个键。环境变量的名称也可以与 ConfigMap 中的键不同。例如
apiVersion: v1
kind: Pod
metadata:
name: env-configmap
spec:
containers:
- name: envars-test-container
image: nginx
env:
- name: CONFIGMAP_USERNAME
valueFrom:
configMapKeyRef:
name: myconfigmap
key: username
在此清单创建的 Pod 中,你将看到环境变量 CONFIGMAP_USERNAME
设置为 ConfigMap 中 username
的值。ConfigMap 数据中的其他键不会复制到环境中。
需要注意的是,Pod 中环境变量名称允许的字符范围是受限的。如果任何键不符合规则,这些键将不会提供给你的容器,但 Pod 仍允许启动。
不可变 ConfigMap
Kubernetes v1.21 [stable]
Kubernetes 特性“不可变 Secret 和 ConfigMap”提供了一个选项,可以将单个 Secret 和 ConfigMap 设置为不可变。对于广泛使用 ConfigMap 的集群(至少有数万个独特的 ConfigMap 到 Pod 挂载),阻止对其数据进行更改具有以下优点:
- 保护你免受可能导致应用程序中断的意外(或不必要的)更新
- 通过关闭标记为不可变的 ConfigMap 的监视,显著减少 kube-apiserver 的负载,从而提高集群性能。
你可以通过将 immutable
字段设置为 true
来创建不可变 ConfigMap。例如
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
...
immutable: true
一旦 ConfigMap 被标记为不可变,就不可能撤销此更改或修改 data
或 binaryData
字段的内容。你只能删除并重新创建 ConfigMap。由于现有 Pod 维护指向已删除 ConfigMap 的挂载点,建议重新创建这些 Pod。
下一步
- 阅读有关Secrets的信息。
- 阅读配置 Pod 以使用 ConfigMap。
- 阅读有关更改 ConfigMap(或任何其他 Kubernetes 对象)的信息
- 阅读《The Twelve-Factor App》,以了解将代码与配置分离的动机。