《Docker Compose + Dockerfile 完全解析:手把手教你部署 FastAPI + LangGraph 项目》
引言
在现代后端开发中,Docker 已经成为部署和运行应用的标配。但对于初学者来说,一个包含数据库、缓存、监控、应用服务的完整 docker-compose.yaml 文件往往令人望而生畏。
本文将从一个真实的生产级项目出发,逐行解析 docker-compose.yaml 和 Dockerfile,涵盖:
-
PostgreSQL + pgvector(向量数据库)
-
Valkey(Redis 兼容缓存)
-
FastAPI + LangGraph 应用
-
Prometheus + Grafana + cAdvisor 监控栈
读完本文,你将彻底理解 “一次构建,多处运行” 的容器化核心理念。
一、docker-compose.yaml 顶层结构解析
yaml
version: '3.8'
services:
# ... 各个服务定义
networks:
monitoring:
driver: bridge
volumes:
grafana-storage:
postgres-data:
valkey-data:
| 字段 | 含义 |
|---|---|
version: '3.8' | Compose 文件格式版本,支持 Docker Engine 19.03.0+ |
services: | 定义所有容器服务(应用、数据库、监控等) |
networks: | 创建自定义桥接网络 monitoring,让所有服务通过服务名互相通信 |
volumes: | 声明 Docker 命名卷,用于数据持久化(容器删除后数据不丢失) |
关键理解:所有服务加入同一个
monitoring网络后,app容器可以通过主机名db直接访问数据库容器,无需暴露端口到宿主机。
二、数据库服务 db —— PostgreSQL + pgvector
yaml
db:
image: pgvector/pgvector:pg16
platform: linux/amd64
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
restart: always
networks:
- monitoring
逐字段解读:
-
image: pgvector/pgvector:pg16:使用官方 pgvector 镜像(基于 PostgreSQL 16),内置向量相似度搜索插件,适用于 AI 应用中的 Embedding 存储和检索。 -
platform: linux/amd64:强制指定平台,避免在 ARM 架构(如 M1/M2 Mac)上运行时出现兼容性问题。 -
environment::从宿主机的.env文件读取数据库名、用户名、密码,保持敏感信息不入库。 -
ports: "5432:5432":映射端口到宿主机,方便用psql或数据库 GUI 工具直接连接调试。 -
volumes::挂载命名卷postgres-data到/var/lib/postgresql/data,确保数据库文件持久化。 -
healthcheck::每 10 秒执行pg_isready检查数据库是否就绪。app服务依赖此健康状态,确保数据库启动后才启动应用。 -
restart: always:容器异常退出时自动重启。
三、Valkey 缓存服务(Redis 兼容)
yaml
valkey:
image: valkey/valkey:8.1.6-alpine
ports:
- "6379:6379"
volumes:
- valkey-data:/data
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: always
networks:
- monitoring
-
image: valkey/valkey:8.1.6-alpine:Valkey 是 Redis 的开源替代品,完全兼容 Redis 协议,Alpine 版本体积小。 -
healthcheck:通过valkey-cli ping检测服务是否正常。 -
注意:缓存是可选的。如果
.env中未设置VALKEY_HOST,应用不会启用缓存功能。
四、应用服务 app —— 核心业务
yaml
app:
build:
context: .
args:
APP_ENV: ${APP_ENV:-development}
ports:
- "8000:8000"
volumes:
- ./app:/app/app
- ./logs:/app/logs
env_file:
- .env.${APP_ENV:-development}
environment:
- APP_ENV=${APP_ENV:-development}
- JWT_SECRET_KEY=${JWT_SECRET_KEY:-supersecretkeythatshouldbechangedforproduction}
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
restart: on-failure
networks:
- monitoring
重点解析:
-
build::使用当前目录(.)作为构建上下文,构建时传入APP_ENV构建参数,默认development。 -
volumes::-
./app:/app/app:将本地代码挂载进容器,覆盖镜像内的代码。修改本地代码后容器自动同步,实现开发热重载。 -
./logs:/app/logs:将日志挂载到宿主机,便于持久化查看。
-
-
env_file::根据APP_ENV加载对应的.env.development或.env.production文件。 -
environment::直接设置环境变量,优先级高于env_file。JWT_SECRET_KEY提供了不安全默认值,生产环境务必覆盖。 -
depends_on::db服务必须处于service_healthy状态后才启动本容器,避免启动时连接数据库失败。 -
restart: on-failure:仅在非正常退出时重启,避免手动停止后反复重启。
五、监控三件套:Prometheus + Grafana + cAdvisor
5.1 Prometheus —— 指标采集
yaml
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
networks:
- monitoring
restart: always
挂载本地的 prometheus.yml 配置文件,定义抓取目标(如 app:8000/metrics、cadvisor:8080/metrics)。
5.2 Grafana —— 可视化面板
yaml
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- grafana-storage:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
- ./grafana/dashboards/dashboards.yml:/etc/grafana/provisioning/dashboards/dashboards.yml
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
networks:
- monitoring
restart: always
-
使用命名卷
grafana-storage保存用户配置和面板数据。 -
通过 Provisioning 方式自动加载预定义的仪表板(JSON 文件)。
-
默认管理员密码
admin,生产环境务必修改。
5.3 cAdvisor —— 容器资源监控
yaml
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
networks:
- monitoring
restart: always
挂载宿主机的多个系统目录,用于获取容器和宿主机的 CPU、内存、网络等运行时指标。
六、Dockerfile 逐行解析
dockerfile
FROM python:3.13.2-slim WORKDIR /app
使用 Python 3.13 的精简版镜像,设置工作目录为 /app。
6.1 构建参数与环境变量
dockerfile
ARG APP_ENV=production
ENV APP_ENV=${APP_ENV} \
PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100
-
ARG APP_ENV=production:构建参数,可通过docker build --build-arg APP_ENV=development覆盖。 -
ENV:设置运行时环境变量,优化 Python 和 pip 行为。
6.2 安装系统依赖
dockerfile
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
&& pip install --upgrade pip \
&& pip install uv \
&& rm -rf /var/lib/apt/lists/*
-
build-essential:提供 C/C++ 编译器,用于编译某些 Python 原生扩展。 -
libpq-dev:PostgreSQL 客户端开发库,供psycopg2连接数据库使用。 -
uv:极快的 Python 包管理器,替代 pip/poetry。 -
rm -rf /var/lib/apt/lists/*:清理 apt 缓存,大幅减小镜像体积(最佳实践)。
6.3 分层复制依赖(利用 Docker 缓存加速)
dockerfile
COPY pyproject.toml uv.lock ./ RUN uv sync --frozen --no-install-project
-
只复制依赖定义文件,安装第三方库,暂不安装项目本身。
-
核心技巧:只要
pyproject.toml和uv.lock不变,这一层就会命中 Docker 缓存。每次修改源码时,不会重新下载和安装依赖,构建速度极快。
6.4 复制源码并安装项目
dockerfile
COPY . . RUN uv sync --frozen
复制全部源码,再次运行 uv sync,此时利用缓存,只链接项目自身的包。
6.5 安全与非 root 用户
dockerfile
RUN chmod +x /app/scripts/docker-entrypoint.sh RUN useradd -m appuser && chown -R appuser:appuser /app USER appuser RUN mkdir -p /app/logs
-
赋予入口脚本执行权限。
-
创建普通用户
appuser,将/app目录所有权转交给该用户。 -
切换到非 root 用户运行,防止容器内以 root 执行带来的安全风险。
6.6 启动命令
dockerfile
EXPOSE 8000 ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"] CMD ["/app/.venv/bin/uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
-
ENTRYPOINT:固定入口点,先执行脚本(通常用于数据库迁移等待)。 -
CMD:提供默认参数给 ENTRYPOINT,最终启动 Uvicorn 服务器。
七、Dockerfile 与 Compose 的协作:“一次构建,多处运行”
| 组件 | 职责 |
|---|---|
| Dockerfile | 构建镜像:定义操作系统环境、依赖、源码和启动入口。它是“静态”的。 |
| docker-compose.yaml | 运行容器:定义端口映射、卷挂载、环境变量注入、服务依赖。它是“动态”的。 |
开发场景:Compose 通过 volumes: - ./app:/app/app 挂载本地代码覆盖镜像内容,配合 APP_ENV=development,实现热重载调试。
生产场景:移除代码卷挂载,传入 APP_ENV=production,使用镜像内固化的稳定代码,保证环境一致性。
八、总结
-
docker-compose.yaml定义了 6 个服务:应用、数据库、缓存、Prometheus、Grafana、cAdvisor,构成了一个完整的可观测性闭环。 -
Dockerfile通过分层构建、非 root 用户、依赖缓存等最佳实践,打造了安全高效的镜像。 -
两者结合,实现了 “一次构建(镜像),多处运行(不同配置)” 的容器化黄金法则。

92

被折叠的 条评论
为什么被折叠?



