Generating ConfigMaps with Kustomize

0

Kustomize is not only useful for applying overlays, patches, prefixes, suffixes, labels, and namespaces. It can also generate Kubernetes ConfigMap objects directly from different sources of information.

This is very useful when you want to keep configuration close to your overlay, but you do not want to manually write complete ConfigMap manifests every time. Instead of creating long YAML files by hand, you can define a configMapGenerator in kustomization.yaml and let Kustomize produce the final Kubernetes resources.

In this article, we will focus only on configMapGenerator. We will look at literals, files, env files, generated name hashes, per-generator options, and global generatorOptions.

secretGenerator follows a similar generator model, but Secrets have different security implications. I will cover that separately in another article.

In the examples below, I use the modern labels field instead of commonLabels, because recent Kustomize versions warn that commonLabels is deprecated.

Why ConfigMap Generators Are Useful

In a Kubernetes project, application configuration often comes from several places:

  • Simple key-value settings, such as feature flags.
  • Configuration files, such as .properties.json.yaml, or JavaScript initialization scripts.
  • Environment-style files, such as .env.local.
  • Environment-specific values that differ between devstaging, and prod.

You can write these ConfigMaps manually, but generators give you a cleaner workflow. Your source files remain normal files in your repository, and Kustomize converts them into Kubernetes resources during the build step.

For example, a JavaScript database initialization script can stay as a real .js file. Your editor can highlight it, format it, and validate it as JavaScript. Kustomize can then package the file into a ConfigMap when building the overlay.

Example Overlay Structure

Imagine the following structure:

k8s/
├── base/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
└── overlays/
    └── dev/
        ├── .env.local
        ├── db-init.js
        └── kustomization.yaml

The dev overlay can include the base resources and generate additional environment-specific configuration:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: dev
namePrefix: dev-
nameSuffix: -alpha

resources:
  - ../../base

labels:
  - pairs:
      app.kubernetes.io/part-of: color-api
      environment: dev
    includeTemplates: true
    includeSelectors: false

A few important details are already visible here:

  • resources includes the shared base.
  • namespace assigns namespaced resources to the dev namespace.
  • namePrefix and nameSuffix modify resource names.
  • labels applies labels without using the deprecated commonLabels field.
  • includeSelectors: false avoids changing immutable selectors after resources already exist.
  • includeTemplates: true also applies the labels to pod templates, which is useful for workloads such as Deployments.

Generating a ConfigMap from Literal Values

The simplest generator source is literals. A literal is a key-value pair written directly in kustomization.yaml.

configMapGenerator:
  - name: feature-flags-config
    literals:
      - USE_DB=true
      - EXPOSE_METRICS=true
      - ENABLE_NEW_UI=true

Now build the overlay:

kubectl kustomize k8s/overlays/dev

Or, if you use the standalone Kustomize binary:

kustomize build k8s/overlays/dev

Kustomize generates a ConfigMap similar to this:

apiVersion: v1
data:
  ENABLE_NEW_UI: "true"
  EXPOSE_METRICS: "true"
  USE_DB: "true"
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/part-of: color-api
    environment: dev
  name: dev-feature-flags-config-alpha-7m2k9g5h8b
  namespace: dev

The important part is the generated name:

dev-feature-flags-config-alpha-7m2k9g5h8b

This name is built from:

  • dev- from namePrefix.
  • feature-flags-config from the generator name.
  • -alpha from nameSuffix.
  • A content hash suffix generated by Kustomize.

The hash suffix changes when the generated content changes. For example, if you add another feature flag, Kustomize produces a new ConfigMap name.

That behavior is intentional. When a Deployment references the generated ConfigMap by its logical name, Kustomize rewrites the reference to the hashed generated name. When the ConfigMap data changes, the referenced name changes too, and that gives Kubernetes a new pod template specification to roll out.

Generating a ConfigMap from a File

Now let us create a JavaScript initialization script:

console.log("Initializing DB");
console.log("Performing some operations");
console.log("Successfully initialized");

Save it as:

k8s/overlays/dev/db-init.js

Then add another generator entry:

configMapGenerator:
  - name: db-init-config
    files:
      - db-init.js

Kustomize will create a ConfigMap where the file name becomes the key and the file contents become the value:

apiVersion: v1
data:
  db-init.js: |
    console.log("Initializing DB");
    console.log("Performing some operations");
    console.log("Successfully initialized");
kind: ConfigMap
metadata:
  name: dev-db-init-config-alpha-4kgfh9k8hb
  namespace: dev

