DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

How to Mount a file inside a pod using configmap

— ny_wk

How to Mount a file inside a pod using configmap

Ever found yourself needing to inject a specific file, like a critical SSL certificate (a .pem, .crt, or .cer), directly into a running Kubernetes or OpenShift pod without rebuilding your Docker image? This guide walks you through the precise, expert-level method of mounting a single file inside a pod using a ConfigMap, leveraging the powerful subPath feature to avoid common pitfalls like overwriting essential system files.

As a DevOps engineer, you'll often encounter scenarios where you need to deliver configuration, scripts, or certificates to your applications running in containers. While Dockerfile is great for static assets, dynamic or sensitive configurations, especially certificates, are best managed outside the image. That's where Kubernetes ConfigMaps come into play. They are a powerful API object used to store non-confidential data in key-value pairs, which can then be consumed by pods as environment variables, command-line arguments, or as files in a volume.

Understanding the 'Why': When Dockerfile Isn't Enough

So, you're building an application, say a microservice that needs to talk to a backend secured by a custom Certificate Authority (CA). Normally, you might add your .pem file into the Dockerfile and run update-ca-certificates during the image build process. This works, no doubt, but what if:

  • You don't have control over the Dockerfile (e.g., using a third-party image).
  • The certificate changes frequently, and you want to avoid constant image rebuilds.
  • The certificate is environment-specific (dev, staging, prod) and you want to manage it externally from the image.
  • The `update-ca-certificates` command isn't available or suitable in your base image.
  • You need to inject a certificate into a read-only filesystem or a specific, non-standard path within the container.

In such situations, directly plugging in your .pem data into the Dockerfile and running update-ca-certificates becomes impractical or impossible. That's our cue to use Kubernetes ConfigMaps for dynamic file injection. It's cleaner, more flexible, and lets you manage your certificates independent of your application images.

Before making any changes to your production or even staging environments, always, always take a backup of your deployment configurations and pod specs. Whether it's a simple `kubectl get deployment -o yaml > deployment_backup.yaml` or using version control like Git, having a rollback plan is non-negotiable. Galati se, you know, ho sakti hai! So, better safe than sorry, right?

Demystifying ConfigMaps: Your Go-To for Configuration

A ConfigMap is essentially a dictionary of configuration data. It allows you to decouple configuration artifacts from image content to keep containerized applications portable. ConfigMaps can store data as plaintext, which makes them suitable for non-sensitive data like URLs, port numbers, or feature flags. For sensitive data like passwords or API keys, Kubernetes Secrets are the way to go, though the mounting mechanism we're discussing today is very similar for both.

When you use a ConfigMap to mount a file, Kubernetes takes the data from the ConfigMap, converts it into files, and places them into a specified directory within your pod. The key in the ConfigMap becomes the filename, and its value becomes the file's content.

Step-by-Step Guide: Mounting a File Inside a Pod Using ConfigMap `subPath`

Let's get our hands dirty and walk through the exact steps. We'll use a `my-cert.pem` file as our example certificate, aiming to place it directly into `/etc/ssl/certs/` inside our pod.

Step 1: Create the ConfigMap from your File

First things first, you need to get your certificate data into a ConfigMap. The easiest way to do this is to create the ConfigMap directly from your local certificate file.

Let's say you have a certificate file named my-cert.pem in your current directory. To create a ConfigMap from this file, you'd use the kubectl create configmap command with the --from-file flag:

kubectl create configmap ca-pemstore --from-file=my-cert.pem

If your certificate file is named differently, like devapp254_full.cer, then:

kubectl create configmap devapp-cert-config --from-file=devapp254_full.cer

You can also specify a namespace if you want the ConfigMap to reside outside the default namespace:

kubectl -n <your-namespace> create configmap ca-pemstore --from-file=my-cert.pem

What if you have multiple certificates or a whole bundle in a directory? Say you have a folder named ca-bundle containing multiple .pem files. You can create a ConfigMap from an entire directory:

kubectl create configmap test-crt --from-file=ca-bundle

In this case, each file within the ca-bundle directory will become a key-value pair in the test-crt ConfigMap. For example, if `ca-bundle` contains `intermediate.pem` and `root.pem`, the ConfigMap `test-crt` will have two keys: `intermediate.pem` and `root.pem`, with their respective file contents as values.

You can verify your ConfigMap creation:

kubectl get configmap ca-pemstore -o yaml

You'll see something like this:

apiVersion: v1
data:
  my-cert.pem: |
    -----BEGIN CERTIFICATE-----
    MIID... (your certificate content) ...ID==
    -----END CERTIFICATE-----
