前面的项目需要先准备 Python、虚拟环境和依赖,再启动 FastAPI。换一台机器时,Python 版本、依赖版本和启动命令都可能不同。本文把项目做成 Docker 镜像,读者只需构建一次镜像,再用 docker run 启动服务,打开 /docs 就能调用接口。

Docker 镜像保存运行 FastAPI 所需的代码、依赖和默认启动命令。容器是镜像启动后的运行实例。

Dockerfile 放什么

在项目根目录新建 Dockerfile。这段配置使用 Python 3.12 精简镜像,把 pyproject.tomlapp/ 复制进容器,安装项目后通过 FastAPI CLI 启动服务。

FROM python:3.12-slim

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY pyproject.toml ./
COPY app ./app

RUN pip install --no-cache-dir .

EXPOSE 8000

CMD ["fastapi", "run", "app/main.py", "--host", "0.0.0.0", "--port", "8000"]

WORKDIR /app 让后续命令都在容器的 /app 目录执行。pip install .pyproject.toml 安装当前项目和依赖;--no-cache-dir 不保留 pip 下载缓存,镜像会少一些无用文件。

CMD 使用 JSON 数组形式。容器停止时,Docker 能把停止信号直接交给 FastAPI 进程,应用有机会正常关闭。

--host 0.0.0.0 不能省略。容器中的 127.0.0.1 只指向容器自己,服务监听 0.0.0.0 后,Docker 的端口映射才能把请求转进应用。

用 .dockerignore 缩小构建上下文

Docker 构建时会把项目目录发送给守护进程。虚拟环境、Git 历史、测试缓存、本地数据库和 .env 都不应进入镜像。

在根目录新建 .dockerignore

.git
.venv
__pycache__/
*.py[cod]
.pytest_cache/
.ruff_cache/
.mypy_cache/
.env
*.db
*.egg-info/
tests/

.env 被排除后,JWT 密钥和环境差异不会写进镜像。镜像可以在开发、测试和生产环境复用,配置在启动容器时再传入。

构建镜像

确认 Docker Desktop 已启动,在项目根目录执行:

docker build -t fastapi-beginner-lab .

末尾的 . 表示构建上下文是当前目录。-t fastapi-beginner-lab 给构建结果取一个本地镜像名,后面的 docker run 会使用这个名字。

首次构建会下载 Python 基础镜像和 Python 依赖,耗时通常比后续构建长。修改应用代码后再次执行同一条命令,Docker 会复用没有变化的层。

用容器启动接口

先准备运行时配置。没有 .env 时,项目会使用 Settings 中的开发默认值;已有 .env 时,把它作为容器环境变量传入。

Copy-Item .env.example .env
docker run --rm --name fastapi-beginner-lab -p 8000:8000 --env-file .env fastapi-beginner-lab

-p 8000:8000 左边是 Windows 主机端口,右边是容器内 FastAPI 的端口。--rm 会在容器停止后删除容器本身,适合本地试验;镜像仍然保留,可以再次启动。

打开下面地址验证:

http://127.0.0.1:8000/docs

也可以在另一个 PowerShell 窗口请求健康检查:

Invoke-RestMethod http://127.0.0.1:8000/health

返回内容里有 statusapp_nameapp_env,说明端口映射和应用启动命令都已生效。

容器里的 SQLite 数据不会自动保留

当前默认数据库地址是 sqlite:///./fastapi_beginner_lab.db。这会在容器的 /app 目录创建 SQLite 文件。使用 docker run --rm 停止容器后,该容器连同其中新建的数据库文件都会消失。

本地演示可以接受这个行为。需要保存商品、用户或上传记录时,至少要做两件事:把数据库地址改到挂载目录或外部数据库,并在启动容器时提供对应的卷或数据库连接配置。Docker 解决的是运行环境一致,不会替应用保存数据。

镜像构建和容器运行各查什么

遇到问题时,可以按下面顺序检查:

  • docker build 失败:查看 DockerfileCOPY 路径、pyproject.toml 和依赖安装输出。
  • 容器启动后马上退出:运行 docker logs fastapi-beginner-lab,检查 FastAPI 的启动异常。
  • 浏览器无法访问:确认容器命令使用了 --host 0.0.0.0,并确认 -p 8000:8000 没有被其他程序占用。
  • 配置不符合预期:确认 .env 没有被复制进镜像,并检查 --env-file .env 是否指向当前项目的配置文件。

动手改一下

把应用名称改为容器环境的名字:

$env:APP_NAME = "FastAPI Container Lab"
docker run --rm -p 8000:8000 -e APP_NAME=$env:APP_NAME fastapi-beginner-lab

刷新 /docs。页面标题显示 FastAPI Container Lab,说明配置来自启动容器时的环境变量,而不是写进镜像的代码。


到这里,这篇的目标已经完成:

  • 我们写出了可构建 FastAPI 项目的 Dockerfile
  • 我们用端口映射启动容器,并访问了 /docs/health
  • 我们知道了 .env 与 SQLite 数据都不该直接固化进镜像。

本文代码:https://github.com/tanghaojin/fastapi-beginner-lab/tree/article-17-docker

参考资料

  • FastAPI in Containers - Docker: https://fastapi.tiangolo.com/deployment/docker/
  • Dockerfile reference: https://docs.docker.com/reference/dockerfile/

更多推荐