文章目录
- 环境
- 概念
- 配置pod使用ConfigMap
- 创建ConfigMap
- kubectl create configmap
- 目录
- 文件
- 自定义key值
- literal值
- 产生器(generator)
- 文件
- 自定义key值
- literal值
- 定义容器环境变量
- 单个ConfigMap
- 多个ConfigMap
- 配置ConfigMap里所有键值对为环境变量
- 在pod命令里使用ConfigMap定义的环境变量
- 添加ConfigMap数据到volume
- 使用ConfigMap的数据填充volume
- 添加ConfigMap的数据到volume的指定路径
- 文件权限
- 可选引用
- mount的ConfigMap会自动更新
- 理解ConfigMap和pod
- 可选的ConfigMap
- 限制
- 示例:使用ConfigMap配置Redis
- 参考
环境
- RHEL 9.3
- Docker Community 24.0.7
- minikube v1.32.0
概念
ConfigMap是一种API对象,用来在键-值对里存储非机密信息。Pod可以以环境变量、命令行参数、volume里的配置文件等方式来消费ConfigMap。
ConfigMap把环境特有的配置和容器image解耦,从而提高了应用的移植性。
注意:ConfigMap不提供保密或加密功能。对于机密数据,应使用Secret或者三方工具。
比如,应用在开发阶段运行在本地电脑上,在生产阶段运行在云上。代码使用了环境变量 DATABASE_HOST
。在本地,可将其设置为 localhost
,在云端,将其设置为指向一个Kubernetes service。
注意:ConfigMap并不是设计为存储大量数据,其容量不能超过1MB。如果数据量大,可以考虑mount一个volume,或者使用数据库/文件。
不像大部分Kubernetes对象有 spec
字段,ConfigMap有 data
和 binaryData
字段,里面存储一些键-值对。二者都是可选的。 data
用来存储UTF-8字符串,而 binaryData
把二进制数据存储为base64编码的字符串。
data
或 binaryData
里的key值必须字母、数字、 -
、 _
、.
组成。二者的key值不能重复。
在pod的 spec
里可以引用ConfigMap,并基于ConfigMap的数据来配置容器。Pod和ConfigMap必须在同一个namespace。
注意:静态pod的 spec
里不能引用ConfigMap和其它任何API对象。
例如:
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里的容器:
- 在容器的
command
和args
里 - 容器的环境变量
- 在只读volume里添加文件,以便应用来读取
- 编写代码,在pod里运行,通过Kubernetes API来读取ConfigMap
对于前三种方法,当 kubelet
启动pod里的容器时,会用到ConfigMap的数据。
第四种方法意味着必须编写代码才能读取ConfigMap。不过,由于直接使用Kubernetes API,因此只要ConfigMap发生更改,应用就能够通过订阅来获取更新,并做出反应。 直接访问Kubernetes API时,可获取其它namespace里的ConfigMap。
例如:
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和其它对象如何消费这些值。
在本例中,定义了一个volume,并将其mount到 demo
容器的 /config
路径,创建了两个文件: /config/game.properties
和 /config/user-interface.properties
。由于在 volumes
处指定了 items
数组,所以只有两个文件。如果省略 items
数组,则ConfigMap里的每个key值都会创建一个同名文件,也就是四个文件。
$ kubectl apply -f cm1.yaml
configmap/game-demo created
$ kubectl apply -f pod1.yaml
pod/configmap-demo-pod created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
configmap-demo-pod 1/1 Running 0 19s
$ kubectl exec configmap-demo-pod -- ls /config
game.properties
user-interface.properties
$ kubectl exec configmap-demo-pod -- cat /config/game.properties
enemy.types=aliens,monsters
player.maximum-lives=5
$ kubectl exec configmap-demo-pod -- cat /config/user-interface.properties
color.good=purple
color.bad=yellow
allow.textmode=true
CongiMap可以mount为数据volume,也可以被系统的其它部分所用,而不是直接暴露给pod。例如,ConfigMap可持有系统其它部分用来配置的数据。
ConfigMap最常见的用法是为同一namespace里的pod的容器提供配置。也可以单独使用ConfigMap。比如,addon或operator基于ConfigMap来调节其行为。
把ConfigMap用作pod的volume:
- 创建或使用已有的ConfigMap。多个pod可引用同一个ConfigMap。
- 修改pod定义,在
.spec.volumes[]
下添加一个volume。为volume命名,并用.spec.volumes[].configMap.name
字段来引用ConfigMap对象。 - 在每个需要ConfigMap的容器里添加
.spec.containers[].volumeMounts[]
,设置.spec.containers[].volumeMounts[].readOnly = true
,设置.spec.containers[].volumeMounts[].mountPath
为一个未使用的目录。 - 修改image或命令行,以便程序能够从该目录找到文件。ConfigMap
data
下的每个key值将成为mountpath
下的一个文件。
例如:
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
。
当volume里ConfigMap有更新时,投射的key最终也会更新。kubelet会在每次周期性同步时,检查所mount的ConfigMap是否为最新。但是,kubelet使用的是本地缓存来获取ConfigMap的当前值。缓存的类型可通过 KubeletConfiguration
结构的 configMapAndSecretChangeDetectionStrategy
字段来配置。ConfigMap可通过watch(默认)、ttl-based(注:Time To Live,生存时间)传播,也可通过把所有请求直接重定向到API服务器来传播。因此,从ConfigMap更新,到新的key被投射到pod里,期间的总体延迟可能等于“kubelet同步周期 + 缓存的传播延迟”。 这里的缓存传播延迟取决于缓存类型(分别对应watch传播延迟、缓存ttl,或者0)。
若ConfigMap用作环境变量,则不会自动更新,需要重启pod。
注意:把ConfigMap用作subPath volume mount的容器,不会收到ConfigMap更新。
Kubernetes v1.21起可将Secret和ConfigMap设置为不可变(immutable)。对于使用大量ConfigMap(比如一万个)的集群,阻止数据变化有如下优点:
- 防止无意的错误更新导致outage
- 提升性能,通过关闭不可变ConfigMap的watch,减少kube-apiserver的负载
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
...
immutable: true
一旦ConfigMap被标记为不可变,则无法再回退,也无法更改 data
或 binaryData
字段的内容。你只能删除并重建ConfigMap。由于现有的pod维护了被删除ConfigMap的挂载点(mount point),建议重建这些 Pods。
配置pod使用ConfigMap
很多应用在初始化或运行期间使用一些配置,并且多数时候,都有调整配置参数的需求。ConfigMap作为Kubernetes的一种机制,把配置注入到应用pod里。
ConfigMap把配置和image内容解耦,提高了容器化应用的可移植性。比如,可以下载并运行同一个image,用于本地开发、系统测试,或者运行实时的用户负载。
创建ConfigMap
可用 kubectl create configmap
或者 kustomization.yaml
里的ConfigMap生成器来创建ConfigMap。
kubectl create configmap
kubectl create configmap <map-name> <data-source>
其中:
<map-name>
:ConfigMap的名字<data-source>
:目录、文件、或者literal值
使用文件时,默认情况下,key是文件的基本名(basename),value是文件内容。
可用 kubectl describe
或者 kubectl get
命令来获取ConfigMap信息。
目录
当基于一个目录创建ConfigMap时,kubectl选择目录里命名符合key值的文件,打包到ConfigMap里。非常规文件将会被忽略(比如: 子目录,symlinks,设备,管道)。
注意:可接受的文件名包括字母、数字、 -
、 _
、 .
。如果目录里有不可接受的文件名,则 kubectl
命令会失败,但不会打印错误。
创建目录 configure-pod-container/configmap
:
mkdir -p configure-pod-container/configmap/
在该目录中,创建 game.properties
文件如下:
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
在该目录中,创建 ui.properties
文件如下:
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
创建ConfigMap game-config
:
$ kubectl create configmap game-config --from-file=configure-pod-container/configmap/
configmap/game-config created
查看ConfigMap game-config
:
$ kubectl describe configmaps game-config
Name: game-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
BinaryData
====
Events: <none>
$ kubectl get configmaps game-config -o yaml
apiVersion: v1
data:
game.properties: |-
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
kind: ConfigMap
metadata:
creationTimestamp: "2024-01-21T10:11:13Z"
name: game-config
namespace: default
resourceVersion: "70852"
uid: 78b6ab26-9c5b-4ee2-bd3a-19122c2125b1
文件
可从一个或多个文件创建ConfigMap。比如:
kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties
kubectl create configmap game-config-3 --from-file=configure-pod-container/configmap/game.properties --from-file=configure-pod-container/configmap/ui.properties
$ kubectl describe configmaps game-config-2
Name: game-config-2
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
BinaryData
====
Events: <none>
$ kubectl describe configmaps game-config-3
Name: game-config-3
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
BinaryData
====
Events: <none>
使用 --from-env-file
选项,从env文件创建ConfigMap。
在 configure-pod-container/configmap
目录里创建文件 game-env-file.properties
如下:
enemies=aliens
lives=3
allowed="true"
# This comment and the empty line above it are ignored
在 configure-pod-container/configmap
目录里创建文件 ui-env-file.properties
如下:
color=purple
textmode=true
how=fairlyNice
创建ConfigMap game-config-env-file
:
kubectl create configmap game-config-env-file \
--from-env-file=configure-pod-container/configmap/game-env-file.properties
查看ConfigMap game-config-env-file
:
$ kubectl get configmap game-config-env-file -o yaml
apiVersion: v1
data:
allowed: '"true"'
enemies: aliens
lives: "3"
kind: ConfigMap
metadata:
creationTimestamp: "2024-01-21T10:27:11Z"
name: game-config-env-file
namespace: default
resourceVersion: "71751"
uid: 25f4bedc-6c9c-4e4e-ba08-ed4aa9e3c7fc
可见,通过 --from-env-file
,properties文件里的每个属性都成为ConfigMap里的一个key。
注意引号会被当作literal的字符。
从Kubernetes v1.23起, kubectl
支持多个 --from-env-file
参数。
kubectl create configmap config-multi-env-files2 \
--from-env-file=configure-pod-container/configmap/game-env-file.properties \
--from-env-file=configure-pod-container/configmap/ui-env-file.properties
$ kubectl get configmap config-multi-env-files2 -o yaml
apiVersion: v1
data:
allowed: '"true"'
color: purple
enemies: aliens
how: fairlyNice
lives: "3"
textmode: "true"
kind: ConfigMap
metadata:
creationTimestamp: "2024-01-21T11:21:20Z"
name: config-multi-env-files2
namespace: default
resourceVersion: "74787"
uid: 508daa61-cceb-472d-a35d-8f548987b8c9
自定义key值
kubectl create configmap game-config-3 --from-file=<my-key-name>=<path-to-file>
其中, <my-key-name>
是自定义的key值。比如:
kubectl create configmap game-config-4 --from-file=game-special-key=configure-pod-container/configmap/game.properties
$ kubectl get configmaps game-config-4 -o yaml
apiVersion: v1
data:
game-special-key: |-
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
kind: ConfigMap
metadata:
creationTimestamp: "2024-01-21T11:25:07Z"
name: game-config-4
namespace: default
resourceVersion: "75002"
uid: 42fbe599-ea55-4f56-8c78-95f80a8151b3
literal值
比如:
kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm
$ kubectl get configmaps special-config -o yaml
apiVersion: v1
data:
special.how: very
special.type: charm
kind: ConfigMap
metadata:
creationTimestamp: "2024-01-21T11:26:53Z"
name: special-config
namespace: default
resourceVersion: "75100"
uid: 62b75de5-31e6-4006-aa8c-ee21cf9a814a
产生器(generator)
需要在 kustomization.yaml
文件里指定产生器。
文件
在当前目录(注意不是 configure-pod-container/configmap
目录)创建文件 kustomization.yaml
如下:
configMapGenerator:
- name: game-config-4
options:
labels:
game-config: config-4
files:
- configure-pod-container/configmap/game.properties
$ kubectl apply -k .
configmap/game-config-4-tbg7c4gc77 created
$ kubectl describe configmap/game-config-4-tbg7c4gc77
Name: game-config-4-tbg7c4gc77
Namespace: default
Labels: game-config=config-4
Annotations: <none>
Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
BinaryData
====
Events: <none>
自定义key值
在当前目录(注意不是 configure-pod-container/configmap
目录)创建文件 kustomization.yaml
如下:
configMapGenerator:
- name: game-config-5
options:
labels:
game-config: config-5
files:
- game-special-key=configure-pod-container/configmap/game.properties
注意多了 game-special-key=
。
$ kubectl apply -k .
configmap/game-config-5-tfhf8f4fkf created
$ kubectl describe configmap/game-config-5-tfhf8f4fkf
Name: game-config-5-tfhf8f4fkf
Namespace: default
Labels: game-config=config-5
Annotations: <none>
Data
====
game-special-key:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
BinaryData
====
Events: <none>
literal值
在当前目录(注意不是 configure-pod-container/configmap
目录)创建文件 kustomization.yaml
如下:
configMapGenerator:
- name: special-config-2
literals:
- special.how=very
- special.type=charm
$ kubectl apply -k .
configmap/special-config-2-2b86tk8fhm created
$ kubectl describe configmap/special-config-2-2b86tk8fhm
Name: special-config-2-2b86tk8fhm
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
special.how:
----
very
special.type:
----
charm
BinaryData
====
Events: <none>
定义容器环境变量
单个ConfigMap
先把ConfigMap special-config
删掉重建:
kubectl delete configmap special-config
kubectl create configmap special-config --from-literal=special.how=very
在pod的specification里,把 special.how
赋给 SPECIAL_LEVEL_KEY
环境变量。创建文件 pods/pod-single-configmap-env-variable.yaml
如下:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
# Define the environment variable
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
# The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY
name: special-config
# Specify the key associated with the value
key: special.how
restartPolicy: Never
注:如果访问不了 registry.k8s.io
,则需事先把image放到能访问的地方,比如 docker.io
:
image: docker.io/kaiding1/busybox
创建pod:
kubectl create -f pods/pod-single-configmap-env-variable.yaml
查看pod:
$ kubectl get pod dapi-test-pod
NAME READY STATUS RESTARTS AGE
dapi-test-pod 0/1 Completed 0 70s
$ kubectl describe pod dapi-test-pod
......
Environment:
SPECIAL_LEVEL_KEY: <set to the key 'special.how' of config map 'special-config'> Optional: false
......
查看pod的log:
$ kubectl logs dapi-test-pod
......
SPECIAL_LEVEL_KEY=very
......
注:log内容包含了pod的标准输出(stdout),本例中创建pod时指定了 command: [ "/bin/sh", "-c", "env" ]
,也就是说,启动容器时运行 env
命令查看环境变量。从pod的log可知,环境变量里包含了 SPECIAL_LEVEL_KEY=very
。
多个ConfigMap
删除ConfigMap special-config
和 env-config
:
kubectl delete cm special-config env-config
删除pod dapi-test-pod
:
kubectl delete pod dapi-test-pod
创建文件 configmap/configmaps.yaml
如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
---
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config
namespace: default
data:
log_level: INFO
创建ConfigMap:
kubectl create -f configmap/configmaps.yaml
创建文件 pods/pod-multiple-configmap-env-variable.yaml
如下:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
# image: registry.k8s.io/busybox
image: docker.io/kaiding1/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
restartPolicy: Never
创建pod:
kubectl create -f pods/pod-multiple-configmap-env-variable.yaml
查看pod:
$ kubectl get pod dapi-test-pod
NAME READY STATUS RESTARTS AGE
dapi-test-pod 0/1 Completed 0 70s
$ kubectl logs dapi-test-pod
......
LOG_LEVEL=INFO
SPECIAL_LEVEL_KEY=very
......
最后,删除pod:
kubectl delete pod dapi-test-pod
配置ConfigMap里所有键值对为环境变量
创建文件 configmap/configmap-multikeys.yaml
如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
SPECIAL_LEVEL: very
SPECIAL_TYPE: charm
删掉ConfigMap special-config
:
kubectl delete cm special-config
重建:
kubectl create -f configmap/configmap-multikeys.yaml
创建文件 pods/pod-configmap-envFrom.yaml
如下:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
# image: registry.k8s.io/busybox
image: docker.io/kaiding1/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: special-config
restartPolicy: Never
创建pod test-container
:
kubectl create -f pods/pod-configmap-envFrom.yaml
$ kubectl get pod dapi-test-pod
NAME READY STATUS RESTARTS AGE
dapi-test-pod 0/1 Completed 0 44s
$ kubectl logs dapi-test-pod
......
SPECIAL_LEVEL=very
SPECIAL_TYPE=charm
......
最后,删除pod:
kubectl delete pod dapi-test-pod
在pod命令里使用ConfigMap定义的环境变量
可以在容器的 command
和 args
里,通过 $(VAR_NAME)
Kubernetes替换语法,使用ConfigMap定义的环境变量。
创建文件 pods/pod-configmap-env-var-valueFrom.yaml
:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
# image: registry.k8s.io/busybox
image: docker.io/kaiding1/busybox
command: [ "/bin/echo", "$(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: SPECIAL_LEVEL
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: SPECIAL_TYPE
restartPolicy: Never
创建pod dapi-test-pod
:
kubectl create -f pods/pod-configmap-env-var-valueFrom.yaml
$ kubectl get pod dapi-test-pod
NAME READY STATUS RESTARTS AGE
dapi-test-pod 0/1 Completed 0 42s
$ kubectl logs dapi-test-pod
very charm
最后,删除pod:
kubectl delete pod dapi-test-pod
添加ConfigMap数据到volume
前面提到,使用 --from-file
创建ConfigMap时,文件名作为key存储在ConfigMap的 data
部分,而文件内容作为key所对应的value。
之前创建过文件 configmap/configmap-multikeys.yaml
,并以此创建ConfigMap special-config
。
使用ConfigMap的数据填充volume
在pod的specification的 volumes
下添加ConfigMap名字。这将会添加ConfigMap的数据到 volumeMounts.mountPath
(本例中为 /etc/config
)。
创建文件 pods/pod-configmap-volume.yaml
如下:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
# image: registry.k8s.io/busybox
image: docker.io/kaiding1/busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
# Provide the name of the ConfigMap containing the files you want
# to add to the container
name: special-config
restartPolicy: Never
创建pod dapi-test-pod
:
kubectl create -f pods/pod-configmap-volume.yaml
$ kubectl logs dapi-test-pod
SPECIAL_LEVEL
SPECIAL_TYPE
文本数据会展现为UTF-8字符编码的文件。要想使用其它字符编码,可以使用 binaryData
。
注意:如果容器image的 /etc/config
目录里有文件,volume mount将会导致该image中的这些文件无法访问。
最后,删除pod:
kubectl delete pod dapi-test-pod
添加ConfigMap的数据到volume的指定路径
使用 patch
字段来指定文件路径。本例中, SPECIAL_LEVEL
会被mount到 config-volume
volume的 /etc/config/keys
。
创建文件 pods/pod-configmap-volume-specific-key.yaml
如下:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
# image: registry.k8s.io/busybox
image: docker.io/kaiding1/busybox
command: [ "/bin/sh","-c","cat /etc/config/keys" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: SPECIAL_LEVEL
path: keys
restartPolicy: Never
创建pod test-container
:
kubectl create -f pods/pod-configmap-volume-specific-key.yaml
$ kubectl logs dapi-test-pod
very
可见, cat /etc/config/keys
的输出结果是 very
。
注意:如果容器image的 /etc/config
目录里有文件,volume mount将会导致该image中的这些文件无法访问。
最后,删除pod:
kubectl delete pod dapi-test-pod
文件权限
默认情况下,文件权限是 0644
。可通过 defaultMode
设置文件权限,比如:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
volumes:
- name: foo
configmap:
name: mycm
defaultMode: 0400
注意:如果使用JSON定义Pod或Pod模板,请注意JSON不支持八进制的literal数值,因为JSON会把 0400
当作十进制的 400
。在JSON中,要用十进制的 defaultMode
。
可选引用
ConfigMap引用可被标记为 optional
。如果ConfigMap不存在,则mount的volume为空。如果ConfigMap存在,但引用的key不存在,则mount point下的路径将不存在。
mount的ConfigMap会自动更新
当mount的ConfigMap更新时,所投射的内容最终也会更新。这适用于pod启动后,可选引用的ConfigMap出现的情况。
Kubelet在每次定期同步时都会检查mount的ConfigMap是否是最新的。然而,它使用基于TTL的缓存来获取ConfigMap的当前值。因此,从“ConfigMap更新”到“新键投射到pod”的总延迟可能与“kubelet同步周期(默认为1分钟)” + “kubelet中ConfigMap缓存的TTL(默认为1分钟)”一样长。可通过更新pod的一个注解来触发立即刷新。
注意:把ConfigMap作为subPath volume的容器不会收到ConfigMap更新。
理解ConfigMap和pod
ConfigMap API资源把配置数据存储为键-值对。这些数据可以在pod里被消费,或者为系统组件比如控制器提供配置。ConfigMap和secret类似,但提供的是一种处理不含敏感信息的字符串的方法。用户和系统组件都可以在ConfigMap中存储配置数据。
注意:ConfigMap应该引用properties文件,而不是替换它们。可以把ConfigMap理解为类似于Linux /etc
目录及其内容的东西。例如,如果从ConfigMap创建volume,则ConfigMap中的每个数据项都由volume中的一个文件来表示。
ConfigMap的 data
字段包含了配置数据。从下面的例子可见,它可以很简单(比如 --from-literal
定义的单个属性)或者很复杂(比如 --from-file
定义的配置文件或JSON blob)。
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2016-02-18T19:14:38Z
name: example-config
namespace: default
data:
# example of a simple property defined using --from-literal
example.property.1: hello
example.property.2: world
# example of a complex property defined using --from-file
example.property.file: |-
property.1=value-1
property.2=value-2
property.3=value-3
当 kubectl
从非ASCII或UTF-8编码的输入创建ConfigMap时,会将其放入ConfigMap的 binaryData
字段,而不是 data
字段。文本和二进制数据源都可以组合在一个ConfigMap中。
要想查看 binaryData
的key和value,使用 kubectl get configmap -o jsonpath='{.binaryData}' <name>
。
Pod可以从使用 data
或 binaryData
的ConfigMap中加载数据。
可选的ConfigMap
在pod的specification里,可以把对ConfigMap的引用标记为 optional
。如果ConfigMap不存在,则对应的配置为空。如果ConfigMap存在但引用的key不存在,则配置也为空。
比如:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: ["/bin/sh", "-c", "env"]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: a-config
key: akey
optional: true # mark the variable as optional
restartPolicy: Never
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: gcr.io/google_containers/busybox
command: ["/bin/sh", "-c", "ls /etc/config"]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: no-config
optional: true # mark the source ConfigMap as optional
restartPolicy: Never
限制
- 在pod的specification中引用ConfigMap之前,必须先创建它,或者将其标记为
optional
。如果所引用的ConfigMap不存在,也没有标记为optional
,则pod将无法启动。同样,引用ConfigMap中不存在的key也会使得pod无法启动,除非将key引用标记为optional
。 - 如果使用
envFrom
来从ConfigMap定义环境变量,则无效的key将被忽略。Pod可以启动,但无效名称将被记录在事件日志中(InvalidVariableNames
)。日志消息列出了每个被跳过的key。例如:
kubectl get events
输出结果类似于:
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON SOURCE MESSAGE
0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames {kubelet, 127.0.0.1} Keys [1badkey, 2alsobad] from the EnvFrom configMap default/myconfig were skipped since they are considered invalid environment variable names.
- ConfigMap位于namespace中。 Pod只能引用同一namespace里的ConfigMap。
- ConfigMap不能用于静态pod,因为kubelet不支持。
示例:使用ConfigMap配置Redis
创建文件 example-redis-config.yaml
如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: ""
kubectl apply -f example-redis-config.yaml
$ kubectl describe cm example-redis-config
Name: example-redis-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis-config:
----
BinaryData
====
Events: <none>
创建文件 redis-pod.yaml
如下(参考 https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/config/redis-pod.yaml
):
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis:5.0.4
command:
- redis-server
- "/redis-master/redis.conf"
env:
- name: MASTER
value: "true"
ports:
- containerPort: 6379
resources:
limits:
cpu: "0.1"
volumeMounts:
- mountPath: /redis-master-data
name: data
- mountPath: /redis-master
name: config
volumes:
- name: data
emptyDir: {}
- name: config
configMap:
name: example-redis-config
items:
- key: redis-config
path: redis.conf
kubectl apply -f redis-pod.yaml
/redis-master-data
是一个空目录:
kubectl exec redis -- ls /redis-master-data
/redis-master/redis.conf
是一个空文件:
kubectl exec redis -- cat /redis-master/redis.conf
进入容器里的 redis-cli
:
kubectl exec -it redis -- redis-cli
127.0.0.1:6379>
检查 maxmemory
:
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "0"
检查 maxmemory-policy
:
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "noeviction"
修改文件 example-redis-config.yaml
如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
kubectl apply -f example-redis-config.yaml
$ kubectl describe configmap/example-redis-config
Name: example-redis-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis-config:
----
maxmemory 2mb
maxmemory-policy allkeys-lru
BinaryData
====
Events: <none>
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "0"
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "noeviction"
可见,配置没有变化,这是因为pod需要重启:
kubectl delete pod redis
kubectl apply -f redis-pod.yaml
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "2097152"
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
可见,现在配置更新了。
参考
https://kubernetes.io/docs/concepts/configuration/configmap
https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap
https://kubernetes.io/docs/tutorials/configuration/configure-redis-using-configmap