Part of the series Kubernetes basics

Kubernetes ConfigMaps, NGINX, and TLS: A simple guide

A ConfigMap stores the settings. Kubernetes delivers them. NGINX must read them. Follow the whole journey with an end-to-end diagram and a small hands-on example.

, 7 min read

Imagine a restaurant. The kitchen is your application. The recipe tells the kitchen how to prepare a meal.

Changing the recipe on the noticeboard does not mean the cook has read it yet.

That is the main idea behind Kubernetes ConfigMaps: saving new settings and using new settings are two different steps.

The pieces in plain language

Piece Think of it as… What it does
Container image The kitchen equipment Packages the application and what it needs to run.
ConfigMap The recipe sheet Stores settings that are safe to share.
Secret A restricted drawer Holds sensitive values, such as passwords and TLS private keys.
Pod A running kitchen Runs one or more containers.
Deployment The kitchen manager Keeps the desired number of Pods running through ReplicaSets.
Service A stable front door Directs traffic to the application’s ready Pod endpoints.
NGINX The server at the counter Serves web content or forwards requests to another application.
TLS A protected conversation Encrypts the connection used by HTTPS.

A ConfigMap can hold a port number, a log level, or an entire configuration file. Keep passwords and private keys in a Secret instead. A Secret still needs access controls; base64 encoding is not encryption.

Follow the end-to-end flow

The diagram separates configuration delivery from website traffic. Read the top path first, then the bottom path. On a phone, swipe sideways inside the diagram to see the full flow.

Open the full end-to-end diagram.

In the top path, you save settings in a ConfigMap. Kubernetes makes them available as files inside the Pod. NGINX reads those files when it starts or reloads.

In the bottom path, a browser connects to an externally reachable Service address. Traffic reaches NGINX in a Pod, where TLS is handled in this example. NGINX sends the response back over the connection.

A ConfigMap is not a network stop. Browser requests do not pass through it. Also, TLS may end at an Ingress controller or load balancer in other designs. Change TLS settings on the component that actually handles that connection.

Try a small ConfigMap example

Start with plain HTTP so you can learn configuration delivery without also setting up certificates. You need kubectl connected to a Kubernetes cluster and permission to create resources in a namespace named demo.

Save this as nginx-demo.yaml, or download the complete example.

apiVersion: v1
kind: Namespace
metadata:
  name: demo
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-settings
  namespace: demo
data:
  default.conf: |
    server {
      listen 8080;
      location / {
        default_type text/plain;
        return 200 "Hello from ConfigMap v1\n";
      }
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-web
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-web
  template:
    metadata:
      labels:
        app: demo-web
    spec:
      containers:
        - name: nginx
          image: nginx:stable
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /
              port: 8080
          volumeMounts:
            - name: settings
              mountPath: /etc/nginx/conf.d
              readOnly: true
      volumes:
        - name: settings
          configMap:
            name: nginx-settings
---
apiVersion: v1
kind: Service
metadata:
  name: demo-web
  namespace: demo
spec:
  selector:
    app: demo-web
  ports:
    - port: 80
      targetPort: 8080

The ConfigMap key default.conf becomes a file at /etc/nginx/conf.d/default.conf. NGINX loads files from that directory. Mounting a directory hides the image’s original files at that location, so supply all the files you need there.

The Service receives traffic on port 80 and targets the Pod on port 8080. This example’s Service is internal; it does not create a public address.

Apply it, wait for the rollout, and open a local tunnel:

kubectl apply -f nginx-demo.yaml
kubectl rollout status deployment/demo-web -n demo
kubectl port-forward service/demo-web 8080:80 -n demo

Leave that terminal running. In another terminal:

curl http://localhost:8080

You should see Hello from ConfigMap v1. This checks the application through a local port-forward; it does not test public exposure or the normal Service network path.

The floating nginx:stable tag keeps this learning example short. For a repeatable release, choose and pin a tested image version or digest.

What happens when you change the ConfigMap?

In your YAML file, change Hello from ConfigMap v1 to Hello from ConfigMap v2, then apply it again:

kubectl apply -f nginx-demo.yaml

Kubernetes saves the new value. With this normal directory mount, the file inside the Pod updates eventually. NGINX continues using its loaded settings until it reloads or restarts.

Check whether the new text has reached the mounted file:

kubectl exec -n demo deployment/demo-web -- \
  cat /etc/nginx/conf.d/default.conf

Wait until that file shows v2. Then validate the files and ask NGINX to reload:

kubectl exec -n demo deployment/demo-web -- nginx -t
# Continue only if the syntax check succeeds.
kubectl exec -n demo deployment/demo-web -- nginx -s reload
curl http://localhost:8080

The response should now contain v2. These commands target one Pod; that is enough for this one-replica example. With multiple replicas, each NGINX process needs the new configuration and a reload, or you can use a controlled rollout.

A reload keeps the Pod and asks NGINX to reread its files. A rolling restart replaces the Deployment’s Pods:

kubectl rollout restart deployment/demo-web -n demo
kubectl rollout status deployment/demo-web -n demo

If you use a restart, reconnect the port-forward after the old Pod exits. Availability during a rollout depends on readiness, capacity, replica count, and the update strategy.

Three update rules to remember

How the setting reaches the container What a ConfigMap edit does
Environment variable Does not update the running process’s environment. Replace the Pod to pick it up.
Normal ConfigMap volume Files update eventually. The application may need a reload.
A file mounted with subPath The existing mount does not receive ConfigMap updates. Replace the Pod.

Updating a ConfigMap alone does not trigger a Deployment rollout. These differences are documented in the Kubernetes ConfigMap guide.

Where HTTPS and TLS fit

HTTP carries web requests and responses. HTTPS carries HTTP over a connection protected by TLS.

For a usual HTTPS website, a certificate helps the browser check the server’s identity. The matching private key stays on the server. TLS also protects data from being read or changed in transit.

Here is a small NGINX HTTPS configuration fragment. It is separate from the HTTP lab above:

server {
    listen 443 ssl;
    server_name shop.example.com;

    ssl_certificate     /etc/nginx/tls/tls.crt;
    ssl_certificate_key /etc/nginx/tls/tls.key;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        return 200 "Hello over HTTPS\n";
    }
}

