《Docker Compose + Dockerfile 完全解析:手把手教你部署 FastAPI + LangGraph 项目》

《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_fileJWT_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/metricscadvisor: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 用户依赖缓存等最佳实践,打造了安全高效的镜像。

  • 两者结合,实现了 “一次构建(镜像),多处运行(不同配置)” 的容器化黄金法则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值