• Post author:
  • Post category:Kubernetes
  • Post comments:0评论
Like
Like Love Haha Wow Sad Angry
基于 Kubernetes 1.22 版本

一、基础概念

  ConfigMap 用于在键值对中存储非机密数据,使用它可以将应用所需的配置信息与程序进行分离,这样可以使得应用程序可以被更好地移植复用,而且还可以通过不同的配置实现更灵活的功能。
  官方文档:https://kubernetes.io/docs/concepts/configuration/configmap/https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/

二、创建

  对于ConfigMap,我们可以通过 yaml 配置文件创建,也可以使用 kubectl create configmap 命令从目录、文件或者命令行文字值创建。

1、基于 yaml 配置文件

[root@master configmap]# vim test.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-yaml
data:
  key: vaule
  nginx_config: |
    server {
     listen 80;
     server_name www.test.com;
      location / {
        root   /usr/share/nginx/html;
        index index.html;
      }
    }

[root@master configmap]# kubectl get configmaps 
NAME               DATA   AGE
configmap-yaml     2      3m9s
kube-root-ca.crt   1      39d

[root@master configmap]# kubectl describe configmaps configmap-yaml 
Name:         configmap-yaml
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
key:
----
value

nginx_config:
----
server {
 listen 80;
 server_name www.test.com;
  location / {
    root   /usr/share/nginx/html;
    index index.html;
  }
}

BinaryData
====

Events:  <none>

2、基于命令行

通过 –from-literal 从命令行文字值创建,直接将指定的键值对创建为 ConfigMap 的内容。
格式:kubectl create configmap NAME [--from-literal=key1=value1]

[root@master configmap]# kubectl create configmap xm --from-literal=name=xm --from-literal=age=11
configmap/xm created
[root@master configmap]# kubectl get configmaps
NAME               DATA   AGE
xm                 2      9s
[root@master configmap]# kubectl describe configmaps xm
Name:         xm
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
age:
----
11
name:
----
xm
......

3、基于文件

通过 –from-file 选项从文件中进行创建,可以指定 key 的名称,不指定 key 名称默认则为文件名字。
格式:kubectl create configmap NAME [--from-file=[key=]source]

[root@master configmap]# kubectl create configmap configmap-file --from-file=nginx_default.conf 
configmap/configmap-file created

[root@master configmap]# kubectl describe configmaps 
configmap-file    configmap-yaml    kube-root-ca.crt  xm                
[root@master configmap]# kubectl describe configmaps configmap-file 
Name:         configmap-file
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
nginx_default.conf:
----
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}
......

如果要以文件方式传入多个键值对以创建 ConfigMap,可以使用 –from-env-file。

[root@master configmap]# echo -e "key1=value1\nkey2=value2" | tee env
key1=value1
key2=value2
[root@master configmap]# kubectl create configmap configmap-env --from-env-file=env 
configmap/configmap-env created
[root@master configmap]# kubectl describe configmaps configmap-env 
Name:         configmap-env
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
key1:
----
value1
key2:
----
value2
......

4、基于目录

  我们也可以通过 –from-file 参数从目录中进行创建,该目录下的每个配置文件名都被设置为 key,文件的内容被设置为 value。
  格式:kubectl create configmap NAME --from-file=dir

[root@master configmap]# mkdir dir
[root@master configmap]# echo "value1" > dir/key1
[root@master configmap]# echo "value2" > dir/key2
[root@master configmap]# kubectl create configmap configmap-dir --from-file=dir/
configmap/configmap-dir created
[root@master configmap]# kubectl describe configmaps configmap-dir 
Name:         configmap-dir
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
key1:
----
value1

key2:
----
value2
......

三、使用

我们可以通过四种不同的方式使用 ConfigMap 在 Pod 内配置容器:

• 容器的环境变量         
• 容器内的命令和参数
• 在只读卷中添加文件,供应用程序读取。
• 编写代码,使用 Kubernetes API 读取 ConfigMap,在 Pod 内运行

  对于前三种方法,kubelet 在为 Pod 启动容器时使用来自 ConfigMap 的数据。
  第四种方法意味着必须编写代码来读取 ConfigMap 及其数据。但是,因为直接使用 Kubernetes API,所以应用程序可以订阅以在 ConfigMap 更改时获取更新,并在发生这种情况时做出反应。通过直接访问 Kubernetes API,此技术还允许您访问不同命名空间中的 ConfigMap。

1、容器环境变量

(1)使用来自单个 ConfigMap 的数据定义容器环境变量

# 将环境变量定义为 ConfigMap 中的键值对
[root@master ~]# kubectl create configmap single-env --from-literal=env.num=single

