K8S的config-map

通过作为卷挂载的 ConfigMap 更新配置

使用 kubectl create configmap 命令基于字面值创建一个 ConfigMap:

kubectl create configmap sport --from-literal=sport=football

下面是一个 Deployment 清单示例,其中 ConfigMap sport 作为挂载到 Pod 的唯一容器中。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-volume
  labels:
    app.kubernetes.io/name: configmap-volume
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: configmap-volume
  template:
    metadata:
      labels:
        app.kubernetes.io/name: configmap-volume
    spec:
      containers:
        - name: alpine
          image: alpine:3
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) My preferred sport is $(cat /etc/config/sport)";
              sleep 10; done;
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config-volume
              mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: sport

创建此 Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-configmap-as-volume.yaml

检查此 Deployment 的 Pod 以确保它们已就绪 (通过选择算符进行匹配):

kubectl get pods --selector=app.kubernetes.io/name=configmap-volume

你应该会看到类似以下的输出:

NAME                                READY   STATUS    RESTARTS   AGE
configmap-volume-6b976dfdcf-qxvbm   1/1     Running   0          72s
configmap-volume-6b976dfdcf-skpvm   1/1     Running   0          72s
configmap-volume-6b976dfdcf-tbc6r   1/1     Running   0          72s

在运行这些 Pod 之一的每个节点上,kubelet 获取该 ConfigMap 的数据,并将其转换为本地卷中的文件。 然后,kubelet 按照 Pod 模板中指定的方式将该卷挂载到容器中。 在该容器中运行的代码从文件中加载信息,并使用它将报告打印到标准输出。 你可以通过查看该 Deployment 中其中一个 Pod 的日志来检查此报告:

# 选择一个属于该 Deployment 的 Pod,并查看其日志
kubectl logs deployments/configmap-volume

你应该会看到类似以下的输出:

Found 3 pods, using pod/configmap-volume-76d9c5678f-x5rgj
Thu Jan  4 14:06:46 UTC 2024 My preferred sport is football
Thu Jan  4 14:06:56 UTC 2024 My preferred sport is football
Thu Jan  4 14:07:06 UTC 2024 My preferred sport is football
Thu Jan  4 14:07:16 UTC 2024 My preferred sport is football
Thu Jan  4 14:07:26 UTC 2024 My preferred sport is football

编辑 ConfigMap:

kubectl edit configmap sport

在出现的编辑器中,将键 sport 的值从 football 变更为 cricket。 保存你的变更。kubectl 工具会相应地更新 ConfigMap(如果报错,请重试)。

以下是你编辑后该清单可能的样子:

apiVersion: v1
data:
  sport: cricket
kind: ConfigMap
# 你可以保留现有的 metadata 不变。
# 你将看到的值与本例的值不会完全一样。
metadata:
  creationTimestamp: "2024-01-04T14:05:06Z"
  name: sport
  namespace: default
  resourceVersion: "1743935"
  uid: 024ee001-fe72-487e-872e-34d6464a8a23

你应该会看到以下输出:

configmap/sport edited

查看属于此 Deployment 的 Pod 之一的日志(并跟踪最新写入的条目):

kubectl logs deployments/configmap-volume --follow

几秒钟后,你应该会看到日志输出中的如下变化:

Thu Jan  4 14:11:36 UTC 2024 My preferred sport is football
Thu Jan  4 14:11:46 UTC 2024 My preferred sport is football
Thu Jan  4 14:11:56 UTC 2024 My preferred sport is football
Thu Jan  4 14:12:06 UTC 2024 My preferred sport is cricket
Thu Jan  4 14:12:16 UTC 2024 My preferred sport is cricket

当你有一个 ConfigMap 通过 configMap 卷或 projected 卷映射到运行中的 Pod, 并且你更新了该 ConfigMap 时,运行中的 Pod 几乎会立即更新。 但是,你的应用只有在编写为轮询变更或监视文件更新时才能看到变更。 启动时一次性加载其配置的应用将不会注意到变更。

说明:

从更新 ConfigMap 的那一刻到将新的键投射到 Pod 的那一刻,整个延迟可能与 kubelet 同步周期相同。

通过 ConfigMap 更新 Pod 的环境变量

使用 kubectl create configmap 命令基于字面值创建一个 ConfigMap:

kubectl create configmap fruits --from-literal=fruits=apples

