ConfigMap

ConfigMap 是一个 API 对象,用于以键值对的形式存储非机密数据。Pod 可以将 ConfigMap 作为环境变量、命令行参数或 中的配置文件使用。

ConfigMap 允许你将特定环境的配置与你的容器镜像解耦,从而使你的应用程序易于移植。

动机

使用 ConfigMap 将配置数据与应用程序代码分开设置。

例如,假设你正在开发一个应用程序,你可以在自己的计算机上运行(用于开发),也可以在云端运行(处理实际流量)。你编写的代码会查找名为 DATABASE_HOST 的环境变量。在本地,你将该变量设置为 localhost。在云端,你将其设置为引用一个 Kubernetes Service,该服务将数据库组件公开给你的集群。这使得你可以在云端获取正在运行的容器镜像,并在需要时在本地调试完全相同的代码。

ConfigMap 对象

ConfigMap 是一个API 对象,它允许你存储配置以供其他对象使用。与大多数具有 spec 的 Kubernetes 对象不同,ConfigMap 具有 databinaryData 字段。这些字段接受键值对作为其值。data 字段和 binaryData 字段都是可选的。data 字段旨在包含 UTF-8 字符串,而 binaryData 字段旨在包含 base64 编码的二进制数据。

ConfigMap 的名称必须是有效的 DNS 子域名

databinaryData 字段下的每个键必须由字母数字字符、-_. 组成。存储在 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 中的容器

  1. 在容器命令和参数中
  2. 作为容器的环境变量
  3. 在只读卷中添加一个文件,供应用程序读取
  4. 编写代码在 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:

  1. 创建 ConfigMap 或使用现有 ConfigMap。多个 Pod 可以引用同一个 ConfigMap。
  2. 修改你的 Pod 定义,在 .spec.volumes[] 下添加一个卷。给卷命名,并设置 .spec.volumes[].configMap.name 字段以引用你的 ConfigMap 对象。
  3. 向需要 ConfigMap 的每个容器添加一个 .spec.containers[].volumeMounts[]。指定 .spec.containers[].volumeMounts[].readOnly = true.spec.containers[].volumeMounts[].mountPath 到一个未使用的目录名,你希望 ConfigMap 出现在其中。
  4. 修改你的镜像或命令行,以便程序在该目录中查找文件。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 用作环境变量

要在 Pod 中将 ConfigMap 用于环境变量

  1. 对于 Pod 规范中的每个容器,为每个要使用的 ConfigMap 键将一个环境变量添加到 env[].valueFrom.configMapKeyRef 字段。
  2. 修改你的镜像和/或命令行,以便程序在指定的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 被标记为不可变,就不可能撤销此更改或修改 databinaryData 字段的内容。你只能删除并重新创建 ConfigMap。由于现有 Pod 维护指向已删除 ConfigMap 的挂载点,建议重新创建这些 Pod。

下一步

最后修改于 2024 年 9 月 11 日下午 6:37(太平洋标准时间):在文档中添加 envFrom 详细信息 (#47709) (2ccaf064f8)