• eparis
  • pmorie title: Configure Containers Using a ConfigMap

Many applications require configuration via some combination of config files, command line arguments, and environment variables. These configuration artifacts should be decoupled from image content in order to keep containerized applications portable. The ConfigMap API resource provides mechanisms to inject containers with configuration data while keeping containers agnostic of Kubernetes. ConfigMap can be used to store fine-grained information like individual properties or coarse-grained information like entire config files or JSON blobs.

Overview of ConfigMap

The ConfigMap API resource holds key-value pairs of configuration data that can be consumed in pods or used to store configuration data for system components such as controllers. ConfigMap is similar to Secrets, but designed to more conveniently support working with strings that do not contain sensitive information.

Note: ConfigMaps are not intended to act as a replacement for a properties file. ConfigMaps are intended to act as a reference to multiple properties files. You can think of them as way to represent something similar to the /etc directory, and the files within, on a Linux computer. One example of this model is creating Kubernetes Volumes from ConfigMaps, where each data item in the ConfigMap becomes a new file.

Consider the following example:

kind: ConfigMap
apiVersion: v1
metadata:
  creationTimestamp: 2016-02-18T19:14:38Z
  name: example-config
  namespace: default
data:
  example.property.1: hello
  example.property.2: world
  example.property.file: |-
    property.1=value-1
    property.2=value-2
    property.3=value-3

The data field contains the configuration data. As you can see, ConfigMaps can be used to hold fine-grained information like individual properties or coarse-grained information like the contents of configuration files.

Configuration data can be consumed in pods in a variety of ways. ConfigMaps can be used to:

  1. Populate the values of environment variables
  2. Set command-line arguments in a container
  3. Populate config files in a volume

Both users and system components may store configuration data in ConfigMap.

Creating ConfigMaps

You can use the kubectl create configmap command to create configmaps easily from literal values, files, or directories.

Let's take a look at some different ways to create a ConfigMap:

Creating from directories

Say that we have a directory with some files that already contain the data we want to populate a ConfigMap with:

$ ls docs/user-guide/configmap/kubectl/
game.properties
ui.properties

$ cat docs/user-guide/configmap/kubectl/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

$ cat docs/user-guide/configmap/kubectl/ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice

The kubectl create configmap command can be used to create a ConfigMap holding the content of each file in this directory:

$ kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl

When --from-file points to a directory, each file directly in that directory is used to populate a key in the ConfigMap, where the name of the key is the filename, and the value of the key is the content of the file.

Let's take a look at the ConfigMap that this command created:

$ kubectl describe configmaps game-config
Name:           game-config
Namespace:      default
Labels:         <none>
Annotations:    <none>

Data
====
game.properties:        158 bytes
ui.properties:          83 bytes

You can see the two keys in the map are created from the filenames in the directory we pointed kubectl to. Since the content of those keys may be large, in the output of kubectl describe, you'll see only the names of the keys and their sizes.

If we want to see the values of the keys, we can simply kubectl get the resource:

$ 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: 2016-02-18T18:34:05Z
  name: game-config
  namespace: default
  resourceVersion: "407"
  selfLink: /api/v1/namespaces/default/configmaps/game-config
  uid: 30944725-d66e-11e5-8cd0-68f728db1985

Creating from files

We can also pass --from-file a specific file, and pass it multiple times to kubectl. The following command yields equivalent results to the above example:

$ kubectl create configmap game-config-2 --from-file=docs/user-guide/configmap/kubectl/game.properties --from-file=docs/user-guide/configmap/kubectl/ui.properties

$ kubectl get configmaps game-config-2 -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: 2016-02-18T18:52:05Z
  name: game-config-2
  namespace: default
  resourceVersion: "516"
  selfLink: /api/v1/namespaces/default/configmaps/game-config-2
  uid: b4952dc3-d670-11e5-8cd0-68f728db1985

We can also set the key to use for an individual file with --from-file by passing an expression of key=value: --from-file=game-special-key=docs/user-guide/configmap/kubectl/game.properties:

$ kubectl create configmap game-config-3 --from-file=game-special-key=docs/user-guide/configmap/kubectl/game.properties

$ kubectl get configmaps game-config-3 -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: 2016-02-18T18:54:22Z
  name: game-config-3
  namespace: default
  resourceVersion: "530"
  selfLink: /api/v1/namespaces/default/configmaps/game-config-3
  uid: 05f8da22-d671-11e5-8cd0-68f728db1985

Creating from literal values

It is also possible to supply literal values for ConfigMaps using kubectl create configmap. The --from-literal option takes a key=value syntax that allows literal values to be supplied directly on the command line:

$ 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: 2016-02-18T19:14:38Z
  name: special-config
  namespace: default
  resourceVersion: "651"
  selfLink: /api/v1/namespaces/default/configmaps/special-config
  uid: dadce046-d673-11e5-8cd0-68f728db1985

Consuming ConfigMap in pods

Use-Case: Consume ConfigMap in environment variables