下面是一个 Deployment 清单的示例,包含一个通过 ConfigMap fruits 配置的环境变量。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-env-var
  labels:
    app.kubernetes.io/name: configmap-env-var
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: configmap-env-var
  template:
    metadata:
      labels:
        app.kubernetes.io/name: configmap-env-var
    spec:
      containers:
        - name: alpine
          image: alpine:3
          env:
            - name: FRUITS
              valueFrom:
                configMapKeyRef:
                  key: fruits
                  name: fruits
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) The basket is full of $FRUITS";
                sleep 10; done;
          ports:
            - containerPort: 80

创建此 Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-configmap-as-envvar.yaml

检查此 Deployment 的 Pod 以确保它们已就绪(通过选择算符进行匹配):

kubectl get pods --selector=app.kubernetes.io/name=configmap-env-var

你应该会看到类似以下的输出:

NAME                                 READY   STATUS    RESTARTS   AGE
configmap-env-var-59cfc64f7d-74d7z   1/1     Running   0          46s
configmap-env-var-59cfc64f7d-c4wmj   1/1     Running   0          46s
configmap-env-var-59cfc64f7d-dpr98   1/1     Running   0          46s

ConfigMap 中的键值对被配置为 Pod 容器中的环境变量。 通过查看属于该 Deployment 的某个 Pod 的日志来检查这一点。

kubectl logs deployment/configmap-env-var

你应该会看到类似以下的输出:

Found 3 pods, using pod/configmap-env-var-7c994f7769-l74nq
Thu Jan  4 16:07:06 UTC 2024 The basket is full of apples
Thu Jan  4 16:07:16 UTC 2024 The basket is full of apples
Thu Jan  4 16:07:26 UTC 2024 The basket is full of apples

编辑 ConfigMap:

kubectl edit configmap fruits

在出现的编辑器中,将键 fruits 的值从 apples 变更为 mangoes。 保存你的变更。kubectl 工具会相应地更新 ConfigMap(如果报错,请重试)。

以下是你编辑后该清单可能的样子:

apiVersion: v1
data:
  fruits: mangoes
kind: ConfigMap
# 你可以保留现有的 metadata 不变。
# 你将看到的值与本例的值不会完全一样。
metadata:
  creationTimestamp: "2024-01-04T16:04:19Z"
  name: fruits
  namespace: default
  resourceVersion: "1749472"

你应该看到以下输出:

configmap/fruits edited

查看此 Deployment 的日志,并观察几秒钟的输出:

# 如上所述,输出不会有变化
kubectl logs deployments/configmap-env-var --follow

请注意,即使你编辑了 ConfigMap,输出仍然没有变化:

Thu Jan  4 16:12:56 UTC 2024 The basket is full of apples
Thu Jan  4 16:13:06 UTC 2024 The basket is full of apples
Thu Jan  4 16:13:16 UTC 2024 The basket is full of apples
Thu Jan  4 16:13:26 UTC 2024 The basket is full of apples

说明:

尽管 ConfigMap 中的键的取值已经变更,Pod 中的环境变量仍然显示先前的值。 这是因为当源数据变更时,在 Pod 内运行的进程的环境变量不会被更新; 如果你想强制更新,需要让 Kubernetes 替换现有的 Pod。新 Pod 将使用更新的信息来运行。

你可以触发该替换。使用 kubectl rollout 为 Deployment 执行上线操作:

# 触发上线操作
kubectl rollout restart deployment configmap-env-var

# 等待上线操作完成
kubectl rollout status deployment configmap-env-var --watch=true

接下来,检查 Deployment:

kubectl get deployment configmap-env-var

你应该会看到类似以下的输出:

NAME                READY   UP-TO-DATE   AVAILABLE   AGE
configmap-env-var   3/3     3            3           12m

检查 Pod:

kubectl get pods --selector=app.kubernetes.io/name=configmap-env-var

上线操作会导致 Kubernetes 为 Deployment 新建一个 ReplicaSet; 这意味着现有的 Pod 最终会终止,并创建新的 Pod。几秒钟后,你应该会看到类似以下的输出:

NAME                                 READY   STATUS        RESTARTS   AGE
configmap-env-var-6d94d89bf5-2ph2l   1/1     Running       0          13s
configmap-env-var-6d94d89bf5-74twx   1/1     Running       0          8s
configmap-env-var-6d94d89bf5-d5vx8   1/1     Running       0          11s