kind: ConfigMap
metadata:
  name: ca-pemstore
  # ... other metadata ...

Dekho, your certificate content is now stored under the key `my-cert.pem` within the `ca-pemstore` ConfigMap. This is crucial for the next step.

Step 2: Mount the ConfigMap File as a One-to-One Relationship in Your Pod

Now, this is where the magic happens and where the crucial detail of `subPath` comes in. To mount this specific file (my-cert.pem) from your ConfigMap into your pod's filesystem at a specific path (e.g., `/etc/ssl/certs/my-cert.pem`), you need to define a volume and a volumeMount in your Deployment, Pod, or StatefulSet configuration.

Here's how you'd modify your deployment configuration file. We'll use a sample Deployment spec. Pay close attention to the volumes and volumeMounts sections, especially the subPath field.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-deployment
  labels:
    app: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: your-app-image:v1.0
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: config-volume # This name must match a volume defined below
          mountPath: /etc/ssl/certs/devapp254_full.cer # The exact path where the file should appear
          subPath: devapp254_full.cer # Crucial: This is the key from your ConfigMap
          readOnly: true # Good practice for certs
        # ... other volumeMounts if any ...
        # For example, if you had other secrets or certificates
        - mountPath: /etc/secret
          name: client-credentials
          readOnly: true
      volumes:
      - name: config-volume # This name links to the volumeMount above
        configMap:
          name: devapp-cert-config # The name of your ConfigMap
          defaultMode: 420 # Optional: permissions for the mounted file
      # ... other volumes if any ...
      - name: client-credentials
        secret:
          defaultMode: 420
          secretName: users-grants-be-client-credentials
      # Example for the `test-crt` ConfigMap from a directory (if you used it)
      # - name: ca-bundle-volume
      #   configMap:
      #     name: test-crt
      #     defaultMode: 420

Let's break down the key parts:

  1. volumes section:
    • name: config-volume: This is an arbitrary name you give to your volume. It acts as an identifier.
    • configMap:: This tells Kubernetes that this volume will be populated from a ConfigMap.
    • name: devapp-cert-config: This is the actual name of the ConfigMap you created in Step 1. Kubernetes will look for a ConfigMap with this name in the same namespace as your pod (or the namespace specified during ConfigMap creation).
    • defaultMode: 420: (Optional but recommended) Sets the permissions for the files mounted from this ConfigMap. 420 (octal) corresponds to read-only for owner and group (rw-r--r-- for 644, or `r--r--r--` for 444, so 420 is rwxr-x---, often `0444` is used for certs).
  2. volumeMounts section (inside your container definition):
    • name: config-volume: This links back to the config-volume defined in the volumes section.
    • mountPath: /etc/ssl/certs/devapp254_full.cer: This is the *exact path and filename* inside your container where you want your certificate to appear.
    • subPath: devapp254_full.cer: This is the CRITICAL part. It specifies *which specific key* from the `devapp-cert-config` ConfigMap should be mounted at the `mountPath`. Since we created the ConfigMap with --from-file=devapp254_full.cer, the key in the ConfigMap is `devapp254_full.cer`. By using `subPath`, you're telling Kubernetes to mount *only* the content associated with that key, as a file, at the specified `mountPath`.
    • readOnly: true: Good practice for configuration files like certificates. Prevents accidental modifications from within the pod.

Example: Mounting `my-cert.pem` into a Pod

Let's consider another straightforward example directly from the source, using a simple Pod definition:

apiVersion: v1
kind: Pod
metadata:
  name: cacheconnectsample
spec:
  containers:
  - name: cacheconnectsample
    image: cacheconnectsample:v1
    volumeMounts:
    - name: ca-pemstore # Volume name
      mountPath: /etc/ssl/certs/my-cert.pem # Desired file path inside pod
      subPath: my-cert.pem # Key from the ConfigMap
      readOnly: false # Can be true for certs, depends on use case
    ports:
    - containerPort: 80
    command: [ "dotnet" ]
    args: [ "cacheconnectsample.dll" ]
  volumes:
  - name: ca-pemstore # Volume definition
    configMap:
      name: ca-pemstore # ConfigMap name

In this example, the ConfigMap `ca-pemstore` (which we created earlier from `my-cert.pem`) will have its key `my-cert.pem` mounted as a file at `/etc/ssl/certs/my-cert.pem` inside the `cacheconnectsample` container. Simple, elegant, and effective!

The Magic of `subPath`: Preventing Data Loss

This is arguably the most crucial takeaway from this entire discussion, junior! Pay attention. If you don't use subPath and instead map the entire ConfigMap volume to a directory, you're in for a nasty surprise.

