# Docker 容器化开发环境实施计划 > **目标**: 在 Docker 容器内运行 FastAPI,使用 asyncpg 驱动,解决 macOS GSSAPI 问题 > **预计时间**: 30 分钟 > **状态**: 待执行 > **创建时间**: 2026-01-17 ## 背景 ### 问题 - macOS 上 asyncpg 存在 GSSAPI 认证问题 - 无法直接连接 PostgreSQL("role postgres does not exist" 错误) - 已尝试多种方案均无效 ### 解决方案 在 Docker 容器内运行 FastAPI,完全避免 macOS 环境问题,同时保留 asyncpg 的性能优势(比 psycopg 快 2.8 倍)。 ## 实施步骤 ### Step 1: 恢复 asyncpg 依赖 **文件**: `server/requirements.txt` **操作**: ```txt # 数据库驱动(使用 asyncpg 获得最佳性能) asyncpg==0.29.0 ``` **说明**: 移除 psycopg,恢复 asyncpg --- ### Step 2: 恢复数据库连接配置 **文件**: `server/.env` **操作**: ```env # 数据库配置(容器内网络) DATABASE_URL=postgresql+asyncpg://postgres:postgres@postgres:5432/jointo DATABASE_ECHO=True ``` **说明**: - 使用容器名称 `postgres` 作为主机名(Docker 内部 DNS) - 不再使用 127.0.0.1(宿主机地址) --- **文件**: `server/app/core/database.py` **操作**: ```python # 创建异步引擎 engine = create_async_engine( settings.DATABASE_URL, echo=settings.DATABASE_ECHO, future=True, pool_pre_ping=True, pool_size=10, max_overflow=20 ) ``` **说明**: 移除 connect_args(容器内不需要禁用 GSSAPI) --- ### Step 3: 优化 Dockerfile(支持热重载) **文件**: `server/Dockerfile` **操作**: ```dockerfile FROM python:3.11-slim WORKDIR /app # 安装系统依赖 RUN apt-get update && apt-get install -y \ gcc \ postgresql-client \ && rm -rf /var/lib/apt/lists/* # 复制依赖文件 COPY requirements.txt . # 安装 Python 依赖 RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码(开发模式下会被挂载覆盖) COPY . . # 暴露端口 EXPOSE 8000 # 启动命令(支持热重载) CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] ``` **关键点**: - 使用 Python 3.11(与本地一致) - 安装 gcc(编译 asyncpg C 扩展) - `--reload` 支持代码热重载 --- ### Step 4: 更新 docker-compose.yml **文件**: `server/docker-compose.yml` **操作**: 添加 `app` 服务 ```yaml version: "3.8" services: # PostgreSQL 数据库 postgres: image: postgres:14-alpine container_name: jointo-server-postgres environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: jointo ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5 networks: - jointo-network # Redis 缓存 redis: image: redis:7-alpine container_name: jointo-server-redis ports: - "6381:6379" volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - jointo-network # MinIO 对象存储 minio: image: minio/minio:latest container_name: jointo-server-minio environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin ports: - "9100:9000" - "9101:9001" volumes: - minio_data:/data command: server /data --console-address ":9001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 networks: - jointo-network # FastAPI 应用(新增) app: build: context: . dockerfile: Dockerfile container_name: jointo-server-app ports: - "8000:8000" volumes: - .:/app # 挂载代码目录(支持热重载) - /app/venv # 排除虚拟环境 environment: - DATABASE_URL=postgresql+asyncpg://postgres:postgres@postgres:5432/jointo - REDIS_URL=redis://redis:6379/0 - MINIO_ENDPOINT=minio:9000 depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy networks: - jointo-network restart: unless-stopped volumes: postgres_data: redis_data: minio_data: networks: jointo-network: driver: bridge ``` **关键配置**: - `volumes: - .:/app` - 挂载代码目录,支持热重载 - `depends_on` - 等待数据库服务健康后再启动 - `networks` - 所有服务在同一网络,可通过服务名互相访问 --- ### Step 5: 创建 .dockerignore **文件**: `server/.dockerignore` **操作**: ``` venv/ __pycache__/ *.pyc *.pyo *.pyd .Python *.so *.egg *.egg-info/ dist/ build/ .pytest_cache/ .coverage htmlcov/ .env .DS_Store *.log ``` **说明**: 避免将不必要的文件复制到镜像中 --- ### Step 6: 更新启动脚本 **文件**: `server/start_docker.sh`(新建) **操作**: ```bash #!/bin/bash # 停止并移除旧容器 docker-compose down # 构建并启动所有服务 docker-compose up --build -d # 查看日志 docker-compose logs -f app ``` **说明**: 简化 Docker 启动流程 --- ### Step 7: 更新 README.md **文件**: `server/README.md` **操作**: 添加 Docker 开发指南 ````markdown ## 开发环境 ### 方式 1: Docker 容器(推荐) **优点**: 环境一致,性能最优(使用 asyncpg) ```bash # 启动所有服务 docker-compose up --build -d # 查看日志 docker-compose logs -f app # 停止服务 docker-compose down ``` ```` 访问: - API 文档: http://localhost:8000/api/docs - 健康检查: http://localhost:8000/health ### 方式 2: 本地运行(仅限 Linux) macOS 用户请使用 Docker 方式,避免 asyncpg GSSAPI 问题。 ```bash # 启动依赖服务 docker-compose up -d postgres redis minio # 本地运行 FastAPI ./start_dev.sh ``` ```` --- ## 验证步骤 ### 1. 构建并启动服务 ```bash cd server docker-compose up --build -d ```` ### 2. 检查容器状态 ```bash docker-compose ps ``` 预期输出: ``` NAME STATUS jointo-server-app Up (healthy) jointo-server-postgres Up (healthy) jointo-server-redis Up (healthy) jointo-server-minio Up (healthy) ``` ### 3. 查看应用日志 ```bash docker-compose logs -f app ``` 预期输出: ``` 🚀 Starting Jointo API... ✅ Database initialized INFO: Uvicorn running on http://0.0.0.0:8000 ``` ### 4. 测试 API 端点 ```bash # 健康检查 curl http://localhost:8000/health # 数据库健康检查 curl http://localhost:8000/api/v1/health/db # API 文档 open http://localhost:8000/api/docs ``` ### 5. 测试热重载 修改 `app/main.py` 中的任意代码,保存后观察日志: ``` INFO: Detected file change, reloading... ``` --- ## 预期结果 ✅ FastAPI 在 Docker 容器内成功启动 ✅ asyncpg 正常连接 PostgreSQL ✅ 数据库表自动创建 ✅ 代码修改自动热重载 ✅ 所有健康检查端点正常响应 --- ## 回滚方案 如果遇到问题,可以快速回滚: ```bash # 停止 Docker 服务 docker-compose down # 使用本地 + psycopg 方案 # 1. 修改 requirements.txt: asyncpg -> psycopg[binary] # 2. 修改 .env: postgresql+asyncpg -> postgresql+psycopg # 3. 重新安装依赖 # 4. 启动本地服务 ``` --- ## 相关文件 - `server/Dockerfile` - 应用镜像定义 - `server/docker-compose.yml` - 服务编排配置 - `server/.dockerignore` - Docker 忽略文件 - `server/start_docker.sh` - 启动脚本 - `server/requirements.txt` - Python 依赖 - `server/.env` - 环境变量配置 - `server/README.md` - 项目文档 --- ## 后续优化 1. **多阶段构建**: 减小镜像体积 2. **健康检查**: 为 app 服务添加健康检查 3. **日志管理**: 配置日志收集和轮转 4. **性能监控**: 集成 Prometheus + Grafana 5. **调试支持**: 配置远程调试器 --- ## 更新日志 - **2026-01-17**: 初始版本,实施 Docker 容器化开发环境