6 min read1 day ago
–
This project demonstrates how to mount external configuration and sensitive data into a container using Kubernetes ConfigMap and Secret volumes. We use Mosquitto (Eclipse Mosquitto 2.0) as an example.
Press enter or click to view image in full size
Mastering ConfigMap and Secret Volumes in Kubernetes with Mosquitto
In Kubernetes, ConfigMaps and Secrets go far beyond storing simple environment variables. They’re powerful mechanisms that let you inject configuration files, credentials, and certificates directly into your running containers the same way production-grade services like Prometheus, Nginx, or Elasticsearch manage their configuration.
Mounting these as volumes allows your applications to stay lightweight, stateless, an…
6 min read1 day ago
–
This project demonstrates how to mount external configuration and sensitive data into a container using Kubernetes ConfigMap and Secret volumes. We use Mosquitto (Eclipse Mosquitto 2.0) as an example.
Press enter or click to view image in full size
Mastering ConfigMap and Secret Volumes in Kubernetes with Mosquitto
In Kubernetes, ConfigMaps and Secrets go far beyond storing simple environment variables. They’re powerful mechanisms that let you inject configuration files, credentials, and certificates directly into your running containers the same way production-grade services like Prometheus, Nginx, or Elasticsearch manage their configuration.
Mounting these as volumes allows your applications to stay lightweight, stateless, and easily configurable without modifying their container images.
In this guide, we’ll explore how this works using Mosquitto, a lightweight and popular MQTT message broker. You’ll learn how to:
- Store configuration data using a ConfigMap
- Securely manage sensitive files using a Secret
- Mount both into a Mosquitto container through Kubernetes volume mounts.
By the end, you’ll have a clear understanding of how these two Kubernetes resources help separate configuration and secrets from your application a core principle in modern containerised deployments.
1. Why This Matters
Imagine you’re deploying an application that connects to 10 different external services, all secured.
You probably have a passwords.properties file or a set of client certificates that the app needs to start.
You don’t want to hardcode those credentials or rebuild the image each time configuration changes.
That’s where ConfigMaps and Secrets come in. They allow you to inject external configuration or sensitive files into your pods safely and dynamically.
There are two common use cases:
- **Storing individual key-value pairs: **for example, a database username, password, or host.
- **Storing and mounting complete files: **configuration files, certificates, or other static assets your app reads from disk.
Let’s explore both.
Press enter or click to view image in full size
2. The Classic Use Case: Individual Key-Value Pairs
You’ve probably seen this one before. For example, here’s a MongoDB ConfigMap and Secret that store connection details:
apiVersion: v1kind: ConfigMapmetadata: name: mongodb-configmapdata: database_url: mongodb-service
apiVersion: v1kind: Secretmetadata: name: mongodb-secrettype: Opaquedata: mongo-root-username: dXNlcm5hbWU= #base64 encoded mongo-root-password: cGFzc3dvcmQ= #base64 encoded
And here’s how those values are used inside a container, for example, in mongo-express.yaml [YAML FILE REFERENCE]
env: - name: ME_CONFIG_MONGODB_ADMINUSERNAME valueFrom: secretKeyRef: name: mongodb-secret key: mongo-root-username - name: ME_CONFIG_MONGODB_ADMINPASSWORD valueFrom: secretKeyRef: name: mongodb-secret key: mongo-root-password - name: ME_CONFIG_MONGODB_SERVER valueFrom: configMapKeyRef: name: mongodb-configmap key: database_url
This approach works great for injecting individual values, perfect for environment variables. But what if your application expects an actual file on disk?
3. The Real-World Scenario: Mounting Files as Volumes
Many applications, including Mosquitto, Elasticsearch, and Nginx, load configuration from files like mosquitto.conf, nginx.conf, or .pem certificate files.
You can use ConfigMaps and Secrets to mount those files directly into your container.
Let’s see how it works.
4. Creating the ConfigMap (Configuration File)
Here’s our config-file.yaml that defines a ConfigMap containing a Mosquitto configuration file:
apiVersion: v1kind: ConfigMapmetadata: name: mosquitto-config-filedata: mosquitto.conf: | log_dest stdout log_type all log_timestamp true listener 9001
Notice how we use the pipe symbol (**|**) to represent a multi-line string, this is the entire content of the file.
When mounted, this file will appear inside the container at /mosquitto/config/mosquitto.conf.
5. Creating the Secret (Sensitive File)
Next, let’s create a secret file, something that contains sensitive information like passwords or certificates.
In Secrets, we have to provide the content base64 encoded, so execute:
echo -n 'some supersecret file contents nobody should see' | base64OUTPUT => c29tZSBzdXBlcnNlY3JldCBmaWxlIGNvbnRlbnRzIG5vYm9keSBzaG91bGQgc2Vl
Here’s secret-file.yaml:
apiVersion: v1kind: Secretmetadata: name: mosquitto-secret-filetype: Opaquedata: secret.file: | c29tZSBzdXBlcnNlY3JldCBmaWxlIGNvbnRlbnRzIG5vYm9keSBzaG91bGQgc2Vl
This base64-encoded string decodes to a secret message but in real scenarios, it could be a password file or client certificate.
You can create similar Secrets for certificates, for example:
apiVersion: v1kind: Secretmetadata: name: my-secrettype: Opaquedata: cacert.pem: | base64-encoded-value-of-certificate
6. Deploying Mosquitto with Volumes
Now let’s put everything together in mosquitto.yaml:
apiVersion: apps/v1 # Use the apps/v1 API for Deploymentskind: Deployment # This resource will create a Deploymentmetadata: name: mosquitto # Name of the Deployment labels: app: mosquitto # Label to identify all pods managed by this Deploymentspec: replicas: 1 # Number of pod replicas to run selector: matchLabels: app: mosquitto # How the Deployment finds which pods to manage template: # Pod template metadata: labels: app: mosquitto # Label assigned to each pod spec: containers: - name: mosquitto # Container name image: eclipse-mosquitto:2.0 # Container image (Mosquitto version 2.0) ports: - containerPort: 1883 # Expose port 1883 (MQTT default) volumeMounts: # Mount volumes into the container - name: mosquitto-config mountPath: /mosquitto/config # Path in the filesystem inside the container - name: mosquitto-secret mountPath: /mosquitto/secret # Mount the Secret at this path readOnly: true # Prevent container from modifying secret files volumes: # Define volumes available to the pod - name: mosquitto-config configMap: name: mosquitto-config-file # Use the ConfigMap named "mosquitto-config-file" - name: mosquitto-secret secret: secretName: mosquitto-secret-file # Use the Secret named "mosquitto-secret-file"
Let’s break this down.
- The ConfigMap volume mounts the configuration file (
mosquitto.conf) into/mosquitto/config. - The Secret volume mounts the secret file into
/mosquitto/secretas read-only. - The
readOnly: trueattribute ensures the application can’t modify sensitive files. - The volumes section (under
spec) defines what resources (ConfigMaps/Secrets) the Pod has access to. - The volumeMounts section (inside each container) decides which container actually uses them useful when your Pod has multiple containers.
This separation gives fine-grained control you can choose which containers get access to which files.
7. Deployment Order
Before applying the Deployment, remember that the referenced ConfigMap and Secret must exist in the cluster.
If not, Kubernetes will throw an error.
So, always apply them in this order:
kubectl apply -f config-file.yamlkubectl apply -f secret-file.yamlkubectl apply -f mosquitto.yaml
8. Verifying Everything Works
Check the created resources:
kubectl get configmapkubectl get secretkubectl get deploymentkubectl get pod
Then inspect the files inside the container:
# Inspect the podkubectl exec -it [pod name] -- /bin/sh# Inside the container, view the configuration file:cat /mosquitto/config/mosquitto.conf# And view the secret file:cat /mosquitto/secret/secret.file
You’ll see both files exactly as defined in your ConfigMap and Secret mounted into the container’s file system.
9. Understanding the Concept Visually
Think of it like this:
- The ConfigMap and Secret exist as standalone Kubernetes resources.
- The Pod spec mounts them as volumes (makes them available to the Pod).
- The Container spec mounts them again into its own filesystem (decides where they appear).
This two-level structure (Pod → Container) is what gives Kubernetes flexibility in managing multiple containers within a single Pod.
10. Final Thoughts
What we just did is something you’ll repeat over and over in production setups.
Whether it’s:
- NGINX loading
/etc/nginx/nginx.conf - Elasticsearch reading
/usr/share/elasticsearch/config/elasticsearch.yml - Or your own app needing
/app/config/application.properties
ConfigMaps and Secrets are how you inject those files into containers cleanly and securely.
They may not look like “typical volumes,” but they are indeed local volume types in Kubernetes. Once you understand that, a lot of things click into place.
So next time you see a container expecting a config or certificate file, you’ll know exactly how to handle it.
Once you grasp this concept, you’re not just deploying apps anymore you’re architecting clean, maintainable configurations.