使用 Docker 和 Nginx 部署 Python FastAPI 应用完整步骤

落日邮差
落日邮差
发布时间:2026-11-01 | 6人浏览过
原创

本文详细介绍使用 Docker 容器化 Python FastAPI 应用,并通过 Nginx 作为高性能反向代理网关的完整部署步骤,涵盖架构原理、项目结构、Dockerfile 编写、Nginx 配置、Docker Compose 编排及生产环境校验。

使用 Docker 和 Nginx 部署 Python FastAPI 应用完整步骤
在生产环境中部署 Python FastAPI 应用时,将 FastAPI 容器与 Nginx 反向代理组合是兼顾性能、安全与维护性的成熟方案。FastAPI 及其 ASGI 服务器(如 Uvicorn)专注于执行 Python 异步业务逻辑,而 Nginx 驻留在应用外层,负责统一监听公网端口(80 与 443)、终结 SSL/TLS 握手、缓冲客户端慢连接以及阻断非法畸形请求。本文提供一套基于 Docker 与 Docker Compose 的标准化部署方案,从零构建独立运行环境,详细阐述从项目目录结构规划、FastAPI 容器化打包、Nginx 反向代理转发规则编写,到一键编排启动与连通性验证的完整操作步骤。

一、整体架构与工作流转原理

在生产级部署中,直接将 Uvicorn 监听的端口暴露到公网存在多项局限:Uvicorn 作为 ASGI 应用服务器,设计重心在于利用 Python 的 asyncio 事件循环高效处理 Python 协程与业务请求,但其并非为直接对抗恶劣的公网网络环境而设计。公网请求往往包含慢速客户端连接、恶意畸形包探测、突发流量洪峰以及静态资源的高频请求,这些若直接由 Uvicorn 处理,会过早耗尽工作进程的并发队列与文件描述符。

引入 Nginx 担任反向代理网关后,整个流量流转机制被清晰地划分为外网与内网两层:外部客户端与 Nginx 建立 TCP 连接,Nginx 在前端完成请求合法性过滤、连接缓冲与 SSL 加解密;通过内部 Docker 虚拟网络,Nginx 将清洗合规后的请求以轻量 HTTP 协议转发至后端的 FastAPI 容器。FastAPI 容器无需对外开放宿主机端口,仅在 Docker 内部桥接网络与 Nginx 通信,从而构筑了严格的网络边界防护。

使用 Docker 和 Nginx 部署 Python FastAPI 应用完整步骤
图 1:使用 Docker 与 Nginx 部署 FastAPI 的分层网络拓扑与请求流转图

二、项目工程目录与基础业务代码准备

为了让部署流程条理清晰并支持多环境平滑迁移,建议按照职责对配置文件与业务源代码进行目录分离。创建一个名为 fastapi-nginx-docker 的工作根目录,其标准布局如下:

目录结构 project tree
fastapi-nginx-docker/
├── docker-compose.yml       # Docker Compose 服务编排配置文件
├── nginx/
│   └── nginx.conf           # Nginx 反向代理与 HTTP 转发规则
└── app/
    ├── Dockerfile           # FastAPI 应用容器镜像构建脚本
    ├── requirements.txt     # Python 依赖包清单
    └── main.py              # FastAPI 应用入口与核心路由

1. 编写 Python 依赖文件

在 app/requirements.txt 中指定生产所需的最小依赖包集合。为了保证容器运行时的稳定性与可复现性,建议固定主版本号:

requirements.txt app/requirements.txt
fastapi==0.110.0
uvicorn[standard]==0.29.0
pydantic==2.6.4

2. 编写 FastAPI 业务代码

在 app/main.py 中编写基础示例应用。代码包含一个根路径探针接口和一个状态查询接口,并在接口中回显接收到的客户端 IP 信息,便于后续验证反向代理请求头传递是否正确:

Python app/main.py
import time
from fastapi import FastAPI, Request