This is useful when your application expects a file to exist inside the container. You can mount the ConfigMap as a volume and expose db-init.js as a file.

Customizing the Key Name for a File

By default, the key is the file name. You can override it with this syntax:

configMapGenerator:
  - name: db-init-config
    files:
      - init-script.js=db-init.js

The generated output then uses init-script.js as the key:

data:
  init-script.js: |
    console.log("Initializing DB");
    console.log("Performing some operations");
    console.log("Successfully initialized");

This gives you flexibility when the file name in your repository should be different from the file name that the application expects in the container.

A practical example is a MongoDB initialization script. You may want to keep the local file as db-init.js, but mount it inside a container under a more specific name such as init-script.js or 001-create-users.js.

Generating a ConfigMap from an Env File

Another useful option is envs. This tells Kustomize to parse a file that contains key-value pairs.

Create a local env file:

ENVIRONMENT=local
DB_HOST=http://localhost:27017
EXPOSE_METRICS=true

Save it as:

k8s/overlays/dev/.env.local

Then reference it with envs:

configMapGenerator:
  - name: local-config
    envs:
      - .env.local

Kustomize creates one ConfigMap key per env file entry:

apiVersion: v1
data:
  DB_HOST: http://localhost:27017
  ENVIRONMENT: local
  EXPOSE_METRICS: "true"
kind: ConfigMap
metadata:
  name: dev-local-config-alpha-bm7h2g6t5f
  namespace: dev

This is different from using files.

envs vs files

The difference between envs and files is one of the most important details to understand.

Generator sourceInput exampleResult in ConfigMap
literalsUSE_DB=trueOne key-value pair per literal
filesdb-init.jsOne key using the file name, with the full file content as value
files with custom keyinit-script.js=db-init.jsOne key using the custom key, with the full file content as value
envs.env.localOne key-value pair per line in the env file

For example, this configuration:

configMapGenerator:
  - name: local-config
    files:
      - .env.local

Does not parse the env file into separate keys. Instead, it creates one key named .env.local:

data:
  .env.local: |
    ENVIRONMENT=local
    DB_HOST=http://localhost:27017
    EXPOSE_METRICS=true

Use envs when you want each line to become a separate key. Use files when you want the whole file to be stored as one value.

Disabling the Name Suffix Hash Per Generator

By default, Kustomize adds a hash suffix to generated ConfigMaps. You can disable it for a specific generator entry:

configMapGenerator:
  - name: feature-flags-config
    literals:
      - USE_DB=true
      - EXPOSE_METRICS=true
    options:
      disableNameSuffixHash: true

The generated resource name becomes stable:

metadata:
  name: dev-feature-flags-config-alpha

This can be useful when an external system expects a fixed object name, but it removes one of the strongest rollout benefits of Kustomize generators.

When the hash is enabled, changes in generated data change the generated name. When that name is referenced from a Deployment, the Deployment output changes too. With disableNameSuffixHash: true, the generated name remains the same, so a Deployment that references it may not get a new pod template automatically.

That matters especially for environment variables. If a Pod consumes a ConfigMap through environment variables, those values are read when the container starts. Changing the ConfigMap does not update already-running environment variables. You usually need a rollout restart or a pod replacement.

Disabling the Hash Globally with generatorOptions

You can also configure generator behavior globally with generatorOptions:

generatorOptions:
  disableNameSuffixHash: true

This applies to all generated ConfigMaps in the same kustomization.yaml.

You can also add labels and annotations only to generated resources:

generatorOptions:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/component: generated-configuration
  annotations:
    generated-resource: "true"

This is different from the top-level labels field. Top-level labels can apply across all resources in the build. generatorOptions.labels only applies to resources produced by generators such as configMapGenerator.

Full ConfigMap Generator Example

Here is a complete dev overlay example:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: dev
namePrefix: dev-
nameSuffix: -alpha

resources:
  - ../../base

labels:
  - pairs:
      app.kubernetes.io/part-of: color-api
      environment: dev
    includeTemplates: true
    includeSelectors: false

generatorOptions:
  labels:
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/component: generated-configuration

configMapGenerator:
  - name: feature-flags-config
    literals:
      - USE_DB=true
      - EXPOSE_METRICS=true
      - ENABLE_NEW_UI=true

  - name: db-init-config
    files:
      - init-script.js=db-init.js

  - name: local-config
    envs:
      - .env.local

This single overlay generates three ConfigMaps:

  • feature-flags-config from literal key-value pairs.
  • db-init-config from a JavaScript file.
  • local-config from an env file.

Using a Generated ConfigMap in a Deployment

