用 Docker 与 Compose 拉起前后端项目的步骤
前言
本地跑一个「前端静态站点 + 后端 API」的项目时,常要在本机安装 Python、Node、Nginx 等环境,版本冲突和路径问题很占时间。
Docker 把运行环境打在镜像里,Docker Compose 用一份 YAML 把多个服务一次性定义好,适合团队内对齐「同一套启动方式」。
本文不取代官方文档的深度细节,而是按「项目根下放 backend、frontend、docker」这类常见布局,拆解 Dockerfile、compose、Nginx 三件事,并给出可照抄的启动顺序。
路径请以你本机实际目录为准,若结构与下文不同,只需替换服务名、context、dockerfile 与挂载路径即可。
环境
- 已安装 Docker Engine(或 Docker Desktop),终端可执行
docker-compose。 - 需要构建前端静态产物时,在宿主机装好 Node/npm 或 Bun,与容器内 nginx 挂载目录配合。
- Linux 上使用 GPU 时,除镜像与驱动外,还需 NVIDIA Container Toolkit,并在 Compose 里按文档增加
deploy.resources(参考示例文件末尾注释)。
拆解配置
本节对应 docker 目录里与运行直接相关的四个文件:后端 Dockerfile、前端 Dockerfile、Compose、Nginx。
它们共同完成「后端跑 API、前端用 nginx 提供页面并把 /api 转到后端」。
后端镜像
镜像基于 python slim,安装 uv 作为依赖与运行时管理工具,配置国内 PyPI、工作目录与健康依赖库(如 libgomp 等),并暴露 API 端口 8000。
1 | FROM python:3.13-slim-bookworm |
Compose 里没有把「启动命令」写进 Dockerfile,而是在 Compose 的 command 里执行:先 uv sync --frozen --no-dev 装依赖,再 uv run python -m uvicorn app.main:app 启动 FastAPI/Uvicorn。
这样改启动参数时不一定重建镜像。
context: .. 表示构建上下文在多级目录上一级(仓库根),dockerfile 指向 docker/docker_backend.Dockerfile,与文件实际放置方式一致。volumes 把宿主 backend 挂到容器 /app,开发时改代码可不重建后端镜像。
前端镜像
前端镜像很轻:基于 nginx Alpine,仅保留 Web 服务能力;真正的页面来自宿主机构建出的 frontend/dist,通过只读挂载到 nginx 默认站点目录。
1 | # syntax=docker/dockerfile:1 |
宿主机需在项目 frontend 下先执行 npm run build(或项目文档中的等价命令),保证 dist 目录存在且有内容。depends_on 只做启动顺序约束,不能保证后端 API 已就绪;若需在健康检查后再导流,可为 backend 增加 healthcheck 并在前端侧配合重试。
Nginx 反代 API
/api/ 的请求转发到 Compose 网络内的服务名 backend,端口与 Uvicorn 一致为 8000;SPA 路由用 try_files 落到 index.html。
nginx.conf
1 | server { |
注意
这里
proxy_pass http://backend:8000;是后端服务的内部端口,不是对外开放的端口。
Compose配置
Compose 可使用 name 为编排命名,生成的默认网络等项目级资源会带此前缀;下面示例中用 example-web-stack,你按项目改名即可。
每个需要 build 的服务都应配置 image,否则构建出的镜像只会得到随机 project_service 形式的临时名,不方便打标签发布。
GPU 相关说明见文末注释示意,需在真实环境中自行按 Compose 文档增补 deploy 段落。
以下为与前文片段衔接的完整 docker-compose.yml 骨架(含镜像名称与版本标签)。
1 | name: paper-training-stack |
注意
这里
backend不用对外开放,所以不用设置端口映射。
构建
这里拉 moby/buildkit 拉不下来,可临时关掉 BuildKit,改用旧版构建
1 | cd docker |
运行
1 | cd docker |
如果想强制重新构建镜像
1 | docker-compose up -d --build |