Module 2.7: ConfigMaps & Secrets
Complexity: [MEDIUM] | Time to Complete: 55 minutes | CKA Weight: Part of 15%
Prerequisites
Section titled “Prerequisites”Before starting this module, ensure you have:
- Completed Module 2.1: Pods Deep-Dive (Pod spec structure)
- Completed Module 2.2: Deployments (Updating configurations)
- A running Kubernetes cluster (kind or minikube)
- Basic understanding of environment variables
What You’ll Be Able to Do
Section titled “What You’ll Be Able to Do”After this module, you will be able to:
- Create ConfigMaps and Secrets from files, literals, and directories
- Mount configuration as environment variables and volume mounts and explain when to use each
- Implement immutable ConfigMaps/Secrets and explain when immutability matters
- Troubleshoot configuration issues (wrong mount path, missing key, base64 encoding errors)
Why This Module Matters
Section titled “Why This Module Matters”Every real application needs configuration. Database connection strings, feature flags, API keys, certificates—these can’t be hardcoded. Kubernetes provides two primitives for injecting configuration into Pods: ConfigMaps for non-sensitive data and Secrets for sensitive data.
On the CKA exam, you’ll need to:
- Create ConfigMaps and Secrets from files, literals, and manifests
- Inject them as environment variables or mounted files
- Update configurations without rebuilding containers
- Understand the security implications of Secrets
Getting this wrong in production means leaked credentials or broken applications. Getting it right means secure, flexible deployments.
Did You Know?
Section titled “Did You Know?”-
Secrets aren’t encrypted by default—they’re only base64 encoded. Anyone with API access can decode them. Encryption at rest requires explicit configuration.
-
ConfigMap updates propagate automatically when mounted as volumes, but NOT when used as environment variables. Environment variables require Pod restart.
-
The 1MB limit on ConfigMaps and Secrets exists because they’re stored in etcd. Larger configurations need different solutions (external config stores, init containers downloading configs).
-
Projected volumes allow you to mount multiple ConfigMaps, Secrets, and Downward API information into a single directory, which is extremely useful when an application expects all its configuration files in one place.
The Real-World Analogy
Section titled “The Real-World Analogy”Think of ConfigMaps and Secrets like hotel room configuration:
-
ConfigMaps are like the room service menu, Wi-Fi instructions, and TV channel guide. Everyone can see them, and they change the guest experience without renovating the room.
-
Secrets are like the safe code and door lock combination. They need to stay private, and sharing them with unauthorized people causes serious problems.
Both are separate from the room itself (your container image)—you don’t rebuild the room to change the menu or safe code.
Understanding ConfigMaps
Section titled “Understanding ConfigMaps”What ConfigMaps Store
Section titled “What ConfigMaps Store”ConfigMaps hold key-value pairs of non-sensitive configuration data:
apiVersion: v1kind: ConfigMapmetadata: name: app-config namespace: defaultdata: # Simple key-value pairs LOG_LEVEL: "debug" MAX_CONNECTIONS: "100" FEATURE_FLAGS: "new-ui,beta-api"
# Entire configuration files config.json: | { "database": { "host": "db.example.com", "port": 5432 }, "cache": { "enabled": true, "ttl": 300 } }
nginx.conf: | server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; } }Key concepts:
- data: String key-value pairs (most common)
- binaryData: Base64-encoded binary content
- immutable: If set to
true, prevents modifications (performance optimization)
Creating ConfigMaps
Section titled “Creating ConfigMaps”Method 1: From literal values (exam favorite)
# Single valuek create configmap app-config --from-literal=LOG_LEVEL=debug
# Multiple valuesk create configmap app-config \ --from-literal=LOG_LEVEL=debug \ --from-literal=MAX_CONNECTIONS=100 \ --from-literal=CACHE_ENABLED=trueMethod 2: From a file
# Create a config filecat > config.properties <<EOFdatabase.host=db.example.comdatabase.port=5432cache.enabled=trueEOF
# Create ConfigMap from filek create configmap app-config --from-file=config.properties
# The key becomes the filename, value is file contents# Result: data: { "config.properties": "database.host=db.example.com\n..." }Method 3: From a file with custom key
# Specify the key namek create configmap app-config --from-file=app.conf=config.properties# Result: data: { "app.conf": "..." }Method 4: From a directory
# All files in directory become keysk create configmap app-config --from-file=./config-dir/Method 5: From env file
cat > config.env <<EOFLOG_LEVEL=debugMAX_CONNECTIONS=100EOF
k create configmap app-config --from-env-file=config.env# Each line becomes a separate key-value pair (not one key with file contents)Using ConfigMaps in Pods
Section titled “Using ConfigMaps in Pods”Option 1: As environment variables (specific keys)
apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: nginx env: - name: LOG_LEVEL # Name in container valueFrom: configMapKeyRef: name: app-config # ConfigMap name key: LOG_LEVEL # Key in ConfigMap - name: DB_HOST valueFrom: configMapKeyRef: name: app-config key: database.host optional: true # Don't fail if key missingOption 2: All keys as environment variables
apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: nginx envFrom: - configMapRef: name: app-config prefix: APP_ # Optional: prefix all varsAll ConfigMap keys become environment variables. With prefix, LOG_LEVEL becomes APP_LOG_LEVEL.
Option 3: As a mounted volume (entire ConfigMap)
apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: nginx volumeMounts: - name: config-volume mountPath: /etc/config # Directory containing all files volumes: - name: config-volume configMap: name: app-config # Each key becomes a file in /etc/config/Option 4: Mount specific keys as files
apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: nginx volumeMounts: - name: config-volume mountPath: /etc/nginx/nginx.conf subPath: nginx.conf # Mount single file, not directory volumes: - name: config-volume configMap: name: app-config items: - key: nginx.conf # Key from ConfigMap path: nginx.conf # Filename in volumePause and predict: You update a ConfigMap that is injected into a pod two ways: one key is used as an environment variable, and another key is mounted as a volume. After updating the ConfigMap, which value changes automatically in the pod and which one stays stale? What about if the volume uses
subPath?
ConfigMap Update Behavior
Section titled “ConfigMap Update Behavior”| Injection Method | Auto-Updates? | Notes |
|---|---|---|
| Environment variable | No | Requires Pod restart |
| Volume mount | Yes | ~1 minute delay (kubelet sync) |
| subPath mount | No | Requires Pod restart |
Understanding Secrets
Section titled “Understanding Secrets”Secret Types
Section titled “Secret Types”Kubernetes supports several Secret types:
| Type | Description | Auto-created? |
|---|---|---|
Opaque | Generic key-value pairs | No (default) |
kubernetes.io/tls | TLS certificate + key | No |
kubernetes.io/dockerconfigjson | Docker registry auth | No |
kubernetes.io/service-account-token | ServiceAccount token | Yes |
kubernetes.io/basic-auth | Username + password | No |
kubernetes.io/ssh-auth | SSH private key | No |
Pause and predict: You write a Secret YAML with
data: {password: MyPassword123}and apply it. When your app reads the password, it gets garbled text. What went wrong, and what field should you use instead ofdatato avoid this issue?
Creating Secrets
Section titled “Creating Secrets”Method 1: Generic secret from literals
# Values are automatically base64 encodedk create secret generic db-creds \ --from-literal=username=admin \ --from-literal=password='S3cur3P@ssw0rd!'Method 2: From files
# Create credential filesecho -n 'admin' > username.txtecho -n 'S3cur3P@ssw0rd!' > password.txt
k create secret generic db-creds \ --from-file=username=username.txt \ --from-file=password=password.txt
# Clean up filesrm username.txt password.txtMethod 3: TLS secret
# From existing cert and keyk create secret tls app-tls \ --cert=tls.crt \ --key=tls.keyMethod 4: Docker registry secret
k create secret docker-registry regcred \ --docker-server=registry.example.com \ --docker-username=user \ --docker-password=pass \ --docker-email=user@example.comMethod 5: From YAML (manual base64)
apiVersion: v1kind: Secretmetadata: name: db-credstype: Opaquedata: # Values must be base64 encoded username: YWRtaW4= # echo -n 'admin' | base64 password: UzNjdXIzUEBzc3cwcmQh # echo -n 'S3cur3P@ssw0rd!' | base64Or use stringData for plain text (Kubernetes encodes it):
apiVersion: v1kind: Secretmetadata: name: db-credstype: OpaquestringData: username: admin # Plain text - Kubernetes encodes password: S3cur3P@ssw0rd!Using Secrets in Pods
Section titled “Using Secrets in Pods”Option 1: As environment variables
apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: myapp env: - name: DB_USERNAME valueFrom: secretKeyRef: name: db-creds key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-creds key: passwordOption 2: All keys as environment variables
apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: myapp envFrom: - secretRef: name: db-creds prefix: DB_Option 3: As mounted files
apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: myapp volumeMounts: - name: secret-volume mountPath: /etc/secrets readOnly: true # Best practice for secrets volumes: - name: secret-volume secret: secretName: db-creds defaultMode: 0400 # Restrict permissionsOption 4: Mount TLS certificate
apiVersion: v1kind: Podmetadata: name: appspec: containers: - name: app image: nginx volumeMounts: - name: tls-certs mountPath: /etc/nginx/ssl readOnly: true volumes: - name: tls-certs secret: secretName: app-tls items: - key: tls.crt path: server.crt - key: tls.key path: server.key mode: 0400 # Restrictive for private keyDecoding Secrets
Section titled “Decoding Secrets”# View encoded valuesk get secret db-creds -o yaml
# Decode a specific keyk get secret db-creds -o jsonpath='{.data.password}' | base64 -d
# Decode all keysk get secret db-creds -o go-template='{{range $k,$v := .data}}{{$k}}: {{$v | base64decode}}{{"\n"}}{{end}}'Security Considerations
Section titled “Security Considerations”Secrets Are Not Truly Secret (by default)
Section titled “Secrets Are Not Truly Secret (by default)”Base64 is encoding, not encryption:
# Anyone can decodeecho 'UzNjdXIzUEBzc3cwcmQh' | base64 -d# Output: S3cur3P@ssw0rd!Security measures:
- RBAC: Limit who can read Secrets
- Encryption at rest: Enable etcd encryption
- Audit logging: Track Secret access
- External secret stores: HashiCorp Vault, AWS Secrets Manager
Stop and think: A security auditor tells you that storing database passwords as environment variables is risky. They recommend volume mounts instead. What specific attack vector do environment variables create that mounted files avoid?
Environment Variables vs Volume Mounts
Section titled “Environment Variables vs Volume Mounts”| Aspect | Env Vars | Volume Mounts |
|---|---|---|
| Visibility | kubectl exec -- env shows them | Must cat files |
| Process inheritance | Child processes inherit | Must explicitly read |
| Logging risk | Often logged accidentally | Less likely to log |
| Updates | Requires restart | Auto-updates (~1min) |
Best practice: Use volume mounts for sensitive secrets to reduce accidental exposure.
Secret Immutability
Section titled “Secret Immutability”For production, consider immutable Secrets:
apiVersion: v1kind: Secretmetadata: name: db-creds-v1type: Opaqueimmutable: true # Cannot be modifieddata: password: UzNjdXIzUEBzc3cwcmQhBenefits:
- Prevents accidental changes
- Performance: kubelet doesn’t need to watch for updates
- Version control: Use naming (v1, v2) for rotation
Common Mistakes
Section titled “Common Mistakes”| Mistake | Problem | Solution |
|---|---|---|
| Forgetting base64 in YAML | Invalid Secret data | Use stringData for plain text |
Not using -n with echo | Newline in encoded value | echo -n 'value' |
| Expecting env var updates | App uses stale config | Restart Pod or use volume mount |
| Hardcoding secrets in image | Security risk, inflexible | Always use Secrets |
| Committing Secrets to git | Credentials exposed | Use .gitignore, external stores |
| Overly permissive RBAC | Anyone can read Secrets | Limit with Role/RoleBinding |
| Not setting volume readOnly | Container could modify | Always readOnly: true |
| Ignoring subPath limitation | Config doesn’t update | Use full volume mount when possible |
Hands-On Exercise
Section titled “Hands-On Exercise”Scenario: Configure a Web Application
Section titled “Scenario: Configure a Web Application”You need to deploy a web application with:
- Configuration file (ConfigMap)
- Database credentials (Secret)
- Feature flags (ConfigMap as env vars)
Task 1: Create Configuration
Section titled “Task 1: Create Configuration”# Create namespacek create ns config-demo
# Create ConfigMap with app configurationk create configmap app-config -n config-demo \ --from-literal=LOG_LEVEL=info \ --from-literal=CACHE_TTL=300 \ --from-literal=FEATURE_NEW_UI=true
# Create nginx configuration filecat > /tmp/nginx.conf <<EOFserver { listen 80; location / { root /usr/share/nginx/html; index index.html; } location /health { return 200 'OK'; add_header Content-Type text/plain; }}EOF
k create configmap nginx-config -n config-demo \ --from-file=nginx.conf=/tmp/nginx.confTask 2: Create Secrets
Section titled “Task 2: Create Secrets”# Database credentialsk create secret generic db-creds -n config-demo \ --from-literal=DB_USER=appuser \ --from-literal=DB_PASS='Pr0dP@ssw0rd!'
# Verifyk get secret db-creds -n config-demo -o yamlTask 3: Deploy Application
Section titled “Task 3: Deploy Application”cat <<EOF | k apply -f -apiVersion: v1kind: Podmetadata: name: webapp namespace: config-demospec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 # Environment variables from ConfigMap envFrom: - configMapRef: name: app-config prefix: APP_ # Environment variables from Secret env: - name: DATABASE_USER valueFrom: secretKeyRef: name: db-creds key: DB_USER - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: db-creds key: DB_PASS volumeMounts: # Mount nginx config - name: nginx-config mountPath: /etc/nginx/conf.d/default.conf subPath: nginx.conf # Mount secrets as files - name: db-creds mountPath: /etc/secrets readOnly: true volumes: - name: nginx-config configMap: name: nginx-config - name: db-creds secret: secretName: db-creds defaultMode: 0400EOFTask 4: Verify Configuration
Section titled “Task 4: Verify Configuration”# Check Pod is runningk get pod webapp -n config-demo
# Verify environment variablesk exec webapp -n config-demo -- env | grep -E "APP_|DATABASE"
# Verify mounted config filek exec webapp -n config-demo -- cat /etc/nginx/conf.d/default.conf
# Verify secret files exist (don't cat in production!)k exec webapp -n config-demo -- ls -la /etc/secrets/
# Test nginx health endpointk exec webapp -n config-demo -- curl -s localhost/healthTask 5: Update ConfigMap
Section titled “Task 5: Update ConfigMap”# Update a ConfigMap valuek edit configmap app-config -n config-demo# Change LOG_LEVEL from info to debug
# Check if env var updated (it won't - requires restart)k exec webapp -n config-demo -- env | grep LOG_LEVEL# Still shows: APP_LOG_LEVEL=info
# Restart pod to pick up changesk delete pod webapp -n config-demo# Re-create the pod (run the apply command again)Success Criteria
Section titled “Success Criteria”- Pod is running with all configurations injected
- Environment variables visible with correct prefix
- nginx.conf mounted at correct path
- Secret files have restrictive permissions (0400)
- Health endpoint returns OK
Cleanup
Section titled “Cleanup”k delete ns config-demorm /tmp/nginx.confQuestion 1
Section titled “Question 1”You have a config file app.properties with 20 key-value pairs. You need each pair as a separate environment variable in your pod. A teammate used --from-file=app.properties, but all 20 pairs ended up as a single key. What did they do wrong, and what’s the correct command?
Show Answer
They used --from-file, which stores the entire file as a single key (the filename becomes the key, the file contents become the value). For individual key-value pairs, they should use --from-env-file:
# Wrong: single key "app.properties" with all content as valuek create configmap test --from-file=app.properties# Result: data: { "app.properties": "key1=value1\nkey2=value2\n..." }
# Correct: each line becomes its own key-value pairk create configmap test --from-env-file=app.properties# Result: data: { "key1": "value1", "key2": "value2", ... }Use --from-file when you need to mount the entire file (e.g., nginx.conf, application.yaml). Use --from-env-file when you need individual properties as separate environment variables. This distinction is a common exam trap.
Question 2
Section titled “Question 2”You deploy an nginx pod with a ConfigMap-mounted nginx.conf using subPath. Later, you update the ConfigMap to add a new location /api block. Users report the change isn’t taking effect even after 10 minutes. What’s wrong, and what are your options?
Show Answer
When a ConfigMap is mounted using subPath, updates do NOT automatically propagate to the pod. This is because subPath mounts a specific file rather than a symlinked directory, bypassing the kubelet’s automatic update mechanism. You have three options: (1) Delete and recreate the pod to pick up the new ConfigMap (simplest for exam), (2) switch from subPath to a full volume mount at a directory path (enables auto-updates but may overwrite other files in the directory), or (3) use an immutable ConfigMap naming scheme (e.g., nginx-config-v2) and update the pod spec to reference the new ConfigMap. Option 2 is the best long-term solution if auto-updates are important, but be aware that a full volume mount replaces the entire directory contents.
Question 3
Section titled “Question 3”A junior developer wrote a Secret YAML with data: {password: MySecurePassword123} and applied it. Authentication to the database fails, but kubectl get secret db-creds -o yaml shows the password field has a value. They’re confused because the value “is right there.” What are two things wrong with this scenario, and how should the YAML be written?
Show Answer
Two issues: (1) The data field requires base64-encoded values, but MySecurePassword123 is plain text. Kubernetes will try to base64-decode this value when injecting it into a pod, producing garbled output. (2) The developer may also be confused because kubectl get secret -o yaml shows base64-encoded values, which look valid but are actually a double-encoding issue. The fix is to either base64-encode the value yourself (echo -n 'MySecurePassword123' | base64) in the data field, or use stringData instead, which accepts plain text and Kubernetes handles the encoding:
stringData: password: MySecurePassword123Always use echo -n (not echo) when encoding to avoid including a trailing newline, which is another common cause of authentication failures.
Question 4
Section titled “Question 4”A security audit found that your team’s database passwords are visible when running kubectl exec <pod> -- env on any pod that uses them. The auditor requires that secrets not be retrievable via process introspection. What injection method are you using now, what should you switch to, and what additional hardening step should you take?
Show Answer
You’re currently injecting secrets as environment variables (via envFrom or env.valueFrom.secretKeyRef), which makes them visible to kubectl exec -- env, child process inheritance, and crash dump logging. Switch to volume-mounted secrets, which are stored as files at a mount path (e.g., /etc/secrets/password). Applications must explicitly read the file to access the value. Additionally, set readOnly: true on the volume mount and use restrictive file permissions with defaultMode: 0400 on the volume definition. This ensures the files can only be read by the container’s process owner and cannot be modified. For deeper security, combine this with RBAC rules that limit which service accounts can access the Secret, and enable encryption at rest for etcd to protect the stored Secret data.
Question 5
Section titled “Question 5”You created a Secret with echo 'S3cur3P@ssw0rd!' | base64 and stored the result in your YAML. When the application tries to authenticate, it fails with “invalid credentials.” You’ve triple-checked the password is correct. What went wrong?
Show Answer
The echo command adds a trailing newline character by default. When you pipe to base64, the newline is encoded along with the password, so the decoded value becomes S3cur3P@ssw0rd!\n instead of S3cur3P@ssw0rd!. The database rejects the password because of the invisible extra character. The fix is to use echo -n (no newline):
# Wrong: includes newlineecho 'S3cur3P@ssw0rd!' | base64 # encodes "S3cur3P@ssw0rd!\n"
# Correct: no newlineecho -n 'S3cur3P@ssw0rd!' | base64 # encodes "S3cur3P@ssw0rd!"This is one of the most common Kubernetes Secret pitfalls. Alternatively, use stringData in your YAML to avoid base64 entirely, or use kubectl create secret generic --from-literal=password='S3cur3P@ssw0rd!' which handles encoding correctly.
Question 6
Section titled “Question 6”Your application reads its config from a file at /etc/config/app.yaml mounted from a ConfigMap. After a ConfigMap update, the application picks up the new config automatically within a minute. Your team wants the same auto-update behavior for a TLS certificate stored in a Secret and mounted at /etc/nginx/ssl/server.crt. But they’re using subPath for the certificate mount. Will the TLS certificate auto-update? What’s the best approach?
Show Answer
No, the TLS certificate will NOT auto-update because subPath mounts bypass the kubelet’s automatic update mechanism. The ConfigMap at /etc/config/app.yaml auto-updates because it uses a full volume mount (the kubelet creates symlinks that get updated). For the TLS certificate, remove the subPath and mount the entire secret volume to a directory (e.g., /etc/nginx/ssl/), then reference the files within that directory. The certificate will auto-update within approximately 60 seconds of a Secret change. However, note that nginx caches TLS certificates in memory, so you may also need a sidecar or process that watches for file changes and triggers a config reload (e.g., nginx -s reload).
Question 7
Section titled “Question 7”You have a ConfigMap mounted as a volume in your Pod. You set immutable: true on the ConfigMap, but later need to update a configuration value. What is the correct procedure to apply this change to your application?
Show Answer
Because the ConfigMap is marked as immutable, you cannot update it in place. The kubelet also stops watching immutable ConfigMaps for changes, which improves cluster performance. To apply a change, you must: (1) Create a new ConfigMap with a new name (e.g., app-config-v2) containing the updated values, and (2) Update the Pod template (usually via its Deployment) to reference the new ConfigMap name. This triggers a rolling update of the Pods, ensuring a safe and version-controlled configuration rollout.
Practice Drills
Section titled “Practice Drills”Practice these scenarios under exam time pressure.
Drill 1: Quick ConfigMap Creation
Section titled “Drill 1: Quick ConfigMap Creation”Target Time: 30 seconds
Create a ConfigMap named web-config with these values:
SERVER_PORT=8080DEBUG_MODE=false
Show Solution
k create configmap web-config \ --from-literal=SERVER_PORT=8080 \ --from-literal=DEBUG_MODE=falseDrill 2: ConfigMap from File
Section titled “Drill 2: ConfigMap from File”Target Time: 45 seconds
Create a file /tmp/app.properties with content:
db.host=localhostdb.port=5432Then create ConfigMap app-props from this file.
Show Solution
cat > /tmp/app.properties <<EOFdb.host=localhostdb.port=5432EOF
k create configmap app-props --from-file=/tmp/app.propertiesDrill 3: Secret from Literals
Section titled “Drill 3: Secret from Literals”Target Time: 30 seconds
Create a Secret named api-key with:
API_KEY=abc123secretAPI_SECRET=xyz789token
Show Solution
k create secret generic api-key \ --from-literal=API_KEY=abc123secret \ --from-literal=API_SECRET=xyz789tokenDrill 4: Pod with ConfigMap Env Vars
Section titled “Drill 4: Pod with ConfigMap Env Vars”Target Time: 2 minutes
Create a Pod envpod using image nginx that loads all keys from ConfigMap web-config as environment variables.
Show Solution
k run envpod --image=nginx --dry-run=client -o yaml > /tmp/pod.yamlEdit to add envFrom:
apiVersion: v1kind: Podmetadata: name: envpodspec: containers: - name: envpod image: nginx envFrom: - configMapRef: name: web-configk apply -f /tmp/pod.yamlDrill 5: Pod with Secret Volume
Section titled “Drill 5: Pod with Secret Volume”Target Time: 2 minutes
Create Pod secretpod using image nginx that mounts Secret api-key at /etc/api-secrets with read-only access.
Show Solution
apiVersion: v1kind: Podmetadata: name: secretpodspec: containers: - name: secretpod image: nginx volumeMounts: - name: secret-vol mountPath: /etc/api-secrets readOnly: true volumes: - name: secret-vol secret: secretName: api-keyk apply -f /tmp/secretpod.yamlDrill 6: Decode Secret Value
Section titled “Drill 6: Decode Secret Value”Target Time: 30 seconds
Extract and decode the API_KEY value from Secret api-key.
Show Solution
k get secret api-key -o jsonpath='{.data.API_KEY}' | base64 -dDrill 7: TLS Secret
Section titled “Drill 7: TLS Secret”Target Time: 1 minute
You have files server.crt and server.key. Create a TLS Secret named web-tls.
Show Solution
# If you need to create test files first:openssl req -x509 -nodes -days 1 -newkey rsa:2048 \ -keyout server.key -out server.crt \ -subj "/CN=test"
# Create the secretk create secret tls web-tls --cert=server.crt --key=server.keyDrill 8: Specific Key as File
Section titled “Drill 8: Specific Key as File”Target Time: 2 minutes
Create Pod configfile that mounts only the db.host key from ConfigMap app-props as /etc/dbhost file.
Show Solution
apiVersion: v1kind: Podmetadata: name: configfilespec: containers: - name: configfile image: nginx volumeMounts: - name: config-vol mountPath: /etc/dbhost subPath: db.host volumes: - name: config-vol configMap: name: app-props items: - key: db.host path: db.hostNote: This requires the ConfigMap to have a key named db.host. If your ConfigMap was created with --from-file, the key would be app.properties (the filename).
Drill 9: Troubleshooting Missing ConfigMap
Section titled “Drill 9: Troubleshooting Missing ConfigMap”Target Time: 2 minutes
A Pod named api-server is crashing with CreateContainerConfigError. Troubleshoot and find out why it won’t start. (Simulate this by creating a pod referencing a non-existent ConfigMap).
Show Solution
# Check the pod status and eventsk describe pod api-server
# Look at the Events section at the bottom. You will see an error like:# Warning Failed ... Error: configmap "missing-config" not found
# To fix it, either create the missing ConfigMap or update the Pod to reference the correct one.Drill 10: Troubleshooting Secret Base64 Error
Section titled “Drill 10: Troubleshooting Secret Base64 Error”Target Time: 2 minutes
You created a Secret using YAML, but the application is getting rejected due to invalid credentials. You suspect an encoding issue. How do you verify the exact decoded value Kubernetes is passing to the Pod?
Show Solution
# Get the base64 encoded value from the secretk get secret my-secret -o jsonpath='{.data.password}'
# Decode it and pipe through xxd or cat -e to reveal hidden characters (like trailing newlines)k get secret my-secret -o jsonpath='{.data.password}' | base64 -d | cat -e
# If you see "mypassword%$" (where $ is a newline) instead of just "mypassword%",# it means it was encoded with a newline. Fix it by recreating the secret with echo -n.Key Takeaways
Section titled “Key Takeaways”-
ConfigMaps store non-sensitive configuration; Secrets store sensitive data (but aren’t encrypted by default)
-
Creation methods:
--from-literal,--from-file,--from-env-file, YAML manifest -
Injection methods: Environment variables (single or all), volume mounts (full or specific keys)
-
Updates: Volume mounts auto-update (~1min), environment variables require Pod restart, subPath mounts don’t update
-
Secrets: Use
stringDatafor plain text in YAML, always useecho -nto avoid newline issues -
Security: Limit RBAC access, prefer volume mounts over env vars, consider external secret stores for production
What’s Next?
Section titled “What’s Next?”Congratulations! You’ve completed all modules in Part 2: Workloads & Scheduling.
Next step: Part 2 Cumulative Quiz - Test your knowledge across all Part 2 topics before moving on.
Coming up in Part 3: Services & Networking - How Pods communicate with each other and the outside world.
Part 2 Module Index
Section titled “Part 2 Module Index”Quick links for review:
| Module | Topic | Key Skills |
|---|---|---|
| 2.1 | Pods Deep-Dive | Multi-container patterns, lifecycle, probes |
| 2.2 | Deployments & ReplicaSets | Rolling updates, rollbacks, scaling |
| 2.3 | DaemonSets & StatefulSets | Node-level workloads, stateful apps |
| 2.4 | Jobs & CronJobs | Batch processing, scheduled tasks |
| 2.5 | Resource Management | Requests, limits, QoS, quotas |
| 2.6 | Scheduling | Affinity, taints, topology |
| 2.7 | ConfigMaps & Secrets | Configuration injection |
Exam Tip: Part 2 (Workloads & Scheduling) is 15% of the CKA exam. Master kubectl run, kubectl create deployment, and kubectl create configmap/secret for quick task completion.