The outage that teaches you deployment
A service passes every test locally. It fails in staging because the API calls localhost:5432 for Postgres — but Postgres is in another container, reachable only as db:5432.
This is not a Docker problem. It is a boundary problem: your code assumed an environment it does not own.
Engineers who have shipped on AWS Lambda already avoid a class of these mistakes. They never SSH into a function to hot-fix. They inject config at deploy time. They treat each invocation as disposable. Containers reward the same discipline with different vocabulary.
This article maps what transfers, what breaks, and what I require before any Python backend goes to production in a container.
What serverless already taught you
Immutable deployments
Lambda versions are replaced, not patched. Container images work the same way: build a new image, roll out, roll back by tag. If your incident runbook includes "edit files inside the running box," you have a design problem.
Configuration at runtime
Secrets belong in Secrets Manager or injected env vars — not in source control, not in the image layer cache. Docker does not change the rule; it changes where you mount the values.
Single responsibility per unit
One Lambda, one job. One container, one main process. Compose and Kubernetes add orchestration; they do not remove the rule.
Cold start awareness
Slim packages on Lambda map to slim base images (python:3.12-slim, multi-stage builds). Startup time affects autoscaling and health-check windows the same way cold starts affect user-facing latency.
If you understand why a Lambda deployment package should stay small, you understand why a 2 GB container image is a liability.
Where the mental model breaks
1. Network identity
Inside Compose or Kubernetes, localhost is the container itself. Services discover each other by DNS name (api, db, redis). This is the most common first-production failure I see in teams moving from bare metal or single-host deploys.
2. Port publishing
EXPOSE in a Dockerfile documents intent. It does not bind a host port. You still need explicit port mapping or an ingress controller. Confusing the two produces "the container is healthy but nothing reaches it from outside."
3. Image vs. container vs. process
The image is immutable. The container is a running instance. You can scale ten replicas from one image. Debugging "which instance handled this request?" requires logs with instance identity — hostname, pod name, task id.
4. Health checks are part of the contract
A process that listens but cannot serve traffic should fail the health check. Load balancers and orchestrators depend on this. HEALTHCHECK in Docker and /health endpoints in your app are not optional polish.
A production-shaped Dockerfile (Python / FastAPI)
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
RUN useradd --create-home appuser
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app ./app
USER appuser
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
Non-root user, slim base, explicit health check, no secrets in layers. This is the minimum bar I review for in PRs.
Serverless vs. containers — a decision lens
| Constraint | Lean serverless | Lean containers |
|---|---|---|
| Traffic shape | Spiky, unpredictable | Steady or long-running workers |
| Unit of work | Short, event-driven | Persistent connections, WebSockets, background workers |
| Ops surface | Minimize | Team can own runtime and patching |
| Dependency weight | Small handler bundles | Custom system libs, ML models, legacy binaries |
Most mature platforms use both. The engineer who can reason about trade-offs — not just "we use Kubernetes" — is the one I want reviewing architecture.
What I look for in a backend engineer's deploy story
Can they explain why the last outage happened at the infrastructure boundary, not in a line of Python? Can they roll back without data loss? Do they know where config lives and who can read it?
Containers are not a separate career. They are the next layer of the same responsibility: ship code that survives real environments.
Further reading
Muhammad Umair Virk is a Backend Engineer based in the UAE — Python, AWS, microservices, and payment systems. Open to backend and platform roles.
Top comments (0)