In your base Deployment, reference the generated ConfigMap by the generator name, without the hash:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: color-api
spec:
  template:
    spec:
      containers:
        - name: color-api
          image: color-api:1.0.0
          envFrom:
            - configMapRef:
                name: feature-flags-config
          volumeMounts:
            - name: db-init
              mountPath: /docker-entrypoint-initdb.d
      volumes:
        - name: db-init
          configMap:
            name: db-init-config

You do not need to manually write the hash in the Deployment. Kustomize rewrites the reference in the final output.

For example, the rendered Deployment may contain:

envFrom:
  - configMapRef:
      name: dev-feature-flags-config-alpha-7m2k9g5h8b
volumes:
  - name: db-init
    configMap:
      name: dev-db-init-config-alpha-4kgfh9k8hb

This is one of the best reasons to keep the hash enabled. The generated object name and the consuming workload stay in sync.

Applying the Overlay

To inspect the generated YAML without applying it:

kubectl kustomize k8s/overlays/dev

To apply the overlay:

kubectl apply -k k8s/overlays/dev

This is often the best workflow:

  1. Build locally with kubectl kustomize.
  2. Inspect the generated resources.
  3. Commit the overlay changes.
  4. Let your GitOps or CI/CD system apply the overlay.

Common Mistakes

Using files When You Wanted envs

If you want each key in .env.local to become a separate ConfigMap entry, use this:

envs:
  - .env.local

Not this:

files:
  - .env.local

The second version stores the complete file as one value.

Disabling the Hash Too Quickly

It can be tempting to disable the name suffix hash because stable names look cleaner. Be careful. The hash is useful because it makes configuration changes visible in generated resource names.

For workloads that consume generated ConfigMaps, that name change can help trigger a rollout.

Forgetting That Env Vars Do Not Update in Running Containers

If a container reads a ConfigMap as environment variables, the values are loaded when the container starts. Updating the ConfigMap does not magically update the process environment inside an already-running container.

Mounted volumes behave differently: Kubernetes can eventually update projected ConfigMap volumes, although applications still need to reload the files if they cache the values.

Using ConfigMaps for Sensitive Data

ConfigMaps are for non-sensitive configuration. Do not store passwords, tokens, private keys, or certificates in a ConfigMap. Those belong in Kubernetes Secrets or an external secret-management system.

Best Practices

  • Use literals for small, simple key-value pairs.
  • Use files for scripts, configuration files, and structured content.
  • Use envs for env-style files where each line should become an individual key.
  • Keep the hash suffix enabled unless you have a strong reason to disable it.
  • Use generatorOptions for labels and annotations that should apply only to generated resources.
  • Use top-level labels for labels that should apply across the full rendered output.
  • Avoid commonLabels in modern Kustomize examples.
  • Do not put sensitive values in ConfigMaps.
  • Inspect generated YAML with kubectl kustomize before applying it.

Conclusion

configMapGenerator is a very practical way to create ConfigMaps from real configuration sources. It lets you keep scripts as scripts, env files as env files, and simple feature flags as readable key-value pairs.

The most important distinction is how each source type is processed. literals create direct key-value pairs. files embed entire files. envs parse env-style files into separate keys.

The hash suffix is also important. It may look like random noise at first, but it helps Kustomize connect configuration changes to new Kubernetes object names and workload updates. Disable it only when you fully understand the rollout consequences.

Used carefully, configMapGenerator and generatorOptions make environment-specific Kubernetes configuration cleaner, more maintainable, and easier to reason about.

References

  • Kubernetes: Declarative Management of Kubernetes Objects Using Kustomize - kubernetes[.]io/docs/tasks/manage-kubernetes-objects/kustomization/
  • Kubernetes: ConfigMaps - kubernetes[.]io/docs/concepts/configuration/configmap/
  • Kubernetes: Configure a Pod to Use a ConfigMap - kubernetes[.]io/docs/tasks/configure-pod-container/configure-pod-configmap/
  • Kustomize: Kubernetes native configuration management - kustomize[.]io/
  • Kustomize: Generator Options - github[.]com/kubernetes-sigs/kustomize/blob/master/examples/generatorOptions.md
  • Kustomize: commonLabels deprecation warning discussion - github[.]com/kubernetes-sigs/kustomize/issues/5653

Post a Comment

0 Comments

Post a Comment (0)

#buttons=(Ok, Go it!) #days=(20)

This site uses cookies from Google to deliver its services and analyze traffic. Your IP address and user-agent are shared with Google along with performance and security metrics to ensure quality of service, generate usage statistics, and to detect and address abuse. More Info
Ok, Go it!