envvar-configmap

ConfigMaps as environment variables

Goal

Populating environment variables of a container from an entire ConfigMap.

Design Points

A container can specify a set of existing ConfigMaps to populate environment variables.

There needs to be an easy way to isolate the variables introduced by a given ConfigMap. The contents of a ConfigMap may not be known in advance and it may be generated by someone or something else. Services may provide binding information via a ConfigMap. If you have a common service with multiple instances like a Message Queue or Database, there needs to be a way to uniquely identify and prevent collision when consuming multiple ConfigMaps in a single container using this feature.

Proposed Design

Containers can specify a set of sources that are consumed as environment variables. One such source is a ConfigMap. Each key defined in the ConfigMap’s Data object must be a “C” identifier. If an invalid key is present, the container will fail to start.

Environment variables defined by a Container are processed in a specific order. The processing order is as follows:

  1. All automatic service environment variables
  2. All EnvFrom blocks in order
  3. All Env blocks in order.

The last value processed for any given environment variable will be the decided winner. Variable references defined by an EnvVar struct will be resolved by the current values defined even if the value is replaced later.

To prevent collisions amongst multiple ConfigMaps, each defined ConfigMap can have an optional associated prefix that is prepended to each key in the ConfigMap. Prefixes must be a “C” identifier.

Kubectl updates

The describe command will display the configmap name that have been defined as part of the environment variable section including the optional prefix when defined.

API Resource

A new EnvFromSource type containing a ConfigMapRef will be added to the Container struct.

// EnvFromSource represents the source of a set of ConfigMaps
type EnvFromSource struct {
  // A string to place in front of every key. Must be a C_IDENTIFIER.
  // +optional
  Prefix string `json:"prefix,omitempty"`
  // The ConfigMap to select from
  ConfigMapRef *LocalObjectReference `json:"configMapRef,omitempty"`
}

type Container struct {
  // List of sources to populate environment variables in the container.
  // The keys defined within a source must be a C_IDENTIFIER. An invalid key
  // will prevent the container from starting. When a key exists in multiple
  // sources, the value associated with the last source will take precedence.
  // Values defined by an Env with a duplicate key will take precedence over 
  // any listed source.
  // Cannot be updated.
  // +optional
  EnvFrom []EnvFromSource `json:"envFrom,omitempty"`
}

Examples

Consuming ConfigMap as Environment Variables

apiVersion: v1
kind: ConfigMap
metadata:
  name: etcd-env-config
data:
  number_of_members: "1"
  initial_cluster_state: new
  initial_cluster_token: DUMMY_ETCD_INITIAL_CLUSTER_TOKEN
  discovery_token: DUMMY_ETCD_DISCOVERY_TOKEN
  discovery_url: http://etcd_discovery:2379
  etcdctl_peers: http://etcd:2379
  duplicate_key: FROM_CONFIG_MAP
  REPLACE_ME: "a value"

This pod consumes the entire ConfigMap as environment variables:

apiVersion: v1
kind: Pod
metadata:
  name: config-env-example
spec:
  containers:
  - name: etcd
    image: openshift/etcd-20-centos7
    ports:
    - containerPort: 2379
      protocol: TCP
    - containerPort: 2380
      protocol: TCP
    env:
    - name: duplicate_key
      value: FROM_ENV
    - name: expansion
      value: $(REPLACE_ME)
    envFrom:
    - configMapRef:
        name: etcd-env-config

The resulting environment variables will be:

number_of_members="1"
initial_cluster_state="new"
initial_cluster_token="DUMMY_ETCD_INITIAL_CLUSTER_TOKEN"
discovery_token="DUMMY_ETCD_DISCOVERY_TOKEN"
discovery_url="http://etcd_discovery:2379"
etcdctl_peers="http://etcd:2379"
duplicate_key="FROM_ENV"
expansion="a value"
REPLACE_ME="a value"

Consuming multiple ConfigMap as Environment Variables

apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
data:
  key1: a
  key2: b

This pod consumes the entire ConfigMap as environment variables:

apiVersion: v1
kind: Pod
metadata:
  name: config-env-example
spec:
  containers:
  - name: etcd
    image: openshift/etcd-20-centos7
    ports:
    - containerPort: 2379
      protocol: TCP
    - containerPort: 2380
      protocol: TCP
    envFrom:
    - prefix: cm1_
      configMapRef:
        name: env-config
    - prefix: cm2_
      configMapRef:
        name: env-config

The resulting environment variables will be:

cm1_key1="a"
cm1_key2="b"
cm2_key1="a"
cm2_key2="b"

Future

Add similar support for Secrets.