Chapter 22 · Production Deployment
Chapter goals: Understand the core conceptual model of production deployment, master multi-worker tuning, Docker image building best practices, and health checks with graceful shutdown.
22.1 The Conceptual Model of Deployment
When deploying FastAPI (or any Web API), there are only six things that truly matter:
- Security (HTTPS) — handled by a TLS-terminating proxy outside the application;
- Auto-start on boot — app relaunches automatically after server restart;
- Crash recovery — process auto-recovers after crashing;
- Replication (replicas) — how many processes to run to utilize multiple cores;
- Memory — control per-process memory usage;
- Pre-start steps — database migrations, etc.
Understand a key layering: the ASGI server (Uvicorn) runs your app, but HTTPS is typically not its job. A TLS-terminating proxy (Traefik / Caddy / Nginx + Certbot / cloud load balancer) decrypts traffic on the outside and forwards HTTP to Uvicorn. "Liveness and restart" is handled by process managers like Docker/Kubernetes/systemd/Supervisor. Each component has its own role — do not ask Python processes to do the proxy's job.
Client --HTTPS--> TLS Terminating Proxy (443) --HTTP--> Uvicorn/FastAPI (8000, internal)22.2 fastapi run and Multi-Worker Tuning
Development uses fastapi dev; the official CLI provides the production counterpart:
# Single process
fastapi run main.py --port 80
# Multi-worker: 1 parent process + 4 worker subprocesses
fastapi run main.py --workers 4
# Equivalent native approach
uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
# If deployed behind a proxy like Nginx/Traefik, trust proxy headers
fastapi run app/main.py --port 80 --proxy-headers--workers 4 starts 1 parent process (process manager) + 4 worker processes, each handling requests independently, utilizing multiple CPU cores.
Worker count tuning rules of thumb:
- CPU-bound primary →接近
CPU core count; - I/O-bound primary (typical API app) → higher, e.g.
(2 × CPU) + 1; - Upper limit is constrained by memory: each worker is a fully独立 process, memory usage scales linearly;
- Container/Kubernetes exception: usually run 1 Uvicorn process per container, scale horizontally via replica count (pod count) — avoid double-copying that oversells resources.
Do not use fastapi dev in production
The dev mode's auto-reload and debugging features are neither performant nor secure for production; always use fastapi run or bare uvicorn in production.
22.3 Dockerfile Best Practices
Official recommended Dockerfile structure (every line has a reason):
FROM python:3.13
WORKDIR /code
# ① Copy dependency list first —— it rarely changes
COPY ./requirements.txt /code/requirements.txt
# ② Install dependencies next —— when the list has not changed, Docker cache is hit, completing in seconds
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# ③ Copy application code last —— changes most frequently, placed last to keep cache effective
COPY ./app /code/app
# ④ CMD must use exec form (JSON array)
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]Four key details:
- Layer order IS cache strategy: requirements.txt changes rarely — put it first;
app/changes daily — put it last. Wrong order means reinstalling all dependencies for every one-line code change. --no-cache-diris a pip option that does not leave downloaded packages in the image, reducing size.- CMD must use exec form (
["fastapi", "run", ...]): shell form (CMD fastapi run ...) runs the command in a shell subprocess, which cannot properly receive SIGTERM, breaking graceful shutdown. 4.配套.dockerignoreto prevent junk from entering the image:
.git
__pycache__
*.pyc
.env # Never bake into the image!
docs
tests
.venvBuild and run:
docker build -t myapp .
docker run -d --name mycontainer -p 80:80 myapp22.4 Health Checks and Graceful Shutdown
Uvicorn supports graceful shutdown: when it receives SIGTERM, it finishes in-flight requests before exiting. Configure this in your orchestrator:
# docker-compose.yml
services:
api:
build: .
ports:
- "80:80"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 10s
retries: 3
stop_grace_period: 30s # Wait up to 30s for in-flight requests to finishAdd a /health endpoint:
@app.get("/health")
async def health():
return {"status": "ok"}22.5 Chapter Summary
- Deployment has six concerns: HTTPS, auto-start, crash recovery, replication, memory, pre-start steps;
fastapi runfor production;--workers Nfor multi-process; never usedevmode in production;- Dockerfile layer order is a cache strategy: dependencies first, code last;
- Graceful shutdown: Uvicorn handles SIGTERM; set
stop_grace_periodin your orchestrator.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. Why should you not use fastapi dev in production?
2. Why must CMD use exec form (JSON array) in Docker?
3. In a Dockerfile, why copy requirements.txt before the application code?
4. What does stop_grace_period do in Docker Compose?
🛠️ Hands-On Exercises
- Write a Dockerfile for your FastAPI app following the official best practices (layer order, exec form CMD, .dockerignore); build and run it.
- Add a
/healthendpoint; configure Docker Compose healthcheck and stop_grace_period; verify health status withdocker ps. - Scale to 4 workers with
--workers 4; measure RPS improvement vs single worker on a simple endpoint.
Course complete. You now have a production-grade FastAPI application from zero to deployment.