Consider this incorrect (for our use case) configuration:

# This is the WRONG way if you want to preserve existing files!
volumeMounts:
- mountPath: /etc/ssl/certs/ # Mounting the entire ConfigMap as a directory here
  name: config-volume
volumes:
- name: config-volume
  configMap:
    name: ca-pemstore

What will happen here? Kubernetes will mount the `ca-pemstore` ConfigMap as a directory at `/etc/ssl/certs/`. If `ca-pemstore` contains `my-cert.pem`, then `/etc/ssl/certs/my-cert.pem` will appear. But here's the catch: when you mount a ConfigMap (or any volume) as a directory, it overwrites and hides anything that was previously in that directory. This means all your existing system certificates in `/etc/ssl/certs/` (like those provided by the base image or OS) will be wiped out and inaccessible! Your application might suddenly fail to connect to common services like apt, yum, or even external APIs using standard CAs.

By using subPath, you tell Kubernetes to mount only a *single specific file* from the ConfigMap into the target directory, without affecting other existing files or directories. It's like precisely placing one new book onto a shelf without disturbing the hundreds of others already there. This ensures that along with all existing certificates in the CA root directory of the pod, your custom `.cert` file is *added*, not replaced. This is the difference between a working application and a very confusing outage. Samjha?

Behind the Scenes: How it Compares to `update-ca-certificates`

You might be wondering, "Is this similar to `update-ca-certificates`?" Yes, partially, but with key differences:

  • `update-ca-certificates` command: This command, commonly found in Debian-based systems, scans a set of directories (e.g., `/usr/local/share/ca-certificates/`) for certificate files, processes them, creates symbolic links, and then concatenates them all into a single bundle file (typically `/etc/ssl/certs/ca-certificates.crt`). Applications then typically read this bundled file to trust various CAs.
  • ConfigMap mounting with `subPath`: When you mount a certificate using ConfigMap and `subPath`, you are simply placing your `my-cert.pem` file at the specified `mountPath` (e.g., `/etc/ssl/certs/my-cert.pem`).

The key differences are:

  • Symbolic Links: `update-ca-certificates` creates symbolic links and manages a unified bundle. ConfigMap mounting just places the raw file.
  • `ca-certificates.crt` Modification: `update-ca-certificates` appends your certificate text into the main `ca-certificates.crt` bundle. ConfigMap `subPath` mounting *does not* append your certificate to `ca-certificates.crt`; it adds it as a *separate file*.

Despite these differences, it often works the same way. Many applications and system libraries that rely on CA certificates are configured to scan the entire `/etc/ssl/certs/` directory for individual `.pem`, `.crt`, or `.cer` files, not just the `ca-certificates.crt` bundle. So, by placing your custom certificate directly in that directory, your application (or its underlying libraries like OpenSSL) will usually pick it up automatically, and no additional changes are required within your application code.

Common Pitfalls and Best Practices

Even with a clear understanding, a few common mistakes can trip you up. Here’s how to navigate them like a pro:

1. The `subPath` Trap: Directory vs. File Mounts

As discussed, this is the biggest one.

Pitfall: Mounting a ConfigMap volume *without* subPath into a directory like `/etc/ssl/certs/`.

Result: All existing files in `/etc/ssl/certs/` (including default CA certificates) are hidden by the ConfigMap content, potentially breaking network connectivity or certificate validation for your application and even system tools.

Best Practice: Always use subPath when you intend to mount a single file from a ConfigMap into an existing directory to preserve its contents.

2. Permissions and `defaultMode`

Pitfall: Not specifying appropriate permissions.

Result: Your application might fail to read the certificate due to incorrect file permissions.

Best Practice: Use `defaultMode` in your `ConfigMap` volume definition to set file permissions. For certificates, `0444` (read-only for all) or `0400` (read-only for owner) are common and secure choices. For example:

volumes:
- name: ca-pemstore
  configMap:
    name: ca-pemstore
    defaultMode: 0444 # Read-only for everyone

3. ConfigMap Immutability (Kubernetes 1.18+)

Pitfall: Expecting ConfigMaps to be mutable by default.

Result: If you update a ConfigMap, pods using it won't automatically see the changes unless they are recreated or explicitly configured to watch for changes (which is complex for file mounts).

Best Practice: For critical configuration like certificates, treat ConfigMaps as immutable. If a certificate needs to be updated, create a *new* ConfigMap with a new name (e.g., `ca-pemstore-v2`) and update your Deployment to reference the new ConfigMap. Then perform a rolling update of your deployment. This ensures a clean rollout and avoids unexpected behavior. You can mark a ConfigMap as truly immutable by adding `immutable: true` to its metadata, which prevents accidental updates.