# 将 ConfigMap 中定义的 special.how 值分配给 Pod 中的 ENV_NUM 环境变量
[root@master configmap]# vim single-env-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: single-env-pod
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        # 定义环境变量
        - name: ENV_NUM
          valueFrom:
            configMapKeyRef:
              # 要分配给 ENV_NUM 变量值的 ConfigMap
              name: single-env
              # 指定与值关联的键
              key: env.num
  restartPolicy: Never

[root@master configmap]# kubectl  apply -f single-env-pod.yaml
[root@master configmap]# kubectl logs single-env-pod test-container | grep -i env
ENV_NUM=single

(2)使用来自多个 ConfigMap 的数据定义容器环境变量

创建两个 ConfigMap:

[root@master configmap]# vim multiple-env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: multiple-env1
data:
  env.num1: multiple1
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: multiple-env2
data:
  env.num2: multiple2

[root@master configmap]# kubectl apply -f multiple-env.yaml
configmap/multiple-env1 created
configmap/multiple-env2 created

Pod中定义环境变量:

[root@master configmap]# vim multiple-env-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: multiple-env-pod
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        - name: ENV_NUM1
          valueFrom:
            configMapKeyRef:
              name: multiple-env1
              key: env.num1
        - name: ENV_NUM2
          valueFrom:
            configMapKeyRef:
              name: multiple-env2
              key: env.num2
  restartPolicy: Never
[root@master configmap]# kubectl apply -f multiple-env-pod.yaml
[root@master configmap]# kubectl logs multiple-env-pod test-container | grep -i env
ENV_NUM1=multiple1
ENV_NUM2=multiple2

(3)将 ConfigMap 中的所有键值对配置为容器环境变量

创建一个包含多个键值对的 ConfigMap:

[root@master configmap]# cat all-env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: all-env
data:
  SPECIAL_LEVEL: very
  SPECIAL_TYPE: charm

[root@master configmap]# kubectl apply -f all-env.yaml 
configmap/all-env created

  使用 envFrom 将所有 ConfigMap 数据定义为容器环境变量,ConfigMap 中的键将成为 Pod 中的环境变量名:

[root@master configmap]# vim all-env-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: all-env-pod
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh", "-c", "env" ]
      envFrom:
      - configMapRef:
          name: all-env
  restartPolicy: Never

[root@master configmap]# kubectl apply -f all-env-pod.yaml 
[root@master configmap]# kubectl logs all-env-pod test-container | grep -i special
SPECIAL_LEVEL=very
SPECIAL_TYPE=charm

2、Pod 命令

  我们可以在 Pod 定义的 command 和 args 部分使用 ConfigMap 定义的环境变量,语法为Kubernetes替换语法——$(VAR_NAME) 。

[root@master configmap]# vim pod-command-env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
data:
  SPECIAL_LEVEL: very
  SPECIAL_TYPE: charm

---
apiVersion: v1
kind: Pod
metadata:
  name: pod-command-env
spec:
  containers:
    - name: test-container
      image: 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

[root@master configmap]# kubectl apply -f pod-command-env.yaml
[root@master configmap]# kubectl logs pod-command-env test-container 
very charm

3、卷

创建 ConfigMap:

[root@master configmap]# vim configmap-multikeys.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  SPECIAL_LEVEL: very
  SPECIAL_TYPE: charm

[root@master configmap]# kubectl apply -f configmap-multikeys.yaml 
configmap/special-config created

(1)使用存储在 ConfigMap 中的数据填充卷。

  在 Pod 定义的卷部分下添加 ConfigMap 名称,这会将 ConfigMap 数据添加到指定为 volumeMounts.mountPath 的目录中(在本例中为/etc/config),命令部分列出 /etc/config 目录中名称与 ConfigMap 中的键匹配的文件。

[root@master configmap]# vim pod-configmap-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap-volume
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh", "-c", "ls /etc/config/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
  restartPolicy: Never

[root@master configmap]# kubectl apply -f pod-configmap-volume.yaml 
[root@master configmap]# kubectl logs pod-configmap-volume test-container 
SPECIAL_LEVEL
SPECIAL_TYPE

  注意:如果 /etc/config/ 目录中有文件,它们将被覆盖。当然我们可以使用 subPath 就不会覆盖了,这样也可解决多个 configmap 挂载同一目录导致覆盖问题。

(2)将 ConfigMap 数据添加到卷中的特定路径

  使用 volumes.configMap.items 将 ConfigMap 添加到指定的文件路径。在下例中,SPECIAL_LEVEL 将添加到 /etc/config/keys 中。

[root@master configmap]# vim pod-configmap-volume-specific-key.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap-volume-specific-key
spec:
  containers:
    - name: test-container
      image: 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