The ssl_protocols line allows TLS 1.2 and TLS 1.3. The client and server need a version and other connection settings they both support.

The fragment alone will not enable HTTPS in the lab. You also need a valid certificate for your hostname, its matching private key mounted from a Secret, and a Service port pointing to NGINX’s port 443. Public access needs a reachable entry point and DNS as well. See the NGINX SSL module documentation.

To check an actual HTTPS endpoint, replace the example hostname with yours:

curl -v --tlsv1.2 --tls-max 1.2 https://shop.example.com/
curl -v --tlsv1.3 --tls-max 1.3 https://shop.example.com/

These force an exact TLS version. Your local curl must support the requested version, and certificate verification must succeed. A failed request can also mean DNS, networking, or certificate trouble; inspect the error before blaming the protocol setting.

nginx -t checks the configuration files. It does not prove clients can reach the website. Test the actual endpoint after a reload, and remember that a proxy in front may handle TLS instead of your NGINX Pod.

Immutable means the settings are locked

An immutable ConfigMap blocks changes to its data and binaryData. Set immutable: true at the top level:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-settings-v1
  namespace: demo
immutable: true
data:
  LOG_LEVEL: "info"

This is a separate example of the lock. NGINX does not automatically use this LOG_LEVEL key; an application must explicitly read a setting for it to have an effect.

You cannot turn the lock off or edit that object’s data afterward. An authorized user can still delete it, and immutability does not encrypt it.

For the next release, create a new ConfigMap, such as nginx-settings-v2, containing the full new configuration. Change the Deployment’s volumes[].configMap.name to that name and apply the Deployment. Changing the Pod template triggers a rollout.

Keep the previous ConfigMap while you may still need to roll back. A Deployment rollback does not restore ConfigMap data that you edited or deleted. Versioned names make it easier to keep each release’s settings together.

A simple troubleshooting order

Follow the same direction as the diagram:

  1. Stored settings: inspect kubectl get configmap nginx-settings -n demo -o yaml.
  2. Delivered file: read the mounted default.conf inside the Pod.
  3. Application: run nginx -t, reload if needed, and inspect kubectl logs -n demo deployment/demo-web.
  4. Traffic: check kubectl get pods,service,endpointslices -n demo, then test the response.
  5. HTTPS: identify where TLS ends, then check DNS, certificate validity, and the negotiated version.

The question at each step is small: Is this layer doing its job?

When you finish the HTTP lab, stop the port-forward with Ctrl+C. To remove only the lab workload resources:

kubectl delete service/demo-web deployment/demo-web configmap/nginx-settings -n demo

Remember the recipe sheet: store the settings → deliver the file → let NGINX read it → test the result. For a release you want to keep fixed, use a versioned immutable ConfigMap.

Official references