说明:

请等待旧的 Pod 完全终止后再进行下一步。

查看此 Deployment 中某个 Pod 的日志:

# 选择属于 Deployment 的一个 Pod,并查看其日志
kubectl logs deployment/configmap-env-var

你应该会看到类似以下的输出:

Found 3 pods, using pod/configmap-env-var-6d9ff89fb6-bzcf6
Thu Jan  4 16:30:35 UTC 2024 The basket is full of mangoes
Thu Jan  4 16:30:45 UTC 2024 The basket is full of mangoes
Thu Jan  4 16:30:55 UTC 2024 The basket is full of mangoes

这个场景演示了在 Pod 中如何更新从 ConfigMap 派生的环境变量。ConfigMap 值的变更在随后的上线操作期间被应用到 Pod。如果 Pod 由于其他原因(例如 Deployment 扩容)被创建, 那么新 Pod 也会使用最新的配置值; 如果你不触发上线操作,你可能会发现你的应用在运行过程中混用了新旧环境变量值。(也即是说config-map不支持热更新)

在包含边车容器的 Pod 中通过 ConfigMap 更新配置

要重现上述场景,可以使用边车容器作为辅助容器来写入 HTML 文件。由于边车容器在概念上是一个 Init 容器,因此保证会在主要 Web 服务器容器启动之前启动。 这确保了当 Web 服务器准备好提供服务时,HTML 文件始终可用。

如果你从前一个场景继续操作,你可以在此场景中重用名为 color 的 ConfigMap。 如果你是独立执行此场景,请使用 kubectl create configmap 命令基于字面值创建一个 ConfigMap:

kubectl create configmap color --from-literal=color=blue

以下是一个 Deployment 清单示例,该 Deployment 管理一组 Pod,每个 Pod 有一个主容器和一个边车容器。 这两个容器共享一个 emptyDir 卷并使用此卷来通信。主容器运行 Web 服务器(NGINX)。 在 Web 服务器容器中共享卷的挂载路径是 /usr/share/nginx/html。 第二个容器是基于 Alpine Linux 作为辅助容器的边车容器。对于这个辅助容器,emptyDir 卷被挂载在 /pod-data。 边车容器写入一个 HTML 文件,其内容基于 ConfigMap。Web 服务器容器通过 HTTP 提供此 HTML 文件。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: configmap-sidecar-container
  labels:
    app.kubernetes.io/name: configmap-sidecar-container
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: configmap-sidecar-container
  template:
    metadata:
      labels:
        app.kubernetes.io/name: configmap-sidecar-container
    spec:
      volumes:
        - name: shared-data
          emptyDir: {}
        - name: config-volume
          configMap:
            name: color
      containers:
        - name: nginx
          image: nginx
          volumeMounts:
            - name: shared-data
              mountPath: /usr/share/nginx/html
      initContainers:
        - name: alpine
          image: alpine:3
          restartPolicy: Always
          volumeMounts:
            - name: shared-data
              mountPath: /pod-data
            - name: config-volume
              mountPath: /etc/config
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) My preferred color is $(cat /etc/config/color)" > /pod-data/index.html;
              sleep 10; done;

创建此 Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-configmap-and-sidecar-container.yaml

检查此 Deployment 的 Pod 以确保它们已就绪(通过选择算符进行匹配):

kubectl get pods --selector=app.kubernetes.io/name=configmap-sidecar-container

你应该会看到类似以下的输出:

NAME                                           READY   STATUS    RESTARTS   AGE
configmap-sidecar-container-5fb59f558b-87rp7   2/2     Running   0          94s
configmap-sidecar-container-5fb59f558b-ccs7s   2/2     Running   0          94s
configmap-sidecar-container-5fb59f558b-wnmgk   2/2     Running   0          94s

公开 Deployment(kubectl 工具会为你创建一个 Service):

kubectl expose deployment configmap-sidecar-container --name=configmap-sidecar-service --port=8081 --target-port=80

使用 kubectl 转发端口:

# 此命令将在后台运行
kubectl port-forward service/configmap-sidecar-service 8081:8081 &

访问服务:

curl http://localhost:8081

你应该看到类似以下的输出:

Sat Feb 17 13:09:05 UTC 2024 My preferred color is blue

编辑 ConfigMap:

kubectl edit configmap color

在出现的编辑器中,将键 color 的值从 blue 变更为 green。 保存你的变更。kubectl 工具会相应地更新 ConfigMap(如果报错,请重试)。

以下是你编辑后该清单可能的样子:

apiVersion: v1
data:
  color: green
kind: ConfigMap
# 你可以保留现有的 metadata 不变。
# 你将看到的值与本例的值不会完全一样。
metadata:
  creationTimestamp: "2024-02-17T12:20:30Z"
  name: color
  namespace: default
  resourceVersion: "1054"
  uid: e40bb34c-58df-4280-8bea-6ed16edccfaa

循环访问服务 URL 几秒钟。

# 当你满意时可以取消此操作 (Ctrl-C)
while true; do curl --connect-timeout 7.5 http://localhost:8081; sleep 10; done

你应该会看到如下的输出变化:

Sat Feb 17 13:12:35 UTC 2024 My preferred color is blue
Sat Feb 17 13:12:45 UTC 2024 My preferred color is blue
Sat Feb 17 13:12:55 UTC 2024 My preferred color is blue
Sat Feb 17 13:13:05 UTC 2024 My preferred color is blue
Sat Feb 17 13:13:15 UTC 2024 My preferred color is green
Sat Feb 17 13:13:25 UTC 2024 My preferred color is green
Sat Feb 17 13:13:35 UTC 2024 My preferred color is green
 

通过作为卷挂载的不可变 ConfigMap 更新配置

说明:

不可变 ConfigMap 专门用于恒定且预期不会随时间变化的配置。 将 ConfigMap 标记为不可变可以提高性能,因为 kubelet 不会监视变更。

如果你确实需要进行变更,你应计划:

  • 变更 ConfigMap 的名称,并转而运行引用新名称的 Pod
  • 替换集群中之前运行使用旧值的 Pod 的所有节点
  • 在任何之前加载过旧 ConfigMap 的节点上重新启动 kubelet

以下是一个不可变 ConfigMap的示例清单。

apiVersion: v1
data:
  company_name: "ACME, Inc." # 虚构的公司名称
kind: ConfigMap
immutable: true
metadata:
  name: company-name-20150801

创建不可变 ConfigMap:

kubectl apply -f https://k8s.io/examples/configmap/immutable-configmap.yaml

下面是一个 Deployment 清单示例,其中不可变 ConfigMap company-name-20150801 作为挂载到 Pod 的唯一容器中。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: immutable-configmap-volume
  labels:
    app.kubernetes.io/name: immutable-configmap-volume
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: immutable-configmap-volume
  template:
    metadata:
      labels:
        app.kubernetes.io/name: immutable-configmap-volume
    spec:
      containers:
        - name: alpine
          image: alpine:3
          command:
            - /bin/sh
            - -c
            - while true; do echo "$(date) The name of the company is $(cat /etc/config/company_name)";
              sleep 10; done;
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config-volume
              mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: company-name-20150801

创建此 Deployment:

kubectl apply -f https://k8s.io/examples/deployments/deployment-with-immutable-configmap-as-volume.yaml

检查此 Deployment 的 Pod 以确保它们已就绪(通过选择算符进行匹配):

kubectl get pods --selector=app.kubernetes.io/name=immutable-configmap-volume

你应该看到类似以下的输出:

NAME                                          READY   STATUS    RESTARTS   AGE
immutable-configmap-volume-78b6fbff95-5gsfh   1/1     Running   0          62s
immutable-configmap-volume-78b6fbff95-7vcj4   1/1     Running   0          62s
immutable-configmap-volume-78b6fbff95-vdslm   1/1     Running   0          62s

Pod 的容器引用 ConfigMap 中所定义的数据,并使用它将报告打印到标准输出。 你可以通过查看 Deployment 中某个 Pod 的日志来检查此报告:

# 选择属于该 Deployment 的一个 Pod,并查看其日志
kubectl logs deployments/immutable-configmap-volume

你应该会看到类似以下的输出:

Found 3 pods, using pod/immutable-configmap-volume-78b6fbff95-5gsfh
Wed Mar 20 03:52:34 UTC 2024 The name of the company is ACME, Inc.
Wed Mar 20 03:52:44 UTC 2024 The name of the company is ACME, Inc.
Wed Mar 20 03:52:54 UTC 2024 The name of the company is ACME, Inc.