[root@master configmap]# kubectl apply -f pod-configmap-volume-specific-key.yaml
[root@master configmap]# kubectl logs pod-configmap-volume-specific-key test-container 
very

(3)subPath

一个 ConfigMap 单个数据,挂载其数据作为文件,且不覆盖目标目录。

[root@master configmap]# kubectl create configmap key --from-literal=key=1
[root@master configmap]# cat pod-configmap-volume-specific-key.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap-volume-specific-key
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh","-c","sleep 600" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/
        subPath: key
  volumes:
    - name: config-volume
      configMap:
        name: key
  restartPolicy: Never

[root@master configmap]# kubectl apply -f pod-configmap-volume-specific-key.yaml
[root@master configmap]# kubectl exec pod-configmap-volume-specific-key -it -- sh
/ # ls /etc
group        hostname     hosts        key          localtime    mtab         network      passwd       resolv.conf  shadow
/ # cat /etc/key
1

一个 ConfigMap 多个数据,挂载所有数据作为文件,且不覆盖目标目录。

[root@master configmap]# cat pod-configmap-volume-specific-key.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap-volume-specific-key
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh","-c","sleep 600" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/key1
        subPath: key1
      - name: config-volume
        mountPath: /etc/key2
        subPath: key2
  volumes:
    - name: config-volume
      configMap:
        name: special-config
        items:
        - key: SPECIAL_LEVEL
          path: key1
        - key: SPECIAL_TYPE
          path: key2
  restartPolicy: Never

[root@master configmap]# kubectl apply -f pod-configmap-volume-specific-key.yaml
[root@master configmap]# kubectl exec pod-configmap-volume-specific-key -it -- sh
/ # ls /etc
group        hostname     hosts        key1         key2         localtime    mtab         network      passwd       resolv.conf  shadow
/ # cat /etc/key[1,2]
verycharm

一个 ConfigMap 多个数据,只挂载其中一个数据作为文件,且不覆盖目标目录。

[root@master configmap]# cat pod-configmap-volume-specific-key.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap-volume-specific-key
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh","-c","sleep 600" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/keys
        subPath: keys
  volumes:
    - name: config-volume
      configMap:
        name: special-config
        items:
        - key: SPECIAL_LEVEL
          path: keys
  restartPolicy: Never

[root@master configmap]# kubectl apply -f pod-configmap-volume-specific-key.yaml
[root@master configmap]# kubectl exec pod-configmap-volume-specific-key -it -- sh
/ # ls /etc
group        hostname     hosts        keys         localtime    mtab         network      passwd       resolv.conf  shadow
/ # cat /etc/keys
very

4、更新

  当在卷中使用的 ConfigMap 更新时,投影键最终也会更新。作为环境变量使用的 ConfigMap 不会自动更新,需要重新启动 pod。
  Kubelet 在每次定期同步时检查挂载的 ConfigMap 是否是最新的。但是,它使用其本地基于 TTL 的缓存来获取 ConfigMap 的当前值。因此,从更新 ConfigMap 到将新 key 投射到 Pod 的总延迟可以达到 kubelet 同步周期(默认为 1 分钟)+ ConfigMaps 缓存的 TTL(默认为 1 分钟) ) 。在 kubelet 中,您可以通过更新 pod 的注释之一来触发立即刷新。

[root@master configmap]# vim pod-configmap-volume.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap-volume
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/busybox
      command: [ "/bin/sh", "-c", "sleep 600" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
  restartPolicy: Never

[root@master configmap]# kubectl apply -f pod-configmap-volume.yaml 

# 查看环境变量值
[root@master configmap]# kubectl exec pod-configmap-volume -- cat /etc/config/SPECIAL_LEVEL
very

# 修改Configmap
[root@master configmap]# kubectl edit configmaps special-config
  SPECIAL_LEVEL: very111

# 此时可以看到容器环境变量值也跟着自动更新了
[root@master configmap]# kubectl exec pod-configmap-volume -- cat /etc/config/SPECIAL_LEVEL
very111

5、其它事项

  如果在 Pod 中引用不存在的 ConfigMap,则 Pod 将不会启动。同样,引用 ConfigMap 中不存在的键也会阻止 pod 启动。
  但是如果使用 envFrom 从 ConfigMaps 定义环境变量,则将跳过无效键。Pod 将允许启动,但无效名称将记录在事件日志中(InvalidVariableNames),日志消息列出了每个跳过的键。
  如果 ConfigMap 不存在,则挂载的卷将为空。如果 ConfigMap 存在,但引用的键不存在,则挂载点中将不存在路径。


参考文章:

https://kubernetes.io/docs/
《Kubernetes 权威指南》

Like
Like Love Haha Wow Sad Angry

发表评论