Kubernetes的ConfigMap

发布时间:2024年01月23日

在这里插入图片描述

环境

  • 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有 databinaryData 字段,里面存储一些键-值对。二者都是可选的。 data 用来存储UTF-8字符串,而 binaryData 把二进制数据存储为base64编码的字符串。

databinaryData 里的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里的容器:

  • 在容器的 commandargs
  • 容器的环境变量
  • 在只读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:

  1. 创建或使用已有的ConfigMap。多个pod可引用同一个ConfigMap。
  2. 修改pod定义,在 .spec.volumes[] 下添加一个volume。为volume命名,并用 .spec.volumes[].configMap.name 字段来引用ConfigMap对象。
  3. 在每个需要ConfigMap的容器里添加 .spec.containers[].volumeMounts[] ,设置 .spec.containers[].volumeMounts[].readOnly = true ,设置 .spec.containers[].volumeMounts[].mountPath 为一个未使用的目录。
  4. 修改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被标记为不可变,则无法再回退,也无法更改 databinaryData 字段的内容。你只能删除并重建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-configenv-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定义的环境变量

可以在容器的 commandargs 里,通过 $(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可以从使用 databinaryData 的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
文章来源:https://blog.csdn.net/duke_ding2/article/details/135726972
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。