资讯动态

Python FastAPI 项目使用 Docker 部署并映射端口(完整教程)

发布时间:2026/10/15 6:23:01 来源:尧图企业网站定制
文章目录前言一、最终部署架构二、创建 FastAPI 项目三、配置项目依赖四、编写 Dockerfile1. 基础镜像2. 工作目录3. 安装 Python 依赖4. 声明容器端口5. 启动 FastAPI五、配置 Docker Compose六、为什么使用 127.0.0.1七、配置环境变量八、配置 Docker 忽略文件九、构建 Docker 镜像十、启动容器十一、验证接口1. 查看端口映射2. 测试健康检查3. 访问 Swagger4. 测试业务接口十二、修改宿主机映射端口十三、配置 Nginx 反向代理十四、配置 HTTPS十五、不使用 Docker Compose 的写法踩坑记录问题一Docker Hub连接超时问题二pip install 十几分钟没有完成问题三Dockerfile 出现 unknown instruction问题四宿主机端口被占用问题五修改端口后没有生效问题六健康检查失败十六、常用命令汇总总结前言最近需要把一个 Python 接口部署到服务器并提供给业务方调用。项目使用 FastAPI 开发部署时主要有下面几个需求使用 Docker 打包并运行 FastAPI。将容器里的8000端口映射到宿主机的18000端口。FastAPI 端口不直接暴露到公网。使用 Nginx 对外提供访问。后续可以继续配置域名和 HTTPS。部署过程看起来不复杂但实际操作时可能遇到以下问题Docker Hub连接超时python:3.12-slim镜像拉取失败pip install十几分钟没有反应Dockerfile 提示unknown instruction不清楚宿主机端口和容器端口的区别修改端口后没有生效。本文记录一套完整的部署过程并把这些常见问题集中整理出来。一、最终部署架构部署完成后的访问关系如下业务方 ↓ HTTPS 443 ↓ Nginx ↓ http://127.0.0.1:18000 ↓ Docker端口映射 ↓ FastAPI容器 8000本次使用的端口服务位置端口FastAPI 容器内部8000Docker 宿主机18000Nginx 对外端口80/443端口映射关系宿主机 127.0.0.1:18000 → Docker 容器 8000二、创建 FastAPI 项目项目目录如下order-api/ ├── app/ │ ├── __init__.py │ └── main.py ├── .dockerignore ├── .env ├── Dockerfile ├── compose.yaml └── requirements.txt创建app/main.pyfromfastapiimportFastAPIfrompydanticimportBaseModel appFastAPI(title订单服务,version1.0.0,docs_url/docs,redoc_url/redoc,)classOrderRequest(BaseModel):customer_id:stramount:floatapp.get(/health)defhealth():return{status:ok}app.get(/ready)defready():return{status:ready}app.post(/api/v1/orders)defcreate_order(request:OrderRequest):return{code:0,message:success,data:{customer_id:request.customer_id,amount:request.amount,},}这里一共提供了三个接口GET /health GET /ready POST /api/v1/orders其中/health用于检查服务是否正常运行。FastAPI 还会自动生成 Swagger 文档http://服务地址/docs三、配置项目依赖创建requirements.txtfastapi[standard]如果项目中使用了数据库、Redis 等组件可以继续添加sqlalchemy pymysql redis alembic生产环境建议固定依赖版本避免某个依赖发布新版本后导致镜像重新构建失败。例如fastapi[standard]经过测试的版本四、编写 Dockerfile创建DockerfileFROM public.ecr.aws/docker/library/python:3.12-slim ENV PYTHONDONTWRITEBYTECODE1 ENV PYTHONUNBUFFERED1 WORKDIR /code COPY requirements.txt /code/requirements.txt ARG PIP_INDEX_URLhttps://pypi.tuna.tsinghua.edu.cn/simple RUN python -m pip install \ --no-cache-dir \ --disable-pip-version-check \ --timeout 60 \ --retries 3 \ --index-url ${PIP_INDEX_URL} \ -r /code/requirements.txt COPY app /code/app RUN useradd --create-home --uid 10001 appuser USER appuser EXPOSE 8000 CMD [fastapi, run, app/main.py, --port, 8000, --proxy-headers, --forwarded-allow-ips*]下面简单说明几个关键配置。1. 基础镜像FROM public.ecr.aws/docker/library/python:3.12-slim正常情况下可以直接使用FROM python:3.12-slim但是如果当前网络访问 Docker Hub 超时可以尝试 AWS 公共镜像仓库中的镜像FROM public.ecr.aws/docker/library/python:3.12-slim2. 工作目录WORKDIR /code后续复制的代码和执行的命令都以/code为工作目录。3. 安装 Python 依赖RUN python -m pip install \ --no-cache-dir \ --disable-pip-version-check \ --timeout 60 \ --retries 3 \ --index-url ${PIP_INDEX_URL} \ -r /code/requirements.txt如果默认 PyPI 下载速度较慢可以通过PIP_INDEX_URL指定一个可访问的镜像。公司内部如果有 Python 制品仓库优先使用公司仓库。4. 声明容器端口EXPOSE 8000需要注意EXPOSE 8000只说明程序在容器中使用8000端口并不会自动把该端口映射到宿主机。真正的端口映射需要在 Docker Compose 中配置。5. 启动 FastAPICMD [fastapi, run, app/main.py, --port, 8000, --proxy-headers, --forwarded-allow-ips*]建议将CMD写成完整的一行。如果直接拆成下面这种格式CMD [ fastapi, run ]Dockerfile 没有正确添加续行符时可能会报错unknown instruction: fastapi五、配置 Docker Compose创建compose.yamlservices:api:build:context:.dockerfile:Dockerfileargs:PIP_INDEX_URL:https://pypi.tuna.tsinghua.edu.cn/simpleimage:order-api:1.0.0container_name:order-apirestart:unless-stoppedenv_file:-.envports:-127.0.0.1:18000:8000healthcheck:test:[CMD,python,-c,import urllib.request; urllib.request.urlopen(http://127.0.0.1:8000/health, timeout5)]interval:30stimeout:5sretries:3start_period:20slogging:driver:json-fileoptions:max-size:20mmax-file:5这里最重要的是下面这段ports:-127.0.0.1:18000:8000Docker 端口映射格式宿主机IP:宿主机端口:容器端口因此这条配置的含义是127.0.0.1 : 18000 : 8000 ↓ ↓ ↓ 宿主机IP 宿主机端口 容器端口最终访问关系http://127.0.0.1:18000 ↓ Docker容器中的8000端口六、为什么使用 127.0.0.1本文使用ports:-127.0.0.1:18000:8000这表示18000端口只允许宿主机本机访问。局域网和公网中的其他电脑不能直接访问http://服务器IP:18000这种方式适合生产环境因为 FastAPI 不会直接暴露到公网外部请求统一经过 Nginx。如果确实需要让其他电脑直接访问可以修改为ports:-18000:8000它等价于ports:-0.0.0.0:18000:8000其他电脑便可以访问http://宿主机IP:18000但正式环境不建议这样配置。七、配置环境变量创建.envAPP_ENVproduction如果项目中使用数据库和 Redis可以继续添加DATABASE_URLmysqlpymysql://user:passworddatabase-host:3306/order_db REDIS_URLredis://redis-host:6379/0 API_TOKENreplace-with-real-token不要将.env提交到 Git。建议在.gitignore中添加.env .venv/ __pycache__/ *.pyc .pytest_cache/八、配置 Docker 忽略文件创建.dockerignore.git .env .venv __pycache__ .pytest_cache *.pyc tests这样可以避免无关文件和敏感信息进入 Docker 镜像。九、构建 Docker 镜像执行dockercompose build--progressplain--progressplain可以显示完整的构建日志。如果需要忽略缓存重新构建dockercompose build --no-cache--progressplain如果构建成功可以查看镜像dockerimages预期可以看到order-api 1.0.0十、启动容器执行dockercompose up-d如果修改过 Dockerfile 或端口映射建议执行dockercompose up-d--build--force-recreate查看运行状态dockercomposeps正常情况下会看到NAME STATUS PORTS order-api Up (healthy) 127.0.0.1:18000-8000/tcp其中127.0.0.1:18000-8000/tcp说明宿主机的18000已经成功映射到容器的8000。十一、验证接口1. 查看端口映射dockerport order-api预期8000/tcp - 127.0.0.1:180002. 测试健康检查curlhttp://127.0.0.1:18000/health预期{status:ok}3. 访问 Swagger浏览器打开http://127.0.0.1:18000/docs4. 测试业务接口curl-XPOSThttp://127.0.0.1:18000/api/v1/orders\-HContent-Type: application/json\-d{ customer_id: C10001, amount: 99.5 }预期{code:0,message:success,data:{customer_id:C10001,amount:99.5}}十二、修改宿主机映射端口假设需要将宿主机端口从18000改成9000ports:-127.0.0.1:9000:8000重新创建容器dockercompose up-d--force-recreate新访问地址curlhttp://127.0.0.1:9000/health这里修改的是宿主机端口容器中的 FastAPI 仍然使用8000。十三、配置 Nginx 反向代理安装 Nginxsudoaptupdatesudoaptinstallnginx创建配置文件/etc/nginx/sites-available/order-api配置如下server { listen 80; listen [::]:80; server_name api.example.com; client_max_body_size 10m; access_log /var/log/nginx/order-api-access.log; error_log /var/log/nginx/order-api-error.log; location / { proxy_pass http://127.0.0.1:18000; proxy_http_version 1.1; 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_set_header X-Request-Id $request_id; proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; } }重点是proxy_pass http://127.0.0.1:18000;因为 Nginx运行在宿主机上所以需要访问宿主机映射后的18000端口。启用配置sudoln-s/etc/nginx/sites-available/order-api\/etc/nginx/sites-enabled/order-api检查 Nginx 配置sudonginx-t重新加载sudosystemctl reload nginx测试curlhttp://api.example.com/health十四、配置 HTTPS安装 Certbotsudoaptinstallcertbot python3-certbot-nginx申请证书sudocertbot--nginx-dapi.example.com测试 HTTPScurlhttps://api.example.com/health检查证书自动续期sudocertbot renew --dry-run配置完成后业务方使用https://api.example.com不需要知道 Docker 内部端口或宿主机的18000端口。十五、不使用 Docker Compose 的写法如果不使用 Docker Compose可以通过docker run映射端口dockerrun-d\--nameorder-api\--restartunless-stopped\-p127.0.0.1:18000:8000\order-api:1.0.0其中-p 127.0.0.1:18000:8000与 Compose 中的配置完全相同ports:-127.0.0.1:18000:8000踩坑记录问题一Docker Hub连接超时错误信息Client.Timeout exceeded while awaiting headers或者failed to resolve source metadata for docker.io/library/python:3.12-slim这说明 Docker 无法正常访问https://registry-1.docker.io/v2/可以尝试为 Docker Desktop 配置代理使用公司内部 Harbor使用可访问的公共镜像仓库在其他机器下载后离线导入。本文使用FROM public.ecr.aws/docker/library/python:3.12-slim作为替代。问题二pip install十几分钟没有完成如果构建长时间停留在RUN pip install ...一般是容器访问 PyPI 速度较慢或直接超时。使用下面的命令可以查看详细日志dockercompose build --no-cache--progressplain如果日志中反复出现Retrying ReadTimeoutError Connection timed out可以配置ARG PIP_INDEX_URLhttps://pypi.tuna.tsinghua.edu.cn/simple如果通过本机代理构建假设代理端口是7890dockercompose build\--build-argHTTP_PROXYhttp://host.docker.internal:7890\--build-argHTTPS_PROXYhttp://host.docker.internal:7890\--no-cache\--progressplainMac Docker Desktop 中容器访问宿主机需要使用host.docker.internal不能使用127.0.0.1因为容器中的127.0.0.1指向容器自身。问题三Dockerfile 出现 unknown instruction错误信息unknown instruction: fastapi原因通常是CMD被错误拆行。推荐写法CMD [fastapi, run, app/main.py, --port, 8000, --proxy-headers, --forwarded-allow-ips*]问题四宿主机端口被占用错误信息port is already allocatedLinux 查看端口sudoss-lntp|grep18000Mac 查看端口lsof-nP-iTCP:18000-sTCP:LISTEN解决方法停止占用端口的进程或者更换宿主机端口。例如ports:-127.0.0.1:18001:8000问题五修改端口后没有生效Docker 容器创建后端口映射不能直接动态修改。修改compose.yaml后需要重新创建容器dockercompose up-d--force-recreate问题六健康检查失败健康检查运行在容器内部因此应该访问http://127.0.0.1:8000/health不能写成http://127.0.0.1:18000/health18000是宿主机端口8000才是容器内部端口。十六、常用命令汇总启动服务dockercompose up-d停止并删除容器dockercompose down重新构建dockercompose build --no-cache--progressplain重新创建容器dockercompose up-d--build--force-recreate查看状态dockercomposeps查看日志dockercompose logs-fapi查看端口映射dockerport order-api测试服务curlhttp://127.0.0.1:18000/health总结本次部署最关键的是理解下面三个端口之间的关系Nginx 80/443 ↓ 宿主机 127.0.0.1:18000 ↓ Docker 容器 8000 ↓ FastAPIDockerfile 中定义 FastAPI 使用的容器端口EXPOSE 8000Docker Compose 完成端口映射ports:-127.0.0.1:18000:8000Nginx访问映射后的宿主机端口proxy_pass http://127.0.0.1:18000;本机测试地址http://127.0.0.1:18000/health最终提供给业务方的地址https://api.example.com使用这种部署方式可以避免直接把 FastAPI 容器端口暴露到公网同时保留 Docker 部署、升级和回滚的便利性。文章标签Python、FastAPI、Docker、Docker Compose、Nginx、接口部署、端口映射

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