ConfigMaps in Kubernetes is a way to store and manage configuration data for your applications. Kubernetes ConfigMap allows you to decouple configuration from your application code, making it easier to manage and update configuration settings. In this article, you will learn about the ConfigMap, how to create it, how to use it, and Best Practices.

Do not store sensetive information in ConfigMaps, use Kubernetes Secrets instead.

What is ConfigMaps in Kubernetes?

ConfigMaps in Kubernetes are like storage boxes for your application’s configuration settings. They help you keep things organized by storing key-value pairs of configuration data separately from your application code. This makes it easy to manage and update settings without having to change your code every time.

ConfigMaps are powerful Kubernetes API Objects that allow you to decouple configuration artifacts from containerized applications. They provide a way to store non-sensitive configuration data in key-value pairs. Pods, containers, and other Kubernetes objects then consume it.

Here are some key points about ConfigMaps:

  • Usage: Pods can consume ConfigMaps as environment variables, command-line arguments, or configuration files in a volume.
  • Decoupling Configuration: By using ConfigMaps, you separate configuration data from your application code.
  • No Secrecy or Encryption: Keep in mind that ConfigMaps do not provide secrecy or encryption. For confidential data, use Secrets or other tools.
  • In the Kubernetes Cluster, the ConfigMaps are stored in the etcd database.

Example of ConfigMap:

First, create a file named configmap.yaml with the following content:

my-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-configmap
data:
  key1: value1
  key2: value2

Then, create the ConfigMap using the kubectl command:

kubectl create -f my-configmap.yaml

To view the contents of the ConfigMap, you can use the following command:

kubectl get configmap my-configmap -o yaml

Where are ConfigMaps Stored in Kubernetes?

In Kubernetes, ConfigMaps are stored as Kubernetes objects in the etcd distributed key-value database. Etcd is the primary data store used in the Kubernetes Control Plane.

When you create a ConfigMap using kubectl create configmap or by defining it in a YAML file and applying it with kubectl apply, the ConfigMap data is stored as a key-value pair in etcd. The key is the combination of the ConfigMap’s namespace and name, and the value is the ConfigMap’s data, including its metadata and the key-value pairs it contains.

All Kubernetes objects, including Pods, Services, Deployments, and ConfigMaps, are represented as entries in etcd. This allows the Kubernetes control plane components, such as the API server, scheduler, and controller managers, to read and modify the state of these objects as needed.

When a Pod needs to access the data from a ConfigMap, the Kubernetes API server retrieves the ConfigMap data from etcd and makes it available to the Pod. Either as environment variables or as files in a designated volume mount, depending on how the ConfigMap is consumed.

How to Create Kubernetes ConfigMaps?

There are several ways to create ConfigMaps in Kubernetes.

1. Create ConfigMap from literals with kubectl command:

Here is an example of how to create a ConfigMap for various configs of MySQL using kubectl command. In real-world application, this is not recommended approach:

kubectl create configmap mysql-config --from-literal=MYSQL_HOST=mysql --from-literal=MYSQL_USER=root --from-literal=MYSQL_DATABASE=todo_db

2. Create ConfigMap from YAML file:

The recommended approach is to alternatively use a YAML file mysql-config.yaml with the following content:

mysql-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  MYSQL_HOST: mysql
  MYSQL_USER: root
  MYSQL_DATABASE: todo_db

Then create the ConfigMap by running to create the ConfigMap named mysql-config with the specified key-value pairs.:

kubectl apply -f mysql-config.yaml

3. Create ConfigMap from Files

Step-1: First, Create a file named mysql-config.cnf with your desired MySQL configuration settings in your workspace. For example:

mysql-config.cnf
[mysqld]
innodb_buffer_pool_size = 256M
innodb_log_file_size = 50M
max_connections = 500

Step-2: Create the ConfigMap using kubectl:

kubectl create configmap mysql-config --from-file=mysql-config.cnf

