Docker: Stop Saying 'It Works on My Machine'
If you’re still manually installing dependencies on your server, you’re doing it wrong. Docker ensures your environment is consistent from dev to prod.
The Problem#
- Dev: Python 3.12, Postgres 16
- Prod: Python 3.8, Postgres 12 (System Default)
- Result: Crash.
1. The Dockerfile: From Basic to Production-Ready#
A Dockerfile is a recipe for your environment.
Level 1: The Basic Dockerfile (Don’t deploy this)#
FROM python:3.11
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]Why this is bad: It includes the full OS, compiler tools, and is huge >1GB.
Level 2: Multi-Stage Build (The Professional Way)#
We use a “Builder” stage to compile dependencies, and a “Runner” stage to run the app.
# Stage 1: Builder
FROM python:3.11-slim as builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
# Stage 2: Runner
FROM python:3.11-distroless
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]Result: A 60MB image that is secure and fast.
2. Docker Compose: Orchestrating the Stack#
OrchestrationManage multi-container apps (App + DB + Redis) with docker-compose.yml.
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
depends_on:
- db
- redis
environment:
- DATABASE_URL=postgres://user:pass@db:5432/myapp
db:
image: postgres:15-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: secretpassword
redis:
image: redis:alpine
volumes:
postgres_data:
With this file,
docker-compose up is the only command a new developer needs to run to start the entire project.3. Security Best Practices#
Don’t run as Root: By default, Docker containers run as root. This is a security risk.
RUN adduser -D myuser USER myuserScan your Images: Use
docker scan(powered by Snyk) to find vulnerabilities.docker scan my-image:latestUse
.dockerignore: Prevent secrets from being copied into the image..git .env __pycache__ passwords.txt
4. Common Commands Cheat Sheet#
| Command | Action |
|---|---|
docker build -t myapp . | Build an image |
docker run -p 80:80 myapp | Run container mapping port 80 |
docker ps | List running containers |
docker exec -it <id> bash | Shell into a container |
docker system prune | Clean up unused images/volumes |