说明:

一旦 ConfigMap 被标记为不可变,就无法撤销此变更,也无法修改 data 或 binaryData 字段的内容。 为了修改使用此配置的 Pod 的行为,你需要创建一个新的不可变 ConfigMap,并编辑 Deployment 以定义一个稍有不同的 Pod 模板,引用新的 ConfigMap。

通过使用下面所示的清单创建一个新的不可变 ConfigMap:

apiVersion: v1
data:
  company_name: "Fiktivesunternehmen GmbH" # 虚构的公司名称
kind: ConfigMap
immutable: true
metadata:
  name: company-name-20240312
kubectl apply -f https://k8s.io/examples/configmap/new-immutable-configmap.yaml

你应该看到类似以下的输出:

configmap/company-name-20240312 created

检查新建的 ConfigMap:

kubectl get configmap

你应该看到输出会同时显示新旧 ConfigMap:

NAME                    DATA   AGE
company-name-20150801   1      22m
company-name-20240312   1      24s

修改 Deployment 以引用新的 ConfigMap。

编辑 Deployment:

kubectl edit deployment immutable-configmap-volume

在出现的编辑器中,更新现有的卷定义以使用新的 ConfigMap。

volumes:
- configMap:
    defaultMode: 420
    name: company-name-20240312 # 更新此字段
  name: config-volume

你应该看到以下输出:

deployment.apps/immutable-configmap-volume edited

这将触发一次上线操作。等待所有先前的 Pod 终止并且新的 Pod 处于就绪状态。

监控 Pod 的状态:

kubectl get pods --selector=app.kubernetes.io/name=immutable-configmap-volume
NAME                                          READY   STATUS        RESTARTS   AGE
immutable-configmap-volume-5fdb88fcc8-29v8n   1/1     Running       0          13s
immutable-configmap-volume-5fdb88fcc8-52ddd   1/1     Running       0          14s
immutable-configmap-volume-5fdb88fcc8-n5jx4   1/1     Running       0          15s
immutable-configmap-volume-78b6fbff95-5gsfh   1/1     Terminating   0          32m
immutable-configmap-volume-78b6fbff95-7vcj4   1/1     Terminating   0          32m
immutable-configmap-volume-78b6fbff95-vdslm   1/1     Terminating   0          32m

最终,你应该会看到类似以下的输出:

NAME                                          READY   STATUS    RESTARTS   AGE
immutable-configmap-volume-5fdb88fcc8-29v8n   1/1     Running   0          43s
immutable-configmap-volume-5fdb88fcc8-52ddd   1/1     Running   0          44s
immutable-configmap-volume-5fdb88fcc8-n5jx4   1/1     Running   0          45s

查看此 Deployment 中某个 Pod 的日志:

# 选择属于此 Deployment 的一个 Pod,并查看其日志
kubectl logs deployment/immutable-configmap-volume

你应该会看到类似下面的输出:

Found 3 pods, using pod/immutable-configmap-volume-5fdb88fcc8-n5jx4
Wed Mar 20 04:24:17 UTC 2024 The name of the company is Fiktivesunternehmen GmbH
Wed Mar 20 04:24:27 UTC 2024 The name of the company is Fiktivesunternehmen GmbH
Wed Mar 20 04:24:37 UTC 2024 The name of the company is Fiktivesunternehmen GmbH

建议一旦所有 Deployment 都迁移到使用新的不可变 ConfigMap,删除旧的 ConfigMap。

kubectl delete configmap company-name-20150801

总结

在 Pod 上作为卷挂载的 ConfigMap 所发生的变更将在后续的 kubelet 同步后无缝生效。

配置为 Pod 环境变量的 ConfigMap 所发生变更将在后续的 Pod 上线操作后生效。

一旦 ConfigMap 被标记为不可变,就无法撤销此变更(你不能将不可变的 ConfigMap 改为可变), 并且你也不能对 data 或 binaryData 字段的内容进行任何变更。你可以删除并重新创建 ConfigMap, 或者你可以创建一个新的不同的 ConfigMap。当你删除 ConfigMap 时, 运行中的容器及其 Pod 将保持对引用了现有 ConfigMap 的任何卷的挂载点。

 
 
 
 

 

 

posted @ 2025-08-05 19:24  王能武  阅读(17)  评论(0)    收藏  举报