认识
如果在镜像中包含环境配置信息,那么该镜像的可移植性是非常差的。例如,如果在镜像中包含了测试环境数据库的配置信息,那该镜像只能用于测试环境,不能部署到生产环境。如何向应用程序提供配置数据?
ConfigMap,通过 ConfigMap 对象,将配置从镜像中解耦,以实现镜像的可移植性。
该笔记将记录:我们学习 ConfigMap 使用的笔记(参照官方文档),并提供系列示例,演示如何创建 ConfigMap 以及如何在 Pod 中使用 ConfigMap 中的数据。
组成
.data
ConfigMap 的 data 字段包含配置数据。
如下面的示例所示,这可以很简单(就像使用–from-literal 定义的单个属性),或类似复杂的(配置文件或使用–from-file 定义的 JSON 二进制大对象):
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
限制
必须先创建 ConfigMap,然后才能在 Pod Spec 中引用它(除非将 ConfigMap 标记为“optional”)。如果引用不存在的 ConfigMap,Pod 将无法启动。同样,对 ConfigMap 中不存在的 Key 的引用,将阻止 Pod 启动。
如果使用 envFrom 从 ConfigMaps 定义环境变量,则将跳过被视为无效的 Key。将允许 pod 启动,但“无效名称”将记录在事件日志中(InvalidVariableNames)。日志消息列出每个跳过的 KEY:kubectl get events
只能作用于指定的命名空间。
Kubelet 不支持将 ConfigMaps 用于 APIServer 上找不到的 pod。这包括通过 Kubelet 的 –manifest-url 标志,–config 标志,Kubelet REST API 创建的 pod。(这些不是创建 pod 的常用方法)
性质
通过配置文件向 Pod 提供配置
通过 ConfigMap 可以将配置通过「配置文件」的方式来向 Pod 提供配置信息。
接下来挂载配置文件:
kind: Pod
apiVersion: v1
metadata:
name: oreilly
spec:
volumes:
- name: oreilly
configMap:
name: "name-of-configmap"
containers:
- image: busybox
name: busybox
volumeMount:
- name: "name-of-configmap"
mountPath: /oreilly
通过环境变量向 Pod 提供配置
通过 ConfigMap 可以将配置通过「环境变量」的方式来向 Pod 提供配置信息。
通过 envFrom 将整个 ConfigMap 注入到环境变量中:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
##########################################################################
envFrom:
- configMapRef:
name: special-config
##########################################################################
...
通过 env valueFrom configMapKeyRef 将特定 ConfigMap 信息注入到环境变量中:
kind: Deploymet
apiVerison: extensions/v1beta1
metadata:
name: cmapp
spec:
replicas: 1
template:
metadata:
labels:
app: cmapp
spec:
containers:
- name: sise
image: k8s.gcr.io/busybox
env:
- name: SIMPLE_SVC_VERSION
valueFrom:
configMapKeyRef:
name: sisconfig
key: siseversion
已挂载的 ConfigMaps 会自动更新
当已经在 Volume 中使用的 ConfigMap 发生修改,投影的 Key 也自然会更新。
kubelet 会定期检查已挂载的 ConfigMap 是否是新的。
但是,它使用其本地基于 TTL 的缓存来获取 ConfigMap 的当前值。
所以,从「ConfigMap 发生修改」到「Pod 中的 ConfigMap 发生更新」的延迟,可以和「kubelet sync period」+「TTL」一样长。
注意事项,使用 ConfigMap 作为 subPath 卷,将不会收到 ConfigMap 的更新。
构建
有两种方法创建 ConfigMap 对象:
- 使用命令行:kubectl create configmap
- 使用生成器:使用 kustomization.yaml 中的 ConfigMap 生成器;(从 1.14 开始)
通过 kubectl 管理 ConfigMap 资源
kubectl create configmap “cm-name” –from-literal=siseversion=0.9
通过配置文件中创建 ConfigMap 对象:kubectl create configmap “cm-name” –from-file=example.cfg
通过 kubectl create configmap 命令,从目录、文件、字面量创建 ConfigMap 对象:
kubectl create configmap <map-name> <data-source>
参数 <map-name> 是 ConfigMap 的名字,参数 <data-source> 是用于从中提取数据目录、文件、字面量。
参数 <data-source> 对应了 ConfigMap 中的键值对:
- key – 在命令行提供的「文件名」或者「key」;
- value – 在命令行提供的「文件内容」或者「字面值」;
通过 kubectl describe 或者 kubectl get 命令,来获取 ConfigMap 中的信息。
删除命名空间内所有 ConfigMap 定义:
kubectl delete configmaps $(kubectl -n default get configmaps --output=jsonpath="{range .items[*]}{.metadata.name}{' '}{end}")
从目录中创建 ConfigMap 对象
# Create the local directory
mkdir -p configure-pod-container/configmap/
# Download the sample files into `configure-pod-container/configmap/` directory
wget https://kubernetes.io/examples/configmap/game.properties -O configure-pod-container/configmap/game.properties
wget https://kubernetes.io/examples/configmap/ui.properties -O configure-pod-container/configmap/ui.properties
# ----------------------------------------------------------------------------- # 创建 ConfigMap
kubectl create configmap "tmpl" --dry-run -o yaml --from-literal=foo=bar
# 该命令结合文件「game.properties」和「ui.properties」的内容,创建名为「game-config」的 ConfigMap 对象
kubectl create configmap "game-config" \
--from-file="configure-pod-container/configmap/"
# ----------------------------------------------------------------------------- # 查看 ConfigMap
kubectl describe configmaps game-config
# 数据存在于 ConfigMap 的「data」部分
kubectl get configmaps game-config -o yaml
# apiVersion: v1
# kind: ConfigMap
# metadata:
# creationTimestamp: 2016-02-18T18:52:05Z
# name: game-config
# namespace: default
# resourceVersion: "516"
# selfLink: /api/v1/namespaces/default/configmaps/game-config
# uid: b4952dc3-d670-11e5-8cd0-68f728db1985
# 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
从文件中创建 ConfigMap 对象
################################################################################
# 当从文件创建时,使用「--from-file」选项。
# 这种用法与从目录中创建是一致的。
################################################################################
# 创建
kubectl create configmap "game-config-2" \
--from-file="configure-pod-container/configmap/game.properties"
# 可以指定多次
kubectl create configmap "game-config-2" \
--from-file=configure-pod-container/configmap/game.properties \
--from-file=configure-pod-container/configmap/ui.properties
# 当使用「--from-file」选项时,在「data」部分中的「key」是文件名,也可以使用自定义的名字
kubectl create configmap "game-config-3" \
--from-file=game-special-key=configure-pod-container/configmap/game.properties
# 显示 ConfigMap 对象的信息
kubectl describe configmaps "game-config-2"
################################################################################
# 当从文件创建时,使用「--from-env-file」选项。
# 这种用法与从前面的就不一样了。
################################################################################
kubectl create configmap "game-config-env-file" \
--from-env-file="configure-pod-container/configmap/ui.properties"
# 查看文件内容
kubectl get configmap game-config-env-file -o yaml
# apiVersion: v1
# kind: ConfigMap
# metadata:
# creationTimestamp: 2017-12-27T18:36:28Z
# name: game-config-env-file
# namespace: default
# resourceVersion: "809965"
# selfLink: /api/v1/namespaces/default/configmaps/game-config-env-file
# uid: d9d1ca5b-eb34-11e7-887b-42010a8002b8
# data:
# allowed: '"true"'
# enemies: aliens
# lives: "3"
# !!!如果指定了「--from-env-file」多次,那么只有最后一个是有效的。
从字面值创建 ConfigMap 对象
#!/bin/sh # 这个做法类似于「--from-env-file」选项,只不过是从命令行直接指定 kubectl create configmap "special-config" \ --from-literal=special.how=very \ --from-literal=special.type=charm
通过使用生成器
从 1.14 开始,kubectl 支持 kustomization.yaml。您还可以从「生成器」创建 ConfigMap 对象,然后应用它,在 Apiserver 上创建对象。应在目录中的 kustomization.yaml 中指定生成器。
从文件中创建 ConfigMap 对象
#!/bin/sh # 从「configure-pod-container/configmap/kubectl/game.properties」中生成 ConfigMap 对象 # Create a kustomization.yaml file with ConfigMapGenerator cat <<EOF >./kustomization.yaml configMapGenerator: - name: game-config-4 files: - configure-pod-container/configmap/kubectl/game.properties # 默认的 key 是文件名,可以指定自定义的 key 值 - game-special-key=configure-pod-container/configmap/kubectl/game.properties EOF # 从当前目录中应用定义来创建 ConfigMap 对象 kubectl apply -k . # 查看定义 kubectl get configmap kubectl describe configmaps/game-config-4-m9dm2f92bt # !!!文件名以内容的哈希为后缀。以确保每次 ConfigMap 修改后生成新的 ConfigMap 对象。
从字面值中创建 ConfigMap 对象
#!/bin/sh # Create a kustomization.yaml file with ConfigMapGenerator cat <<EOF >./kustomization.yaml configMapGenerator: - name: special-config-2 literals: - special.how=very - special.type=charm EOF # 从当前目录中应用定义来创建 ConfigMap 对象 kubectl apply -k .
应用
场景 | 挂载所有数据
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
# 定义卷,该卷引用名为 config-volume 的 ConfigMap 对象
volumes:
- name: config-volume
configMap:
name: special-config
# 使用卷,将在容器中使用该卷
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "ls /etc/config/" ]
# 挂载这个卷到 /etc/config/ 目录中
volumeMounts:
- name: config-volume
mountPath: /etc/config
查看 /etc/config/ 目录,会发现该目录下的会有大量的文件。
- 文件名称为 ConfigMap 中的 Key 值,
- 文件内容为该 Key 对应的 Value 值。
场景 | 挂载特定数据
使用 path 字段,将特定的 ConfigMap 项挂载到特定的文件目录。
在该示例中,在 ConfigMap 中的 SPECIAL_LEVEL 将被挂载到 /etc/config/keys 中:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
# 只定义需要挂载的属性,及挂载名称
volumes:
- name: config-volume
configMap:
name: special-config
items:
- key: SPECIAL_LEVEL
path: keys # 挂载的名字
# 使用卷,将在容器中使用该卷
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh","-c","cat /etc/config/keys" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
注意事项,如果 /etc/config 之前包含其他文件,则使用该方式之后,这些文件将不可见。需要使用 subPath 来挂载到特定文件:
volumeMounts: - name: config-volume mountPath: /etc/config/keys subPath: keys
如果想要为每个文件指定权限,参考「Secrets/Using Secrets as Files from a Pod」部分。
场景 | 引入外部配置数据
ConfigMap 为 YAML 格式,数据以字符串保存在其中。当编辑数据时,我们需要注意数据格式和缩进,并且难以使用编辑器的高亮和语法检查功能。
虽然编辑器有 Emacs Narrowing 类似的功能,但是我们依旧认为很繁琐。我们希望 ConfigMap 能够引入外部文件,类似编程语言中的 includeFile 功能。
但是 ConfigMap 并不支持引入外部文件。解决方法有如下几种:
- Kustomize
- Helm Chart Files.Get
- kubectl create configmap –from-file
- 通过 Shell 生成
参考
Configure a Pod to Use a ConfigMap
Kubernetes – Using ConfigMap SubPaths to Mount Files – DEV Community
环境变量:使用 ConfigMap 数据
我们可以将在 ConfigMap 中的数据导入容器的环境变量中。
将特定数据导入环境变量
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
##########################################################################
env:
# 定义环境变量的 KEY 值
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
# 被引用的 ConfigMap 对象的名称
name: special-config
# 该 ConfigMap 中的 KEY 值
key: special.how
# 引用另外一个 ConfigMap 中的值
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: env-config
key: log_level
##########################################################################
# 这些环境变量也可以容器中使用
command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY)" ]
restartPolicy: Never
配置文件:挂载 ConfigMap 到文件
当使用「–from-file」选项创建 ConfigMap 对象时,「文件名」被作为「key」存储在 ConfigMap 的「data」部分,而「文件内容」则作为「value」进行存储。
理解 ConfigMap 和 Pod 对象
针对 ConfigMap API 资源,其将配置数据存储为键值对。可以在 Pod 中使用数据,也可以为「控制器」等系统组件提供配置。
ConfigMap 类似于 Secrets,但提供了一种处理不包含敏感信息的字符串的方法。
用户和系统组件都可以在 ConfigMap 中存储配置数据。
!!!ConfigMaps 应引用属性文件,而不是替换它们。可以将 ConfigMap 视为代表的内容,类似于 Linux 的 /etc 目录及其内容。
!!!例如,如果从 ConfigMap 创建 Kubernetes 卷,则 ConfigMap 中的每个数据项,都由卷中的单个文件表示。