app = FastAPI(
    title="FastAPI Docker Gateway Demo",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

@app.get("/")
def read_root():
    return {
        "status": "online",
        "service": "fastapi-docker-nginx",
        "timestamp": int(time.time())
    }

@app.get("/api/v1/system/status")
def system_status(request: Request):
    # 提取经过 Nginx 转发的真实客户端 IP 与 Host 头
    client_ip = request.headers.get("x-real-ip", request.client.host if request.client else "unknown")
    host_header = request.headers.get("host", "unknown")
    forwarded_proto = request.headers.get("x-forwarded-proto", "http")

    return {
        "app_status": "healthy",
        "client_real_ip": client_ip,
        "request_host": host_header,
        "protocol": forwarded_proto,
        "backend_engine": "uvicorn-asgi"
    }

三、编写 Dockerfile 容器化 FastAPI 应用

在 app/Dockerfile 中定义构建镜像的步骤。在容器工程实践中,构建速度与运行安全是两大关键考量:利用 Docker 分层缓存机制可大幅减少镜像构建时间,而以非 root 用户身份启动进程则是避免容器逃逸的安全基线。

Dockerfile app/Dockerfile
# 选用官方轻量级 Python 运行时基础镜像
FROM python:3.11-slim

# 设置 Python 环境变量:
# 1. PYTHONUNBUFFERED=1 保证日志直接输出至终端,不进行流缓冲,方便 docker logs 采集
# 2. PYTHONDONTWRITEBYTECODE=1 阻止生成 .pyc 文件,保持容器干净
ENV PYTHONUNBUFFERED=1     PYTHONDONTWRITEBYTECODE=1

# 设置容器内工作目录
WORKDIR /app

# 先独立复制依赖描述文件,安装依赖包
# 这样当仅修改业务代码时,该步骤会命中缓存,无需重复下载第三方包
COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

# 复制业务源码到工作目录
COPY . /app

# 创建非 root 专用运行用户并切换,提升运行时安全性
RUN useradd -u 1000 -m appuser &&     chown -R appuser:appuser /app

USER appuser

# 声明容器内部监听端口(供文档与编排参考)
EXPOSE 8000

# 启动 Uvicorn ASGI 服务:必须监听 0.0.0.0,否则宿主机和 Nginx 无法访问
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
重要注意事项:为什么必须绑定 0.0.0.0?
在容器环境内运行服务时,如果启动参数设置为 --host 127.0.0.1,Uvicorn 只会监听容器自身的回环网络接口(loopback)。由于 Docker 为每个容器分配了独立的网络命名空间,来自 Nginx 容器的请求到达网卡时会被直接丢弃,最终导致 Nginx 报 502 Bad Gateway 错误。监听 0.0.0.0 才能保证应用接受来自容器内所有网络接口的转发流量。
使用 Docker 和 Nginx 部署 Python FastAPI 应用完整步骤
图 2:FastAPI 容器镜像分层构建、缓存机制与安全运行生命周期

四、配置 Nginx 反向代理与请求头转发

在 nginx/nginx.conf 中定义 Nginx 反向代理规则。Nginx 既作为前端请求路由中心,又充当网络协议转换器。在这里,Nginx 必须将客户端原始的域名、协议与真实 IP 通过专属 HTTP Header 传递给 FastAPI,避免代理后信息丢失。

Nginx Config nginx/nginx.conf
worker_processes auto;

events {
    worker_connections 1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    # 日志格式定义,打印上游响应耗时与真实客户端 IP
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';

    access_log /var/log/nginx/access.log main;
    error_log  /var/log/nginx/error.log warn;

    sendfile        on;
    keepalive_timeout  65;

    # 客户端上传包体限制(按需调整)
    client_max_body_size 20M;

    # 定义后端应用上游服务器池:通过 Docker 内部服务名 "web" 与端口 8000 寻址
    upstream fastapi_backend {
        server web:8000;
        keepalive 32;
    }

    server {
        listen 80;
        server_name localhost;

        # 针对静态资源或根路径的全局代理
        location / {
            proxy_pass http://fastapi_backend;

            # 协议与连接优化
            proxy_http_version 1.1;
            proxy_set_header Connection "";

            # 核心请求头传递:将客户端真实元数据传递给 FastAPI
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # 代理超时控制(秒)
            proxy_connect_timeout 60s;
            proxy_send_timeout    60s;
            proxy_read_timeout    60s;

            # 开启缓冲,避免慢客户端直接阻塞后端 Uvicorn
            proxy_buffering on;
            proxy_buffer_size 8k;
            proxy_buffers 8 8k;
        }
    }
}

上述配置的关键指令解析:

  • upstream fastapi_backend { server web:8000; }:利用 Docker 内部集成的 DNS 解析器,将名为 web 的容器服务名解析为其对应的容器虚拟 IP。
  • proxy_set_header X-Real-IP $remote_addr;:将与 Nginx 建立 TCP 连接的客户端实际 IP 填入 X-Real-IP 头中,以便 FastAPI 获取访问者的真实物理地址。
  • proxy_set_header X-Forwarded-Proto $scheme;:让后端明确请求是基于 HTTP 还是 HTTPS 协议到达前端的。这在配置 SSL 证书后尤其重要,能避免 FastAPI 自动生成的 OpenAPI/Swagger 文档资源加载出现混合内容警告。
使用 Docker 和 Nginx 部署 Python FastAPI 应用完整步骤
图 3:Nginx 反向代理层 HTTP 请求头重写与网络元数据转交模型

五、使用 Docker Compose 编排多容器服务

在项目根目录下编写 docker-compose.yml 文件,将 web(FastAPI)和 proxy(Nginx)两个容器组合在同一个专用的自定义网络中,实现容器生命周期的统一管理与按序启动。

YAML docker-compose.yml
services:
  web:
    build:
      context: ./app
      dockerfile: Dockerfile
    container_name: fastapi_app
    restart: unless-stopped
    expose:
      - "8000"
    networks:
      - fastapi_network
    environment:
      - APP_ENV=production

  proxy:
    image: nginx:1.25-alpine
    container_name: nginx_proxy
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - web
    networks:
      - fastapi_network

networks:
  fastapi_network:
    driver: bridge

编排规则的关键设计考量:

  • 内部端口开放(expose: - "8000") vs 物理映射(ports):在 web 服务中,仅声明了 expose: - "8000",并没有声明 ports 映射。这意味着只有同在 fastapi_network 网络的容器(即 Nginx)可以通过 http://web:8000 访问它,宿主机外部无法通过 8000 端口直连应用,有效消除了未经反向代理过滤的潜在入侵通道。
  • Nginx 卷挂载(volumes):将宿主机的 ./nginx/nginx.conf 映射到容器内的 /etc/nginx/nginx.conf 并设置为只读(:ro),便于在宿主机调整代理规则而无需频繁重新构建镜像。
  • 自动重启策略(restart: unless-stopped):确保宿主机重启或容器因偶发未捕获异常退出时,Docker 守护进程能自动拉起服务。

六、服务启动与连通性验证

在项目根目录(即 fastapi-nginx-docker/)下打开终端,依次执行以下步骤启动并验证服务运行状态。

1. 构建镜像并后台启动容器

Shell 构建与拉起命令
docker compose up -d --build

2. 检查容器运行状态

Shell 查看容器列表
docker compose ps

终端中输出的状态列表应如下所示(状态列需为 Up):

输出示例 示例输出 (docker compose ps)
NAME          IMAGE               COMMAND                  SERVICE   CREATED          STATUS          PORTS
fastapi_app   fastapi-app         "uvicorn main:app --…"   web       10 seconds ago   Up 9 seconds    8000/tcp
nginx_proxy   nginx:1.25-alpine   "/docker-entrypoint.…"   proxy     10 seconds ago   Up 9 seconds    0.0.0.0:80->80/tcp

3. 使用 curl 发送 HTTP 请求测试

在终端向本机 80 端口(Nginx 监听端口)发送请求,测试反向代理连通性:

Shell 验证根路由
curl -i http://localhost/
输出示例 示例输出 (HTTP 响应头与 JSON 体)
HTTP/1.1 200 OK
Server: nginx/1.25.4
Date: Thu, 30 Oct 2026 09:15:20 GMT
Content-Type: application/json
Content-Length: 68
Connection: keep-alive

{"status":"online","service":"fastapi-docker-nginx","timestamp":1793351720}

进一步请求状态接口,验证真实客户端 IP 与请求头转发功能:

Shell 验证状态接口
curl -s http://localhost/api/v1/system/status
输出示例 示例输出 (JSON 结构)
{"app_status":"healthy","client_real_ip":"172.18.0.1","request_host":"localhost","protocol":"http","backend_engine":"uvicorn-asgi"}

4. 查看实时运行日志

当接口请求出现异常时,可通过以下命令实时追踪 Nginx 访问日志与 FastAPI 应用内部报错:

Shell 日志查看命令
# 查看 Nginx 访问与转发日志
docker compose logs -f proxy

# 查看 FastAPI 应用及 Uvicorn 运行日志
docker compose logs -f web
使用 Docker 和 Nginx 部署 Python FastAPI 应用完整步骤
图 4:FastAPI + Nginx 部署实施、运行检验与生产核对全景路线图

七、生产环境高频问题排查与运维清单

故障现象 根本原因排查 标准处置方案
502 Bad Gateway Uvicorn 启动参数误配为 --host 127.0.0.1,导致容器拒绝外来访问;或 nginx.conf 中 upstream 声明的服务名拼写错误。 检查 Dockerfile 的 CMD 指令,确保为 --host 0.0.0.0;检查 nginx.conf 中的 server web:8000; 是否与 compose 中的服务名 web 严格吻合。
Swagger / Docs 加载失败 在启用 HTTPS 时,Nginx 未传递 X-Forwarded-Proto $scheme,FastAPI 认为处于 HTTP 环境,文档资产加载产生混合内容(Mixed Content)被浏览器阻断。 在 Nginx location / 中补充 proxy_set_header X-Forwarded-Proto $scheme;,并在 FastAPI 实例化时按需指定 root_path。
413 Request Entity Too Large 客户端上传文件或大 JSON 请求体超过 Nginx 默认的 1MB 阈值。 在 nginx.conf 的 http 或 server 上下文中增加 client_max_body_size 20M;(按实际业务上限调整)。
并发吞吐量不足 容器内单个 Uvicorn 进程受 Python GIL 限制,仅能利用单核 CPU 处理业务代码。 在生产环境修改启动命令,增加工作进程数(例如 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]),或通过 Gunicorn 作为进程管理器驱动 Uvicorn Worker。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表