130 lines
5.4 KiB
Markdown
130 lines
5.4 KiB
Markdown
---
|
||
id: devops.docker.scenario.compose-dev-env
|
||
title: 一条命令拉起开发环境:Go API + Python AI 服务 + PostgreSQL + Redis
|
||
type: scenario
|
||
domain: devops
|
||
stack: [docker, go, fastapi, postgresql, redis]
|
||
tags: [Compose, 开发环境, 多语言, 健康检查, 配置管理]
|
||
level: intermediate
|
||
prerequisites: [devops.docker.compose-network-volume]
|
||
est_hours: 2
|
||
related: [devops.docker.interview, devops.nginx.index]
|
||
week: [3, 13, 14]
|
||
---
|
||
|
||
# 一条命令拉起开发环境:Go API + Python AI 服务 + PostgreSQL + Redis
|
||
|
||
## 业务背景与问题
|
||
|
||
一个企业知识库项目:Go 写业务 API(用户、权限、文档管理),Python FastAPI 写 AI 服务(RAG 检索、调用大模型),PostgreSQL(含 pgvector)存数据和向量,Redis 做缓存。新人入职配环境要一两天:Python 版本不一致、pgvector 扩展装不上、各自本机的端口冲突;测试环境和开发环境配置也对不上。
|
||
|
||
## 约束
|
||
|
||
- 开发者使用 macOS、Windows(WSL2)、Linux 都有。
|
||
- 模型 API Key 不能出现在仓库里。
|
||
- 开发时改代码要能快速生效,不想每次都重新构建镜像。
|
||
- 同一套编排文件,尽量也能用于单机测试环境。
|
||
|
||
## 方案设计
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Dev[浏览器 / 前端 dev server] -->|:8080| GW[Nginx 网关]
|
||
GW -->|/api| API[Go API]
|
||
GW -->|/ai| AI[Python AI 服务]
|
||
API --> DB[(PostgreSQL + pgvector)]
|
||
AI --> DB
|
||
API --> R[(Redis)]
|
||
AI --> R
|
||
```
|
||
|
||
1. **一个 `compose.yaml` 描述全部服务**,服务之间用服务名通信;只有网关映射端口到宿主机。
|
||
2. **数据库用带 pgvector 的镜像**,初始化 SQL 放在 `./db/init/` 挂载到 `/docker-entrypoint-initdb.d/`(只在数据卷为空的首次启动时执行)。
|
||
3. **健康检查 + 依赖条件**:数据库健康后才启动 API 和 AI 服务。
|
||
4. **配置分层**:`compose.yaml` 写公共配置;`compose.override.yaml`(开发时自动合并)挂载源码目录、开启热重载;密钥放在不提交的 `.env`,仓库里提供 `.env.example`。
|
||
5. **Makefile 封装常用命令**:`make up`、`make logs`、`make psql`、`make reset-db`。
|
||
|
||
## 关键代码
|
||
|
||
```yaml
|
||
# compose.yaml(节选)
|
||
services:
|
||
gateway:
|
||
image: nginx:1.27-alpine
|
||
ports: ["8080:80"]
|
||
volumes:
|
||
- ./deploy/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||
depends_on: [api, ai]
|
||
|
||
api:
|
||
build: ./api
|
||
environment:
|
||
DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app?sslmode=disable
|
||
REDIS_URL: redis://redis:6379/0
|
||
depends_on:
|
||
db: { condition: service_healthy }
|
||
|
||
ai:
|
||
build: ./ai
|
||
environment:
|
||
DATABASE_URL: postgresql://app:${DB_PASSWORD}@db:5432/app
|
||
LLM_API_KEY: ${LLM_API_KEY} # 来自不提交的 .env
|
||
depends_on:
|
||
db: { condition: service_healthy }
|
||
|
||
db:
|
||
image: pgvector/pgvector:pg17
|
||
environment:
|
||
POSTGRES_USER: app
|
||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||
POSTGRES_DB: app
|
||
volumes:
|
||
- pgdata:/var/lib/postgresql/data
|
||
- ./db/init:/docker-entrypoint-initdb.d:ro # 首次启动执行 CREATE EXTENSION vector 等
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U app -d app"]
|
||
interval: 5s
|
||
retries: 10
|
||
|
||
redis:
|
||
image: redis:7-alpine
|
||
|
||
volumes:
|
||
pgdata:
|
||
```
|
||
|
||
```yaml
|
||
# compose.override.yaml:docker compose up 时自动合并,只用于本地开发
|
||
services:
|
||
ai:
|
||
volumes:
|
||
- ./ai/app:/app/app # 挂载源码
|
||
command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||
```
|
||
|
||
单个 Go 服务的完整 Dockerfile 和 compose 示例见 [examples/go-api-compose](../examples/go-api-compose/)。镜像标签仅作示例,以各镜像的官方页面为准。
|
||
|
||
## 取舍
|
||
|
||
| 方案 | 优点 | 缺点 |
|
||
| --- | --- | --- |
|
||
| **Compose 全部容器化(本方案)** | 环境一致、上手快 | 在 macOS / Windows 上挂载源码的文件性能较差;镜像占磁盘 |
|
||
| 只把依赖(数据库、Redis)放容器,应用本机跑 | 调试方便、热更新快 | 应用的语言版本仍需各自安装 |
|
||
| 远程开发环境(云端开发机 / Dev Container) | 环境完全统一 | 需要网络和额外成本 |
|
||
|
||
实际团队里常见做法是两者结合:依赖一律容器化;应用代码可以选择容器内运行或本机运行。
|
||
|
||
## 易错点
|
||
|
||
- 修改了 `db/init` 里的 SQL 却发现没执行:初始化脚本只在数据卷为空时执行,需要 `docker compose down -v` 重建(会清空数据)或写迁移脚本。
|
||
- `.env` 被提交到仓库,泄露模型 API Key。加入 `.gitignore`,提交前扫描(仓库里的 `tools/check_sensitive.py`)。
|
||
- 所有服务都映射端口,本机端口冲突;只映射网关。
|
||
- 开发环境的 `--reload`、源码挂载被带到测试环境:override 文件只用于开发,测试环境显式指定 `-f compose.yaml`。
|
||
- 容器内时区、字符集和生产不一致,导致时间相关的 bug 只在某个环境出现。统一使用 UTC 存储。
|
||
|
||
## 面试怎么讲
|
||
|
||
> “项目是 Go 业务 API 加 Python AI 服务,依赖 PostgreSQL(pgvector)和 Redis。我用 Compose 把它们编排起来:服务之间用服务名通信,只有网关对外映射端口;数据库加了健康检查,应用等数据库就绪才启动;密钥放在不提交的 .env,开发时用 override 文件挂载源码热重载。新人 clone 后一条命令就能跑起来。”
|
||
|
||
追问准备:生产环境也用 Compose 吗(单机小规模可以,多机用 Kubernetes)?数据怎么备份?
|