An image should contain application code and runtime dependencies, not the message for one environment, an API token, or the data created by users. Baking those values into an image requires a rebuild for a configuration change and can leak a credential through image history. Writing task data only to a container filesystem loses it when Kubernetes replaces the Pod.
This chapter gives each concern its own Kubernetes resource: a ConfigMap for non-sensitive settings, a Secret template for credentials, and a PersistentVolumeClaim (PVC) for task data. By the end, you will know what each resource stores, what it does not secure, and how Chapter 8 mounts or injects it into the Task API.
Code for this chapter. The focused manifests and README are in _resource/kubernetes-basics/07-configmaps-secrets-and-storage.
Put Plain Configuration in a ConfigMap
The Task API reads APP_MESSAGE and PORT from its environment. Neither is a credential, so a
ConfigMap is appropriate:
apiVersion: v1
kind: ConfigMap
metadata:
name: task-api-config
namespace: tasks
data:
APP_MESSAGE: Tasks are ready from Kubernetes.
PORT: "3000"
data values are strings. The quotes around 3000 make that fact clear; environment variables
are strings even when the application later parses a number. Apply and inspect the ConfigMap:
kubectl apply -f configmap.yaml
kubectl get configmap task-api-config -n tasks -o yaml
ConfigMaps are not encrypted secret stores. Anyone with permission to read this ConfigMap can read its values. A ConfigMap consumed as an environment variable does not update an already running process when it changes. A Deployment rollout creates Pods with the new environment. Mounted ConfigMap files can update eventually, but the application must reload them.
Treat a Secret as Sensitive Input
The Task API can require API_TOKEN for POST /tasks. The resource folder contains
secret.template.yaml, not a usable secret:
apiVersion: v1
kind: Secret
metadata:
name: task-api-secret
namespace: tasks
type: Opaque
stringData:
API_TOKEN: CHANGE_ME
stringData lets a human provide plain text; the API server converts it to the base64-encoded
data field when it stores the Secret. Base64 is encoding, not encryption. Access control, API
server encryption at rest when configured, audit logging, and an external secret manager are
separate controls.
Do not apply the template with a real token committed to Git. For a local experiment, create the Secret from an environment variable instead:
kubectl create secret generic task-api-secret \
--namespace tasks \
--from-literal=API_TOKEN="$TASK_API_TOKEN" \
--dry-run=client -o yaml | kubectl apply -f -
Set TASK_API_TOKEN in the current shell from a secret manager or interactive prompt. The
command sends generated YAML directly to the API and does not create a file. In production, use
an external-secrets controller, encrypted GitOps secret system, or CI secret store according to
the organization’s policy.
Request Durable Data With a PVC
The API saves tasks under /var/lib/task-api/tasks.json. A PVC requests storage that survives
replacement Pods:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-api-data
namespace: tasks
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
The claim asks for one gibibyte with ReadWriteOnce access. That mode generally means the volume
can be mounted read-write by one node at a time; it does not mean one Pod in every storage
implementation. A StorageClass chooses how Kubernetes provisions a backing PersistentVolume.
Kind commonly has local storage suitable for experiments, but deleting the Kind cluster is not a
backup strategy. The claim does not name a StorageClass, so Kubernetes uses the cluster’s default
class when one exists.
kubectl apply -f persistent-volume-claim.yaml
kubectl get pvc task-api-data -n tasks
kubectl get storageclass
The PVC should become Bound. If it remains Pending, inspect kubectl describe pvc
task-api-data -n tasks. A cluster without a default StorageClass cannot dynamically satisfy a
claim until you specify an available class or an administrator supplies a matching volume.
Mounting Changes the Deployment Boundary
Chapter 8 mounts the claim at /var/lib/task-api. The mount makes data available, but it does
not make the application safe for every replica pattern. This API uses a JSON file without
concurrent-write coordination. One replica is appropriate for the tutorial. Two replicas with
independent disks split task state, while two writers sharing storage can corrupt it.
For a production API, use a database designed for concurrent access and operate it with backup, availability, and migration plans. A PVC provides durable block or filesystem storage, not an application data model.
Summary
- ConfigMaps hold non-sensitive configuration and need a rollout when environment values change.
- Secrets are access-controlled objects, but base64 encoding alone does not protect credentials.
- Keep only a placeholder Secret template in source; create real values from a trusted source.
- A PVC requests durable storage, while a StorageClass determines how backing storage is supplied.
- Persistent storage does not make a file-based application safe for concurrent replicas.
The final chapter combines these resources with the Task API image, health probes, a Service, and Kind-specific private registry access.