ConfigMaps
Overview
Many applications require configuration using some combination of configuration 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**
object provides mechanisms to inject containers with configuration data while keeping containers agnostic of OKD. A **ConfigMap**
can be used to store fine-grained information like individual properties or coarse-grained information like entire configuration files or JSON blobs.
The **ConfigMap**
API object 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.
For example:
ConfigMap Object Definition
kind: ConfigMap
apiVersion: v1
metadata:
creationTimestamp: 2016-02-18T19:14:38Z
name: example-config
namespace: default
data: (1)
example.property.1: hello
example.property.2: world
example.property.file: |-
property.1=value-1
property.2=value-2
property.3=value-3
binaryData:
bar: L3Jvb3QvMTAw (2)
1 | Contains the configuration data. |
2 | Points to a file that contains non-UTF8 data, for example, a binary Java keystore file. Enter the file path in Base 64. |
You can use the |
Configuration data can be consumed in pods in a variety of ways. A **ConfigMap**
can be used to:
Populate the value of environment variables.
Set command-line arguments in a container.
Populate configuration files in a volume.
Both users and system components may store configuration data in a **ConfigMap**
.
Creating ConfigMaps
You can use the following command to create a **ConfigMap**
easily from directories, specific files, or literal values:
$ oc create configmap <configmap_name> [options]
The following sections cover the different ways you can create a **ConfigMap**
.
Creating from Directories
Consider a directory with some files that already contain the data with which you want to populate a **ConfigMap**
:
$ ls example-files
game.properties
ui.properties
$ cat example-files/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 example-files/ui.properties
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice
You can use the following command to create a **ConfigMap**
holding the content of each file in this directory:
$ oc create configmap game-config \
--from-file=example-files/
When the --from-file
option 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 file name, and the value of the key is the content of the file.
For example, the above command creates the following **ConfigMap**
:
$ oc describe configmaps game-config
Name: game-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
game.properties: 121 bytes
ui.properties: 83 bytes
You can see the two keys in the map are created from the file names in the directory specified in the command. Because the content of those keys may be large, the output of oc describe
only shows the names of the keys and their sizes.
If you want to see the values of the keys, you can oc get
the object with the -o
option:
$ oc 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
You can also pass the --from-file
option with a specific file, and pass it multiple times to the CLI. The following yields equivalent results to the Creating from Directories example:
If you create a configmap from a file, you can include files containing non-UTF8 data will be placed in this new field without corrupting the non-UTF8 data. OKD detects binary files and transparently encodes the file as MIME. On the server, the MIME payload is decoded and stored without corrupting the data. |
Create the
**ConfigMap**
specifying a specific file:$ oc create configmap game-config-2 \
--from-file=example-files/game.properties \
--from-file=example-files/ui.properties
Verify the results:
$ oc 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
You can also set the key to use for an individual file with the --from-file
option by passing an expression of key=value
. For example:
Create the
**ConfigMap**
specifying a key-value pair:$ oc create configmap game-config-3 \
--from-file=game-special-key=example-files/game.properties
Verify the results:
$ oc 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
You can also supply literal values for a **ConfigMap**
. The --from-literal
option takes a key=value
syntax that allows literal values to be supplied directly on the command line:
Create the
**ConfigMap**
specifying a literal value:$ oc create configmap special-config \
--from-literal=special.how=very \
--from-literal=special.type=charm
Verify the results:
$ oc 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
Use Cases: Consuming ConfigMaps in Pods
The following sections describe some uses cases when consuming **ConfigMap**
objects in pods.
Consuming in Environment Variables
**ConfigMaps**
can be used to populate individual environment variables or can populate environment variables from all keys that form valid environment variable names. As an example, consider the following **ConfigMaps**
:
ConfigMap with two environment variables
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config (1)
namespace: default
data:
special.how: very (2)
special.type: charm (2)
1 | Name of the ConfigMap. |
2 | Environment variables to inject. |
ConfigMap with one environment variable
apiVersion: v1
kind: ConfigMap
metadata:
name: env-config (1)
namespace: default
data:
log_level: INFO (2)
1 | Name of the ConfigMap. |
2 | Environment variable to inject. |
You can consume the keys of this **ConfigMap**
in a pod using **configMapKeyRef**
sections:
Sample pod specification configured to inject specific environment variables
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: (1)
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config (2)
key: special.how (3)
- name: SPECIAL_TYPE_KEY
valueFrom:
configMapKeyRef:
name: special-config (2)
key: special.type (3)
optional: true (4)
envFrom: (5)
- configMapRef:
name: env-config (6)
restartPolicy: Never
1 | Stanza to pull the specified environment variables from a ConfigMap . |
2 | Name of the ConfigMap to pull specific environment variables from. |
3 | Environment variable to pull from the ConfigMap . |
4 | Makes the environment variable optional. As optional, the pod will be started even if the specified ConfigMap and keys do not exist. |
5 | Stanza to pull all environment variables from a ConfigMap . |
6 | Name of the ConfigMap to pull all environment variables. |
When this pod is run, its output will include the following lines:
SPECIAL_LEVEL_KEY=very
log_level=INFO
Setting Command-line Arguments
A **ConfigMap**
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 following **ConfigMaps**
:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
To inject values into the command line, you must consume the keys you want to use as environment variables, as in the Consuming in Environment Variables use case. Then you can refer to them in a container’s command using the $(VAR_NAME)
syntax.
Sample pod specification configured to inject specific environment variables
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
Consuming in Volumes
A **ConfigMap**
can also be consumed in volumes. Returning again to the following example **ConfigMap**
:
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
namespace: default
data:
special.how: very
special.type: charm
You 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 file name 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", "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
You 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", "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
Example: Configuring Redis
For a real-world example, you can configure Redis using a **ConfigMap**
. To inject Redis with the recommended configuration for using Redis as a cache, the Redis configuration file should contain the following:
maxmemory 2mb
maxmemory-policy allkeys-lru
If your configuration file is located at example-files/redis/redis-config, create a **ConfigMap**
with it:
Create the
**ConfigMap**
specifying the configuration file:$ oc create configmap example-redis-config \
--from-file=example-files/redis/redis-config
Verify the results:
$ oc get configmap example-redis-config -o yaml
apiVersion: v1
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
kind: ConfigMap
metadata:
creationTimestamp: 2016-04-06T05:53:07Z
name: example-redis-config
namespace: default
resourceVersion: "2985"
selflink: /api/v1/namespaces/default/configmaps/example-redis-config
uid: d65739c1-fbbb-11e5-8a72-68f728db1985
Now, create a pod that uses this **ConfigMap**
:
Create a pod definition like the following and save it to a file, for example redis-pod.yaml:
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
Create the pod:
$ oc create -f redis-pod.yaml
The newly-created 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 configuration file at /redis-master/redis.conf, which is where the image looks for the Redis configuration file for the master.
If you oc exec
into this pod and run the redis-cli
tool, you can check that the configuration was applied correctly:
$ oc 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
A **ConfigMap**
must be created before they are consumed in pods. Controllers can be written to tolerate missing configuration data; consult individual components configured via **ConfigMap**
on a case-by-case basis.
**ConfigMap**
objects reside in a project. They can only be referenced by pods in the same project.
The Kubelet only supports use of a **ConfigMap**
for pods it gets from the API server. This includes any pods created using the CLI, or indirectly from a replication controller. It does not include pods created using the OKD node’s --manifest-url
flag, its --config
flag, or its REST API (these are not common ways to create pods).