apiVersion: v1
kind: ConfigMap
metadata:
  name: ca-pemstore-v2
  immutable: true # Prevents accidental modifications
data:
  my-cert.pem: |
    -----BEGIN CERTIFICATE-----
    ...new cert content...
    -----END CERTIFICATE-----

4. Validating the Mount

Pitfall: Assuming the mount worked without verification.

Result: Application failures that are hard to debug because you believe the certificate is there when it isn't.

Best Practice: After deploying, always shell into the pod and verify the file's presence and content.

kubectl exec -it <your-pod-name> -- /bin/bash
ls -l /etc/ssl/certs/
cat /etc/ssl/certs/my-cert.pem

Also, check your application logs for any certificate-related errors during startup.

5. Namespace Consistency

Pitfall: Creating a ConfigMap in one namespace and trying to mount it from a pod in another.

Result: The pod won't find the ConfigMap and will fail to start.

Best Practice: Ensure your ConfigMap and the pod consuming it are in the same namespace, or use advanced techniques like cross-namespace volume projections if your cluster setup supports it (which is rare for direct ConfigMap mounts).

Advanced Scenarios and Alternatives

While ConfigMaps with `subPath` are excellent for many certificate injection needs, it's good to know other methods for completeness:

  • Init Containers: For complex certificate processing (e.g., downloading from a secure source, running `update-ca-certificates` in a specific way), an init container can be used. This container runs to completion before your main application container starts, preparing the environment or fetching resources. It can fetch the cert, place it in a shared emptyDir volume, and then the main container can pick it up.
  • Custom Base Images: If you have full control over your Dockerfiles and the certificates are static and rarely change, embedding them directly into a custom base image is still a viable option. This reduces Kubernetes configuration overhead but increases image build times and maintenance.
  • CSI Drivers for Secret Stores: For highly sensitive certificates or those managed by external secret management systems (like HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager), you can use the Secrets Store CSI Driver. This allows Kubernetes to mount secrets from external stores directly as volumes into your pods, often with automatic rotation capabilities. This is the gold standard for production-grade secret management.

For most day-to-day scenarios where you just need to drop a certificate file into an existing directory without disturbing other files, our ConfigMap `subPath` method remains the simplest and most effective Kubernetes-native solution. It strikes a good balance between flexibility and operational ease.

Key Takeaways

  • Use Kubernetes ConfigMaps to decouple configuration, like certificates, from your container images.
  • Always back up your configurations before making changes to Kubernetes deployments.
  • Create ConfigMaps from files using kubectl create configmap --from-file=<filename>.
  • Crucially, use the subPath field in your volumeMounts to mount a *single file* from a ConfigMap.
  • Mounting a ConfigMap as an entire directory without subPath will overwrite existing files in the mount target, leading to potential outages.
  • Verify the mounted file's presence and content inside the pod using kubectl exec.

Frequently Asked Questions

Can I mount multiple files from a single ConfigMap into different paths?

Yes, absolutely! You can define multiple volumeMounts for the same ConfigMap volume, each using a different subPath and mountPath combination. For example, you could have `my-cert.pem` mounted at `/etc/ssl/certs/my-cert.pem` and `my-key.key` (from the same ConfigMap) mounted at `/etc/secrets/my-key.key`.

What happens if the ConfigMap key specified in `subPath` doesn't exist?

If the subPath you specify does not correspond to a key in the referenced ConfigMap, the pod will fail to start, and you'll typically see an error message in the pod events indicating that the specified key could not be found. Always double-check your ConfigMap keys and `subPath` values.

Can I use this method for binary files?

While ConfigMaps are primarily designed for non-confidential, UTF-8 encoded string data, they can technically store small binary data (like very small certificates or icons) if you base64 encode them first. However, for larger binary files or more sensitive binary assets, Kubernetes Secrets or specialized volume types like `emptyDir` combined with an init container for fetching are generally better choices.

Is `subPath` available for Secrets as well?

Yes, the `subPath` functionality works identically for Kubernetes Secrets. This means you can mount individual secret keys as files inside your pod, preventing the overwriting of existing directory contents, just like with ConfigMaps.

So, there you have it! Mounting a file inside your Kubernetes pods using ConfigMaps and the powerful `subPath` feature is a robust and flexible way to manage your configurations, especially certificates. Keep these best practices in mind, and you'll navigate your Kubernetes deployments like a seasoned pro.

For a deeper dive and a visual walkthrough of this process, be sure to watch the original video on this topic. You can find more insightful DevOps content and tutorials by subscribing to @explorenystream!