Stage 4 · Provision
Production Containers
Kubernetes-Ready Images
Optimize images for Kubernetes with signals, graceful shutdown, probes, non-root users, and minimal layers.
Kubernetes Expectations
Kubernetes makes specific assumptions about container behavior. It sends SIGTERM to stop containers, expects health check endpoints, requires non-root users for security policies, and expects images to start quickly. Containers that do not follow these conventions experience ungraceful shutdowns and failed deployments.
Signal Handling
Kubernetes sends SIGTERM to the main process when stopping a pod. If the process does not exit within the termination grace period (default 30 seconds), Kubernetes sends SIGKILL. Your application must handle SIGTERM for graceful shutdown.
FROM node:20-alpine
# Use tini as PID 1 to handle signal forwarding
RUN apk add --no-cache tini
WORKDIR /app
COPY . .
USER node
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]tini is a minimal init process that handles PID 1 responsibilities: reaping zombie processes and forwarding signals. Without tini, Node.js does not receive SIGTERM properly.
const server = app.listen(3000);
// Handle SIGTERM for graceful shutdown
process.on('SIGTERM', async () => {
console.log('SIGTERM received, shutting down gracefully');
// Stop accepting new connections
server.close(async () => {
// Close database connections
await db.end();
await redis.quit();
// Close message queue connections
await mq.close();
console.log('All connections closed');
process.exit(0);
});
// Force exit after grace period
setTimeout(() => {
console.error('Forced shutdown after timeout');
process.exit(1);
}, 25000);
});The SIGTERM handler stops accepting new requests, waits for in-flight requests to complete, closes database and cache connections, and exits cleanly. The 25-second timeout ensures exit before Kubernetes's 30-second grace period.
Graceful Shutdown
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
terminationGracePeriodSeconds: 45
containers:
- name: myapp
image: myregistry.com/myapp:1.0
ports:
- containerPort: 3000
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10preStop hook gives the pod time to deregister from service meshes and load balancers before SIGTERM. The probes check health at the Kubernetes level. terminationGracePeriodSeconds gives your app time to shut down.
Probes
| Probe | Purpose | Failure Action |
|---|---|---|
| livenessProbe | Is the container alive? | Restart container |
| readinessProbe | Can it accept traffic? | Remove from Service endpoints |
| startupProbe | Has it finished starting? | Disable other probes until pass |
Security Context
apiVersion: v1
kind: Pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: myapp
image: myregistry.com/myapp:1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}runAsNonRoot prevents containers from running as root. readOnlyRootFilesystem prevents writes to image layers. drop ALL capabilities removes all Linux privileges. emptyDir provides a writable /tmp directory.
Image Optimization
- Use minimal base images (Alpine, distroless, scratch)
- Use multi-stage builds to exclude build tools
- Set HEALTHCHECK for Kubernetes probes
- Run as non-root with USER instruction
- Handle SIGTERM for graceful shutdown
- Start quickly — use startup probes for slow starters
- Set resource requests and limits in pod spec
- Include tini or dumb-init for proper PID 1 handling
Test Kubernetes behavior locally with kind (Kubernetes in Docker) or minikube. Deploy your image and verify signal handling, probe responses, and graceful shutdown before pushing to production.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.