Step-3: In your MySQL deployment YAML file, add a volume and volume mount to reference the ConfigMap:

    YAML
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mysql
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mysql
      template:
        metadata:
          labels:
            app: mysql
        spec:
          containers:
          - name: mysql
            image: mysql:5.7
            env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-root-password
                  key: password
            ports:
            - containerPort: 3306
            volumeMounts:
            - name: mysql-config-volume
              mountPath: /etc/mysql/conf.d
              readOnly: true
          volumes:
          - name: mysql-config-volume
            configMap:
              name: mysql-config

    In this example, we’ve added a volume named mysql-config-volume that references the mysql-config ConfigMap. We’ve also added a volume mount to the MySQL container that mounts the ConfigMap at /etc/mysql/conf.d. This will allow the MySQL container to read the configuration settings from the ConfigMap.

    Note that the mountPath of /etc/mysql/conf.d is the default location where MySQL looks for additional configuration files.

    4. Create ConfigMap from Directories

    Step-1: We will take an example of MongoDB deployment here. Create a new directory called mongo-conf and create the following files inside it:

    mongodb.conf
    # mongodb.conf
    
    # Where and how to store data.
    storage:
      dbPath: /data/db
      journal:
        enabled: true
    
    # Bind to local IP address only
    net:
      bindIp: 127.0.0.1

    Also, create the Log config file.

    mongodb-log.conf
    # mongodb-log.conf
    
    # Log file to send write audit activities
    systemLog:
      destination: file
      path: /var/log/mongodb/mongodb.log
      logAppend: true
    
    # Log level
    systemLog:
      verbosity: 0
      component:
        accessControl:
          verbosity: 0
    #### Other configs #####

    Step-2: Now you need to create the ConfigMpas from this directory using the following command:

    kubectl create configmap mongo-config --from-file=mongo-conf/

    This will create a ConfigMap named mongo-config with the contents of the mongo.conf and mongo-log.conf files.

    Step-3: Now, to use the ConfigMap in MongoDB deployment:

    YAML
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mongodb
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mongodb
      template:
        metadata:
          labels:
            app: mongodb
        spec:
          volumes:
          - name: config-mongodb
            configMap:
              name: mongo-config
          containers:
          - name: mongodb
            image: mongo:4.4
            ports:
            - containerPort: 27017
            volumeMounts:
            - name: config-mongodb
              mountPath: /etc/mongo

    This will create a MongoDB deployment with a single replica that uses the mongo-config ConfigMap to populate the MongoDB configuration file /etc/mongod.conf/mongo.conf.

    Note that we’ve used the subPath field to specify the name of the configuration file within the ConfigMap.

    List and inspecting ConfigMap in Kubernetes

    To list and inspect ConfigMaps in Kubernetes, you can use the kubectl command-line tool. Here are the steps:

    1. List ConfigMaps:

    To list all ConfigMaps in a specific namespace, use the following command:

    kubectl get configmaps -n <namespace>

    Replace <namespace> with the namespace where the ConfigMaps are located. If you want to list ConfigMaps across all namespaces, omit the -n <namespace> option.

    2. Inspect ConfigMap Details:

    To inspect the details of a specific ConfigMap, including its data and metadata, you can use the following command:

    kubectl describe configmap <configmap-name> -n <namespace>

    Replace <configmap-name> with the name of the ConfigMap you want to inspect, and <namespace> with the namespace where the ConfigMap is located.

    Example:

    Let’s say you have a ConfigMap named my-configmap in the default namespace. To list and inspect this ConfigMap, you would use the following commands:

    # List ConfigMaps in the default namespace
    kubectl get configmaps
    
    # Inspect details of the my-configmap ConfigMap in the default namespace
    kubectl describe configmap my-configmap

    These commands will provide you with information about the ConfigMap, including its name, data, and metadata such as labels, annotations, creation time, and more. This information can be useful for debugging, troubleshooting, and understanding the configuration of your Kubernetes resources.

    Using the ConfigMaps in Workloads:

    1. Mounting ConfigMap as a volume:

    I have provided a huge example here just to show you various ways in which ConfigMaps can be created. This YAML configuration defines a ConfigMap named nginx-conf with two key-value pairs under the data field:

    • nginx.conf: This contains the configuration for an Nginx server.
    • virtualhost.conf: This contains the configuration for a virtual host within Nginx
    • The ConfigMap named nginx-conf is used as a volume in the nginx container. The items specified within the ConfigMap (nginx.conf and virtualhost.conf) are mounted at /etc/nginx within the container.
    YAML
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: nginx-conf
    data:
      nginx.conf: |
        user nginx;
        worker_processes  3;
        error_log  /var/log/nginx/error.log;
        events {
          worker_connections  10240;
        }
        http {
          log_format  main
                  'remote_addr:$remote_addr\t'
                  'time_local:$time_local\t'
                  'method:$request_method\t'
                  'uri:$request_uri\t'
                  'host:$host\t'
                  'status:$status\t'
                  'bytes_sent:$body_bytes_sent\t'
                  'referer:$http_referer\t'
                  'useragent:$http_user_agent\t'
                  'forwardedfor:$http_x_forwarded_for\t'
                  'request_time:$request_time';
          access_log	/var/log/nginx/access.log main;
          include /etc/nginx/virtualhost/virtualhost.conf;
        }
      virtualhost.conf: |
        upstream spring-petclinic {
          server localhost:8080;
          keepalive 1024;
        }
        server {
          listen 80 default_server;
          access_log /var/log/nginx/app.access_log main;
          error_log /var/log/nginx/app.error_log;
          location / {
            proxy_pass http://spring-petclinic;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
          }
        }
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      selector:
        matchLabels:
          app: nginx
      replicas: 1
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
            - name: spring-petclinic
              image: dockerbikram/spring-petclinic:3.2.0
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
            - name: nginx
              image: nginx
              ports:
                - containerPort: 80
              volumeMounts:
                - mountPath: /etc/nginx # mount nginx-conf volumn to /etc/nginx
                  readOnly: true
                  name: nginx-conf
                - mountPath: /var/log/nginx
                  name: log
          volumes:
            - name: nginx-conf
              configMap:
                name: nginx-conf # place ConfigMap `nginx-conf` on /etc/nginx
                items:
                  - key: nginx.conf
                    path: nginx.conf
                  - key: virtualhost.conf
                    path: virtualhost/virtualhost.conf # dig directory
            - name: log
              emptyDir: {}

    2. Use ConfigMap as environment variables:

    Here Pod uses the ConfigMap database-config as environment variables:

    YAML
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: database-config
    data:
      DATABASE_URL: jdbc:mysql://localhost:3306/mydatabase
      DATABASE_NAME: mydatabase
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: java-app-pod
    spec:
      containers:
        - name: java-app-container
          image: your-java-app-image
          env:
            - name: DATABASE_URL
              valueFrom:
                configMapKeyRef:
                  name: database-config
                  key: DATABASE_URL
            - name: DATABASE_NAME
              valueFrom:
                configMapKeyRef:
                  name: database-config
                  key: DATABASE_NAME
    

    3. Mounting ConfigMaps as command line arguments:

    ConfigMap values can be interpolated into a container’s command line arguments as shown below.

    YAML
    apiVersion: v1
    kind: Pod
    metadata:
      name: demo-pod
    spec:
      containers:
        - name: app
          command: ["demo-app", "--database-host", "$(DATABASE_HOST)"]
          image: demo-app:latest
          env:
            - name: DATABASE_HOST
              valueFrom:
                configMapKeyRef:
                  name: database-config
                  key: DATABASE_URL

    4. Using Immutable ConfigMaps:

    Immutable ConfigMaps, introduced in Kubernetes 1.19, are ConfigMaps that cannot be updated after creation. This means that once a ConfigMap is created, its data cannot be changed.

    YAML
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: user-service-config
    immutable: true
    data:
      DATABASE_URL: jdbc:mysql://db.example.com:3306/users
      SERVER_PORT: "8080"
      LOG_LEVEL: INFO
    

    Updating ConfigMaps:

    In Kubernetes, there are several ways to update ConfigMaps. Here are some common methods:

    1. Imperative Command:

    You can update a ConfigMap imperatively using the kubectl command:

    kubectl create configmap my-config --from-file=new-config.txt --dry-run=client -o yaml | kubectl apply -f -

    In this command:

    • my-config is the name of the ConfigMap.
    • new-config.txt is the file you want to use to update the ConfigMap.
    • --dry-run=client is used to simulate the update without making actual changes.
    • -o yaml is used to output the result in YAML format.
    • | kubectl apply -f - pipes the YAML output to kubectl apply for applying the changes.

    2. Declarative Approach (recommended):

    You can update a ConfigMap declaratively by editing the YAML definition of the ConfigMap and then applying the changes using kubectl apply:

    kubectl apply -f updated-configmap.yaml

    In this method, you modify the YAML file containing the ConfigMap definition directly, making the necessary changes, and then apply the updated YAML file using kubectl apply.

    3. Editing ConfigMap Directly:

    You can also edit a ConfigMap directly using the kubectl edit command:

    kubectl edit configmap my-config

    This command opens the ConfigMap in your default editor, allowing you to make changes directly. Once you save and exit the editor, the changes will be applied automatically.

    4. Using kubectl patch:

    You can use kubectl patch to update specific fields of a ConfigMap without having to edit the entire ConfigMap:

    kubectl patch configmap my-config --patch "$(cat patch-file.yaml)"

    In this command, patch-file.yaml contains the patch to be applied to the ConfigMap.

    5. Using External Tools:

    There are also external tools and libraries available for managing Kubernetes resources, including ConfigMaps. Tools like Helm, Kustomize, or custom scripts can be used to update ConfigMaps in a more automated or controlled manner.

    Handle Sensitive Config values – ConfigMap vs Secrets

    Handling sensitive information in Kubernetes requires special consideration to maintain security and prevent unauthorized access. While ConfigMaps are suitable for storing non-sensitive configuration data, they are not designed to handle sensitive information such as passwords, API keys, or cryptographic keys. Instead, Kubernetes provides Secrets for managing sensitive data securely.

    Why use Secrets over ConfigMaps for sensitive information:

    1. Encryption: Secrets are encrypted at rest within etcd, the key-value store used by Kubernetes to store cluster data. This provides an additional layer of security compared to ConfigMaps, which are stored in plain text.
    2. Base64 Encoding: Secrets automatically encode data in Base64 format, which adds a layer of obfuscation. While Base64 encoding is not encryption, it does provide a level of obscurity compared to plain text storage.
    3. Access Control: Kubernetes allows fine-grained access control for Secrets, enabling you to define who can create, read, update, or delete Secrets. This level of access control is essential for managing sensitive data securely.
    4. Use in Volume Mounts: Secrets can be mounted into containers as volumes or exposed as environment variables, making it easy to inject sensitive information into applications securely at runtime.

    How to handle sensitive information in Secrets:

    1. Create Secrets: You can create Secrets using kubectl command-line tool or YAML manifests. Secrets can be created from literal values, files, or from environment variables.
       kubectl create secret generic my-secret --from-literal=password=secretPassword
    1. Access Control: Ensure that only authorized users or service accounts have access to create, read, or modify Secrets. Use Kubernetes RBAC (Role-Based Access Control) to define appropriate permissions.
    2. Volume Mounts: Mount Secrets as volumes or expose them as environment variables in your Pods. Ensure that sensitive data is accessed securely within the application.
    3. Avoid Logging: Avoid logging sensitive information stored in Secrets. Ensure that your application’s logging configuration does not inadvertently log sensitive data.
    4. Regular Rotation: Periodically rotate Secrets, especially credentials and keys, to minimize the risk of exposure due to potential breaches or leaks.

    By using Secrets to manage sensitive information in Kubernetes, you can ensure that your application’s security posture is robust and compliant with best practices for handling sensitive data.

    Conclusion:

    Kubernetes ConfigMaps provide a flexible and powerful way to manage configuration data in Kubernetes deployments. They allow you to decouple configuration from container images, making it easier to manage configurations across different environments and applications. By using ConfigMaps, you can store configuration data as key-value pairs or as files, and then mount them into your Pods as volumes or expose them as environment variables. This separation of configuration from application logic simplifies the management of configurations, promotes consistency, and facilitates the dynamic updating of configurations without the need to rebuild container images. With ConfigMaps, Kubernetes users can streamline the deployment process, enhance scalability, and improve the overall reliability of their applications.

    Remember, you will use Secrets to store sentivie information like Password, Access_keys in Kubernetes.

    By |Last Updated: May 12th, 2024|Categories: Kubernetes|

    Table of Contents