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

ConfigMap 和 Pod

您可以编写一个 Pod spec,该规范引用 ConfigMap,并根据 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。

这是一个使用game-demo中的值来配置 Pod 的示例 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 和其他对象如何使用这些值。

在本例中,定义一个卷并将其作为 /config 挂载到 demo 容器内部会创建两个文件,/config/game.properties/config/user-interface.properties,即使 ConfigMap 中有四个键。这是因为 Pod 定义在 volumes 部分指定了一个 items 数组。如果完全省略 items 数组,则 ConfigMap 中的每个键都会成为一个与键同名的文件,您将得到 4 个文件。

使用 ConfigMap

ConfigMap 可以作为数据卷挂载。ConfigMap 也可以被系统的其他部分使用,而无需直接暴露给 Pod。例如,ConfigMap 可以保存系统的其他部分应该用于配置的数据。

使用 ConfigMap 的最常见方式是配置在同一命名空间中的 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 可以通过监视(默认)、基于 TTL 或将所有请求直接重定向到 API 服务器来传播。因此,从 ConfigMap 更新到新键投影到 Pod 的总延迟可能长达 kubelet 同步周期 + 缓存传播延迟,其中缓存传播延迟取决于选择的缓存类型(它分别等于监视传播延迟、缓存的 TTL 或零)。

作为环境变量使用的 ConfigMap 不会自动更新,需要重启 Pod。

将 ConfigMap 用作环境变量

要在 Pod 中的 环境变量 中使用 ConfigMap:

  1. 对于 Pod 规范中的每个容器,为要使用的每个 ConfigMap 键向 env[].valueFrom.configMapKeyRef 字段添加一个环境变量。
  2. 修改您的镜像和/或命令行,以便程序在指定的环境变量中查找值。

这是一个将 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 中的所有值。例如,您可能还有另一个 Pod,它仅使用 ConfigMap 中的 username 值。对于此用例,您可以使用 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 [稳定]

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)