在Kubernetes中使用Configmap

在Kubernetes中使用Configmap

Posted by Brian on Monday, October 2, 2023

configmap资源对象是以Kye value形式的健值对来保存不机密的数据。这些数据可以在Pod的环境变量、命令行参数、或者存储卷的配置文件中使用。

注意configmap 并不是设计用来存储大量数据的。如果数据超过了1MB ,请考虑使用挂载存储卷,或者使用独立的数据库或服务。

创建

Confgmap 只有 databinaryData 与两个可选字段来描述所要存储的数据。

如下的使用将创建一个 configmap (game-demo.yaml)

apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # Key=>value 形式声名
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # 配置文件类型声明
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5        
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true      

执行如下命令,将在 default 命令空间下创建一个命为 game-demo的 configmap

kubectl create -f game-demo.yaml
kubectl get configmaps game-demo --output yaml

使用

在Pod中有如下四种方式来使用已创建的Configmap

  • 环境变量
  • 命令行参数
  • 用作配置文件挂载到Pod中
  • 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap

正常来说我只前三种方式会使用得比较多一些。所以这里着重介绍一下前三种的使用方式。

接下来我们通过一个Pod来演示相应的使用方法:(demo.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
spec:
  containers:
    - name: demo
      image: arm64v8/alpine:3.18
      command: ["sleep", "3600"]
      env:
        # 定义环境变量
        - name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
          valueFrom:
            configMapKeyRef:
              name: game-demo           # 这个值来自 ConfigMap
              key: player_initial_lives # 需要取值的键
        - name: UI_PROPERTIES_FILE_NAME
          valueFrom:
            configMapKeyRef:
              name: game-demo
              key: ui_properties_file_name
      volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
  volumes:
  # 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
  - name: config
    configMap:
      # 提供你想要挂载的 ConfigMap 的名字
      name: game-demo
      # 来自 ConfigMap 的一组键,将被创建为文件
      items:
      - key: "game.properties"
        path: "game.properties"
      - key: "user-interface.properties"
        path: "user-interface.properties"

在这个示例中,定义了一个卷 config 并将它作为/config 文件夹挂载到容器中。创建两个文件 game.properties, game.properties, 可以看到们在 configmap 中有四个key。这里我们只使用了 items 来限定只要特定的key。如没有 items 字段,你将会得到四个以key为名称的文件。 执行如下命令创建Pod并验证:

kubectl create -f demo.yaml

# 验证
kubectl exec -it -n default configmap-demo-pod /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # echo $PLAYER_INITIAL_LIVES
3
/ # echo $UI_PROPERTIES_FILE_NAME
user-interface.properties
/ # tree /config
/config
├── game.properties -> ..data/game.properties
└── user-interface.properties -> ..data/user-interface.properties
/ # cat /config/game.properties
enemy.types=aliens,monsters
player.maximum-lives=5
/ # cat /config/user-interface.properties
color.good=purple
color.bad=yellow
allow.textmode=true

可以看到不管是 环境变量,还是配件文件都使用了我们创建configmap 的值。也跟预期是一致的。

热更新

这里有一个问题。如果我们的configmap更新了。使用了该configmap的Pod它们的表现是怎样的呢?实际上Kubernetes 对于 configmap 的更新有以下的特点:

  • 以环境变量的方式使用 configmap 数据不会被自动更新。如果需要更新必须要重启 pod
  • 使用 configmap 作为 subPath 卷挂载的容器不会收到 ConfigMap 的更新
  • 当使用的 configmap 更新时,所投射的键也会被自动更新。 kubelet 组件会在每次周期性同步时检查所挂载的 ConfigMap 是否为最新。 不过,kubelet 使用的是其本地的高速缓存来获得 ConfigMap 的当前值。 高速缓存的类型可以通过 KubeletConfiguration 结构. 的 configMapAndSecretChangeDetectionStrategy 字段来配置。
  • ConfigMap 既可以通过 watch 操作实现内容传播(默认形式),也可实现基于 TTL 的缓存,还可以直接经过所有请求重定向到 API 服务器。 因此,从 ConfigMap 被更新的那一刻算起,到新的主键被投射到 Pod 中去, 这一时间跨度可能与 kubelet 的同步周期加上高速缓存的传播延迟相等。 这里的传播延迟取决于所选的高速缓存类型 (分别对应 watch 操作的传播延迟、高速缓存的 TTL 时长或者 0)。

以下示例为你演示 configmap 更新后 Pod 中挂载的卷是如何进行更新的。

使用以下命令进行容器:

kubectl exec -it -n default configmap-demo-pod /bin/sh
/ # cat /config/game.properties
enemy.types=aliens,monsters
player.maximum-lives

修改 configmap 如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # Key=>value 形式声名
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # 配置文件类型声明
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5
    player.minimum-lives=15
    log_level=debug    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true    

增加了两个字段 player.minimum-liveslog_level,执行如下命令更新 configmap

kubectl apply -f game-demo.yaml

更新完成之后进入容器查看 /config/game.properties 的内容,大概几秒后就能看到我们的增加的内容了。输出如下:

/ # cat /config/game.properties
enemy.types=aliens,monsters
player.maximum-lives=5
player.minimum-lives=15
log_level=debug

清理

kubectl delete -f game-demo.yaml
kubectl delete -f demo.yaml

至此,有关于 configmap 的创建使用就告一段落了。在使用 configmap 的过程中。 我建议使用文件的方式来创建我们的 configmap。而不是使用命令。配件文件的热更新使用场景。我们可以在配置更新重启服务而不是重启Pod。毕竟重启Pod的时间还是挺久的。最佳实践就是在集群中有一个 Frpc 服务。当我们更新了 frpc.ini 配置文件后,fprc 服务自动重启。这样做的好处是服务在重启的时候我们的链接是不会断开的。如果是重启Pod。新的Pod在正常运行之前我们的Frpc服务将是不可用的。