ConfigMaps can be used to populate individual environment variables or be used in its entirety. As an example, consider the following ConfigMaps:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
  namespace: default
data:
  log_level: INFO

We can consume the keys of this ConfigMap in a pod like so:

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: special-config
              key: special.how
        - name: SPECIAL_TYPE_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: special.type
      envFrom:
        - configMapRef:
            name: env-config
  restartPolicy: Never

When this pod is run, its output will include the lines:

SPECIAL_LEVEL_KEY=very
SPECIAL_TYPE_KEY=charm
log_level=INFO

Optional ConfigMap in environment variables

There might be situations where environment variables are not always required. These environment variables can be marked as optional in a pod like so:

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
  restartPolicy: Never

When this pod is run, the output will be empty.

Use-Case: Set command-line arguments with ConfigMap

ConfigMaps can also be used to set the value of the command or arguments in a container. This is accomplished using the Kubernetes substitution syntax $(VAR_NAME). Consider the ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm

In order to inject values into the command line, we must consume the keys we want to use as environment variables, as in the last example. Then we can refer to them in a container's command using the $(VAR_NAME) syntax.

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
      env:
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: special.how
        - name: SPECIAL_TYPE_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: special.type
  restartPolicy: Never

When this pod is run, the output from the test-container container will be:

very charm

Use-Case: Consume ConfigMap via volume plugin

ConfigMaps can also be consumed in volumes. Returning again to our example ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm

We have a couple different options for consuming this ConfigMap in a volume. The most basic way is to populate the volume with files where the key is the filename and the content of the file is the value of the 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", "cat /etc/config/special.how" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
  restartPolicy: Never

When this pod is run, the output will be:

very

We can also control the paths within the volume where ConfigMap keys are projected:

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
        items:
        - key: special.how
          path: path/to/special-key
  restartPolicy: Never

When this pod is run, the output will be:

very

Projecting keys to specific paths and file permissions

You can project keys to specific paths and specific permissions on a per-file basis. The Secrets user guide explains the syntax.

Optional ConfigMap via volume plugin

Volumes and files provided by a ConfigMap can be also be marked as optional. The ConfigMap or the key specified does not have to exist. The mount path for such items will always be created.

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
  restartPolicy: Never

When this pod is run, the output will be:

Real World Example: Configuring Redis

Let's take a look at a real-world example: configuring redis using ConfigMap. Say that we want to inject redis with the recommendation configuration for using redis as a cache. The redis config file should contain:

maxmemory 2mb
maxmemory-policy allkeys-lru

Such a file is in docs/user-guide/configmap/redis; we can use the following command to create a ConfigMap instance with it:

$ kubectl create configmap example-redis-config --from-file=docs/user-guide/configmap/redis/redis-config

$ kubectl get configmap example-redis-config -o yaml
apiVersion: v1
data:
  redis-config: |
    maxmemory 2mb
    maxmemory-policy allkeys-lru
kind: ConfigMap
metadata:
  creationTimestamp: 2016-03-30T18:14:41Z
  name: example-redis-config
  namespace: default
  resourceVersion: "24686"
  selfLink: /api/v1/namespaces/default/configmaps/example-redis-config
  uid: 460a2b6e-f6a3-11e5-8ae5-42010af00002

Now, let's create a pod that uses this config:

apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: kubernetes/redis:v1
    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

Notice that this pod has a ConfigMap volume that places the redis-config key of the example-redis-config ConfigMap into a file called redis.conf. This volume is mounted into the /redis-master directory in the redis container, placing our config file at /redis-master/redis.conf, which is where the image looks for the redis config file for the master.

$ kubectl create -f docs/user-guide/configmap/redis/redis-pod.yaml

If we kubectl exec into this pod and run the redis-cli tool, we can check that our config was applied correctly:

$ 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"

Restrictions

ConfigMaps must be created before they are consumed in pods unless they are marked as optional. References to ConfigMaps that do not exist will prevent the pod from starting. Controllers may be written to tolerate missing configuration data; consult individual components configured via ConfigMap on a case-by-case basis.

References via configMapKeyRef to keys that do not exist in a named ConfigMap will prevent the pod from starting.

ConfigMaps used to populate environment variables via envFrom that have keys that are considered invalid environment variable names will have those keys skipped. The pod will be allowed to start. There will be an event whose reason is InvalidVariableNames and the message will contain the list of invalid keys that were skipped. The example shows a pod which refers to the default/myconfig ConfigMap that contains 2 invalid keys, 1badkey and 2alsobad.

$ kubectl.sh get events
LASTSEEN   FIRSTSEEN   COUNT     NAME            KIND      SUBOBJECT                         TYPE      REASON
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.

ConfigMaps reside in a namespace. They can only be referenced by pods in the same namespace.

Quota for ConfigMap size is a planned feature.

Kubelet only supports use of ConfigMap for pods it gets from the API server. This includes every pod created using kubectl, or indirectly via a replication controller. It does not include pods created via the Kubelet's --manifest-url flag, its --config flag, or its REST API (these are not common ways to create pods.)