configmap资源对象是以Kye value形式的健值对来保存不机密的数据。这些数据可以在Pod的环境变量、命令行参数、或者存储卷的配置文件中使用。
注意configmap 并不是设计用来存储大量数据的。如果数据超过了1MB ,请考虑使用挂载存储卷,或者使用独立的数据库或服务。
创建
Confgmap 只有 data
与 binaryData
与两个可选字段来描述所要存储的数据。
如下的使用将创建一个 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-lives
与 log_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服务将是不可用的。