Container Spec
Summary
- The container spec is the block under
spec.containers[]that tells the kubelet exactly how to run one container: which image, what to execute, its environment, ports, resources, and security posture. - Insight: Most production incidents that trace back to a manifest are container-spec problems: a mutable tag, a missing
command, an over-broadsecurityContext, or absent resources. - Key Concepts:
image,command/args,env/envFrom,ports,resources,securityContext,volumeMounts. - When to Use: every workload. This block appears in Pods, Deployments, StatefulSets, DaemonSets, and Jobs.
- Limitations: the spec configures the container but does not validate app behavior. A valid spec can still ship a broken image.
Recipe
Pin the image by digest, set an explicit command, inject config through env, declare ports and resources, and lock down securityContext.
containers:
- name: api
image: registry.example.com/api@sha256:2c1f... # digest, not a mutable tag
command: ["/app/server"]
args: ["--port=8080"]
ports:
- name: http
containerPort: 8080
env:
- name: LOG_LEVEL
value: "info"
resources:
requests: { cpu: "100m", memory: "128Mi" }
limits: { memory: "256Mi" }
securityContext:
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]Working Example
A complete, restricted-compliant Deployment showing a realistic container spec with config drawn from a ConfigMap and Secret.
apiVersion: apps/v1
kind: Deployment
metadata:
name: checkout
spec:
replicas: 3
selector:
matchLabels: { app: checkout }
template:
metadata:
labels: { app: checkout }
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: checkout
image: registry.example.com/checkout@sha256:9ab3...
command: ["/app/checkout"]
ports:
- name: http
containerPort: 8080
envFrom:
- configMapRef:
name: checkout-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: checkout-db
key: password
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
resources:
requests: { cpu: "150m", memory: "192Mi" }
limits: { memory: "384Mi" }
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}Deep Dive
image and pull policy
The image field takes a reference like repo:tag or repo@sha256:....
Prefer digests for immutability, or at minimum a specific version tag. Avoid latest, which is a mutable pointer.
imagePullPolicy defaults to IfNotPresent for tagged images and Always for the latest tag. Digest-pinned images are cached safely.
command and args
command overrides the image's ENTRYPOINT; args overrides its CMD.
If you omit both, the image's own defaults run. Set command explicitly when you want the manifest to be self-documenting or to change behavior without rebuilding.
There is no shell by default. command: ["/bin/sh", "-c", "..."] is required if you need shell features like variable expansion or pipes.
env and envFrom
env sets variables one at a time, either with a literal value or a valueFrom reference.
valueFrom can pull from a configMapKeyRef, secretKeyRef, or fieldRef (the downward API, for things like status.podIP or metadata.namespace).
envFrom imports every key from a ConfigMap or Secret as variables. It is convenient but can hide surprises, so name your ConfigMaps clearly.
ports
ports is informational plus a naming aid. Naming a port (name: http) lets Services and probes reference it by name.
Declaring a containerPort does not restrict which ports the process can actually bind; it documents intent and enables named targeting.
resources and securityContext
resources.requests drive scheduling; resources.limits cap runtime usage. See the requests and limits page for QoS implications.
securityContext applies at the Pod and container level. Container-level settings win for that container.
For the restricted Pod Security Standard, set runAsNonRoot: true, allowPrivilegeEscalation: false, seccompProfile.type: RuntimeDefault, and drop all capabilities.
Gotchas
Mutable tags break reproducibility. image: app:latest can resolve to different bytes over time. Pin a digest so a rollback restarts the exact same image.
readOnlyRootFilesystem: true breaks apps that write to disk. Mount an emptyDir at the paths they need (like /tmp) instead of loosening the setting.
runAsNonRoot: true fails if the image has no non-root user. Build the image with a USER directive or set runAsUser to a valid UID.
envFrom name collisions are silent. If a ConfigMap and Secret define the same key, the later source wins and you get no warning.
Forgetting command after switching base images. A distroless rebuild may drop the shell your command assumed. Test the entrypoint after base changes.
Alternatives
ConfigMap/Secret volume mounts vs env vars. Mount config as files when values are large, updated at runtime, or sensitive. Env vars are simplest for small, static settings.
Kustomize or Helm for spec reuse. Rather than copy the same securityContext into every manifest, template it with Helm values or a Kustomize patch.
Pod-level vs container-level securityContext. Set shared defaults at the Pod level and override per container only where needed, to reduce duplication.
FAQs
Do I have to set command? No. If omitted, the image's ENTRYPOINT/CMD run. Set it when you want explicitness or custom behavior.
How do I inject a secret without hardcoding it? Use env.valueFrom.secretKeyRef or mount the Secret as a volume. Never put secrets in value literals.
Why name my ports? Named ports let Services and probes target http instead of a hardcoded number, so you can change the number in one place.
Should every container be non-root? Yes for the restricted standard. Build images with a dedicated non-root UID and set runAsNonRoot: true.
What is the downward API? A fieldRef/resourceFieldRef that exposes Pod metadata (name, namespace, IP, limits) to the container as env vars or files.
Can I override just args, not command? Yes. Set args alone to keep the image ENTRYPOINT and change only its arguments.
Related
- What a Pod Represents
- Pods Basics
- Liveness, Readiness & Startup Probes
- Requests & Limits
- Pods Best Practices
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).