跳到主要内容

第 12 课:为真实项目编写 Dockerfile 和 Compose

第四阶段 · 真实 student-management-api · 面向 Docker 初学者

本课完成标准​

你能够:

  • 读懂真实项目 Dockerfile;
  • 让代码、static 和 migrations 进入镜像;
  • 使用生产 .env 注入配置;
  • 构建并启动 API 容器;
  • 通过登录页面和静态 CSS 验证容器;
  • 理解为什么不在 Compose 中创建 MySQL。

1. 先看最终关系​

Dockerfile(制作 FastAPI 镜像)
↓ build
镜像(代码 + 依赖 + static + migrations)
↓ run
容器(读取 .env,监听 8000)

本课只构建 api 服务。MySQL 在 ECS 主机上运行,所以 Compose 不写 mysql 服务,也不创建数据库卷。

2. 编写 Dockerfile​

在项目根目录创建 Dockerfile:

FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app

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

COPY . .

EXPOSE 8000

CMD ["fastapi", "run", "main.py", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
指令本项目中的含义
FROM使用 Python 3.12 slim 作为基础环境
WORKDIR /app让 main.py 的相对路径可以找到 static/
COPY requirements.txt先复制依赖清单,便于 Docker 缓存
RUN pip install在镜像内部安装依赖,不使用本机 venv
COPY . .复制源码、static、migrations 等内容
CMD容器启动时运行真实 FastAPI

为什么先复制 requirements?代码经常修改,依赖通常不常修改,这样可以复用依赖安装缓存。

3. workers 先从 1 开始​

本课使用一个 worker,先保证能启动和排错。生产环境是否使用更多 worker,要结合 ECS 内存、请求量和数据库连接池测试。

fastapi run main.py --host 0.0.0.0 --port 8000 --workers 2

每个 worker 都是一个 Python 进程,会增加内存和数据库连接。不要把 workers 数量当成越大越好。

4. 编写 compose.yaml​

在同一个项目根目录创建 compose.yaml:

services:
api:
build:
context: .
dockerfile: Dockerfile
env_file:
- .env
ports:
- "127.0.0.1:8000:8000"
restart: unless-stopped
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/login', timeout=3)"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s

当前项目没有专门的 /health 路由,但 /login 会返回登录页面,所以健康检查访问它。它只检查 HTTP 服务和静态文件是否能响应,不代表数据库迁移已经完成。

配置作用
env_file把 ECS 上的 .env 注入容器,镜像本身不保存密码
127.0.0.1:8000:8000只允许 ECS 本机访问,后续由 Nginx 对外提供服务
restart: unless-stopped异常退出自动重启,手动停止后保持停止
healthcheck让 Docker 报告服务是否能响应登录页面

5. 检查构建上下文​

cd /www/wwwroot/student-management-api
docker compose config
docker build --check .

如果 Docker 版本不支持 docker build --check,可以跳过它,继续执行 docker compose config。确认 .dockerignore 没有排除 static、migrations 和 requirements.txt。

6. 构建并启动真实项目​

docker compose build
docker compose up -d
docker compose ps
docker compose logs --tail=100 api

首次构建会下载 Python 基础镜像和依赖,可能需要几分钟。状态理想情况下显示 Up,健康状态可能显示 healthy。

在 ECS 本机测试:

curl -i http://127.0.0.1:8000/login
curl -I http://127.0.0.1:8000/static/css/common.css

服务器终端使用 curl 即可。Windows 本地不负责测试 ECS 的 127.0.0.1;后续通过 SSH 或 Nginx 域名访问。

7. 不要在启动命令中自动迁移​

本课的容器启动只负责启动 FastAPI,不把 alembic upgrade head 拼到 CMD 中。数据库迁移需要单独检查和执行,下一课会先解决容器到 MySQL 的连接,第 14 课再正式操作 Alembic。

如果每次容器重启都自动迁移,迁移失败可能让应用无法启动,也很难判断是应用问题还是数据库问题。

8. 常见错误排查​

现象先检查常见原因
ModuleNotFoundErrorrequirements.txt、构建日志依赖未列出或未重新构建
FileNotFoundError: staticWORKDIR、COPY . .、.dockerignore工作目录错误或静态文件未进入镜像
容器 Exiteddocker compose logs api配置、导入或启动命令错误
健康检查 unhealthy/login 和日志应用还在启动、静态文件缺失或端口不对
数据库连接失败容器内环境和 MySQL 地址第 13 课专门排查,不要开放 3306 公网

9. 一分钟自测​

问题 1:为什么 compose.yaml 使用 127.0.0.1:8000:8000?

  • A. 让 FastAPI 只被 ECS 本机和 Nginx 访问
  • B. 让 Docker 自动安装 MySQL
  • C. 让容器不需要端口

问题 2:为什么 healthcheck 访问 /login?

  • A. 当前项目已有登录页面,能验证 FastAPI 和 static 是否响应
  • B. /login 是 MySQL 管理接口
  • C. /login 会自动执行数据库迁移

答案:1A,2A。

本课通关证据​

docker compose config
docker compose build
docker compose up -d
docker compose ps
docker compose logs --tail=100 api
curl -i http://127.0.0.1:8000/login
curl -I http://127.0.0.1:8000/static/css/common.css

完成标准:真实镜像构建成功,api 容器运行中,登录页面和静态 CSS 能响应,8000 只绑定 ECS 本机,并且 Compose 没有创建 MySQL 容器。

如果遇到错误,请贴完整命令和输出,但隐藏密码、Token 与私钥。


← 第 11 课:整理真实项目依赖 · 第 13 课:连接宝塔 MySQL →

课程推荐

想系统学习这门课程?

你已阅读完本文。需要更完整的知识体系,可以继续了解「Vibe Coding 实战课程」。

查看课程详情