<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged 40daysofkubernetes</title>
<link>https://coderlegion.com/tag/40daysofkubernetes</link>
<description>Powered by Question2Answer</description>
<item>
<title>Kubernetes ConfigMaps and Secrets</title>
<link>https://coderlegion.com/21757/kubernetes-configmaps-and-secrets</link>
<description>&lt;p&gt;Today's mission: stop hardcoding values into pod manifests and learn how to inject them properly using &lt;strong&gt;ConfigMaps&lt;/strong&gt; and &lt;strong&gt;Secrets&lt;/strong&gt;. I also managed to break a few things along the way, which honestly taught me more than if everything had just worked first try. Let's get into it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-is-a-configmap-&quot;&gt;What is a ConfigMap?&lt;/h3&gt;
&lt;p&gt;As your manifest grows, it becomes harder to manage a pile of environment variables directly inside it. A ConfigMap lets you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pull those key-value pairs &lt;strong&gt;out of the manifest&lt;/strong&gt; and store them as their own Kubernetes object&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inject&lt;/strong&gt; that ConfigMap into a pod as environment variables (or as files, but that's for another day)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reuse&lt;/strong&gt; the same ConfigMap across multiple pods, so you're not repeating yourself everywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basically, it's a clean way to separate configuration from your application definition.&lt;/p&gt;
&lt;h4 id=&quot;creating-a-configmap&quot;&gt;Creating a ConfigMap&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create cm app-cm --from-literal=firstname=adeoye --from-literal=lastname=malumi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;firstname&lt;/code&gt; and &lt;code&gt;lastname&lt;/code&gt; are the keys, and &lt;code&gt;adeoye&lt;/code&gt; / &lt;code&gt;malumi&lt;/code&gt; are the values.&lt;/p&gt;
&lt;h4 id=&quot;my-first-gotcha-of-the-day&quot;&gt;My first &quot;gotcha&quot; of the day&lt;/h4&gt;
&lt;p&gt;I actually tried to split this command across two lines like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create cm app-cm --from-literal=firstname=adeoye \
--from-literal=lastname=malumi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First attempt gave me:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error: exactly one NAME is required, got 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turns out I had a trailing space &lt;em&gt;after&lt;/em&gt; the backslash on the first line. In bash, the &lt;code&gt;\&lt;/code&gt; has to be the very last character on the line for line continuation to work. A space after it breaks the continuation, and the shell just treats the next line as a separate (garbled) argument. When I finally got the syntax right, &lt;code&gt;kubectl describe cm app-cm&lt;/code&gt; showed the value for &lt;code&gt;firstname&lt;/code&gt; as &lt;code&gt;adeoye--from-literal=lastname=malumi&lt;/code&gt; — my second flag had literally been glued onto the first value as text!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson learned:&lt;/strong&gt; either keep the command on one line, or make sure there's truly nothing (not even a space) after your &lt;code&gt;\&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once fixed, &lt;code&gt;describe&lt;/code&gt; showed exactly what I wanted:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Data
====
firstname:
----
adeoye

lastname:
----
malumi
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;injecting-a-configmap-into-a-pod&quot;&gt;Injecting a ConfigMap into a Pod&lt;/h3&gt;
&lt;p&gt;Here's the pod manifest I used to consume the ConfigMap as environment variables:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app.kubernetes.io/name: MyApp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    env:
    - name: FIRSTNAME
      valueFrom:
        configMapKeyRef:
          name: app-cm
          key: firstname
    command: ['sh', '-c', 'echo The app is running! &amp;amp;&amp;amp; sleep 3600']
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;valueFrom.configMapKeyRef&lt;/code&gt; block tells Kubernetes: &quot;don't hardcode this value — go fetch it from the &lt;code&gt;app-cm&lt;/code&gt; ConfigMap, using the &lt;code&gt;firstname&lt;/code&gt; key.&quot;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;gotcha-2-pods-are-mostly-immutable&quot;&gt;Gotcha #2: Pods are mostly immutable&lt;/h3&gt;
&lt;p&gt;After creating my ConfigMap with both &lt;code&gt;firstname&lt;/code&gt; and &lt;code&gt;lastname&lt;/code&gt;, I went back and added a &lt;code&gt;LASTNAME&lt;/code&gt; env var to my already-running pod's manifest, then ran:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl apply -f pod.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And got slapped with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The Pod &quot;myapp-pod&quot; is invalid: spec: Forbidden: pod updates may not change fields other than 
`spec.containers[*].image`,`spec.initContainers[*].image`,`spec.activeDeadlineSeconds`,
`spec.tolerations` (only additions to existing tolerations),
`spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was a great reminder: &lt;strong&gt;a bare Pod's spec is mostly frozen once it's created.&lt;/strong&gt; Kubernetes only lets you patch a small allowlist of fields in-place — image, a couple of grace period settings, and tolerations. Environment variables are &lt;em&gt;not&lt;/em&gt; on that list.&lt;/p&gt;
&lt;p&gt;Two ways around this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option 1 — Delete and recreate:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl delete pod myapp-pod
kubectl apply -f pod.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Option 2 — Force replace in one shot:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl replace --force -f pod.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I went with &lt;code&gt;replace --force&lt;/code&gt;, and it worked perfectly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;❯ kubectl replace --force -f pod.yaml
pod &quot;myapp-pod&quot; deleted from default namespace
pod/myapp-pod replaced
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verified inside the container:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;❯ kubectl exec -it myapp-pod -- sh
/ # echo $FIRSTNAME
adeoye
/ # echo $LASTNAME
malumi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; &lt;strong&gt;Side note:&lt;/strong&gt; this is actually one of the reasons Deployments exist and are preferred over bare Pods in real-world use. A Deployment lets you update the pod template (image, env vars, etc.) and &lt;code&gt;kubectl apply&lt;/code&gt; will handle the rolling replacement of pods for you — no manual delete/recreate dance required.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;secrets-same-idea-but-for-sensitive-data&quot;&gt;Secrets: same idea, but for sensitive data&lt;/h3&gt;
&lt;p&gt;Secrets work almost identically to ConfigMaps, except they're meant for sensitive values like passwords, tokens, or usernames you don't want sitting in plain text in your manifests.&lt;/p&gt;
&lt;p&gt;I followed the official Kubernetes docs on &lt;a rel=&quot;nofollow&quot; href=&quot;https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#define-container-environment-variables-using-secret-data&quot;&gt;defining container environment variables using Secret data&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;creating-a-secret&quot;&gt;Creating a Secret&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create secret generic backend-user --from-literal=backend-username='adeoye-admin'
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;using-the-sample-pod-from-the-docs&quot;&gt;Using the sample pod from the docs&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kubectl create -f https://k8s.io/examples/pods/inject/pod-single-secret-env-variable.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This pod injects the secret as an environment variable called &lt;code&gt;SECRET_USERNAME&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;one-more-small-hiccup&quot;&gt;One more small hiccup&lt;/h4&gt;
&lt;p&gt;Right after creating the pod, I tried to exec into it immediately:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;❯ kubectl exec -i -t env-single-secret -- /bin/sh -c 'echo $SECRET_USERNAME'
error: Internal error occurred: unable to upgrade connection: container not found (&quot;envars-test-container&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Checking &lt;code&gt;kubectl get po&lt;/code&gt; showed the pod was still &lt;code&gt;ContainerCreating&lt;/code&gt;. Classic case of being too impatient — I just needed to wait a few seconds for the container to actually spin up. Once it hit &lt;code&gt;Running&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;❯ kubectl exec -i -t env-single-secret -- /bin/sh -c 'echo $SECRET_USERNAME'
adeoye-admin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there it is — the secret successfully injected as an env var.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;key-takeaways&quot;&gt;Key Takeaways&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ConfigMaps&lt;/strong&gt; decouple non-sensitive configuration from your pod manifests, and can be reused across multiple pods.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secrets&lt;/strong&gt; work the same way but are the right home for sensitive values.&lt;/li&gt;
&lt;li&gt;Both can be injected into a pod's containers via &lt;code&gt;env.valueFrom.configMapKeyRef&lt;/code&gt; or &lt;code&gt;secretKeyRef&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Watch your shell syntax — a stray space after a line-continuation &lt;code&gt;\&lt;/code&gt; will silently mangle your command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pods are mostly immutable&lt;/strong&gt; once created. Only image, tolerations, and a couple of grace-period fields can be patched live. Everything else means delete + recreate, or &lt;code&gt;kubectl replace --force&lt;/code&gt;. This is a big part of why Deployments exist.&lt;/li&gt;
&lt;li&gt;Give newly created pods a moment to leave &lt;code&gt;ContainerCreating&lt;/code&gt; before you &lt;code&gt;exec&lt;/code&gt; into them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's Day 19 done — small errors, but each one taught me something I'll remember longer than if it had just worked on the first try.&lt;/p&gt;
&lt;hr&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21757/kubernetes-configmaps-and-secrets</guid>
<pubDate>Thu, 02 Jul 2026 11:22:25 +0000</pubDate>
</item>
</channel>
</rss>