跳到主要内容

基础设施搭建 (Docker Compose)

本指南定义了使用 Docker Compose 进行本地基础设施编排的标准方法。我们优先采用 分层、基于 Profile 的配置,可从简单服务扩展到复杂的多平台架构。

🏗 Docker Compose 架构

使用 分层 Compose 文件 方法:基础文件定义核心基础设施,叠加文件(Overlay files)添加特定环境或特定 Profile 的配置。

目录结构

infra/ (或 platform-dev/)
├── compose.yaml # 基础:基础设施服务 (Postgres, Redis 等)
├── compose.dev.yaml # 开发叠加:绑定挂载、调试端口、热重载
├── compose.staging.yaml # 预发布叠加:生产目标、预发布配置
├── compose.prod.yaml # 生产叠加:不可变镜像、资源限制
└── env/
├── compose.dev.env # Compose 插值变量 (开发)
├── compose.staging.env # Compose 插值变量 (预发布)
├── compose.prod.env # Compose 插值变量 (生产)
├── shared.base.env # 跨服务运行时变量 (所有环境)
├── shared.dev.env # 跨服务运行时变量 (开发覆盖)
├── shared.prod.env # 跨服务运行时变量 (生产值)
├── service-a.dev.env # 特定服务变量 (开发)
└── service-a.prod.env # 特定服务变量 (生产)
专业提示:文件命名

始终使用 .yaml(而非 .yml)以及 compose.yaml(现代标准),以保持跨项目的一致性。

执行策略

# 后面的文件会覆盖前面的配置
docker compose \
--env-file ./env/compose.dev.env \
-f compose.yaml \
-f compose.dev.yaml \
--profile dev \
up -d

🔀 Monorepo vs Polyrepo:Compose 布局

仓库策略直接影响 Compose 文件的组织方式和 build.context 的配置。

Polyrepo 布局

每个服务有独立仓库。infra/ 目录与服务代码平级:

api-gateway/ # 服务仓库
├── Dockerfile
└── src/
infra/ # 基础设施仓库(共享)
├── compose.yaml
└── compose.dev.yaml

build.context 指向服务目录:

services:
api:
build:
context: ../api-gateway # 相对于 infra/
dockerfile: Dockerfile

Monorepo 布局

所有服务和共享库在同一仓库。Compose 文件通常位于仓库根目录或专用 infra/ 目录:

monorepo/
├── infra/
│ ├── compose.yaml
│ └── compose.dev.yaml
├── services/
│ ├── api-gateway/
│ │ └── Dockerfile
│ └── auth-service/
│ └── Dockerfile
└── libs/
└── shared-utils/

build.context 指向仓库根目录,以便 Dockerfile 能 COPY 共享库:

services:
api:
build:
context: ../.. # 仓库根目录
dockerfile: services/api-gateway/Dockerfile

对比

维度PolyrepoMonorepo
Compose 位置各仓库独立或共享 infra 仓库仓库根目录或 infra/ 目录
build.context服务目录仓库根目录(可访问共享库)
共享服务独立的 infra compose 文件单一基础 compose 文件
服务隔离天然(独立仓库)需要 profiles 或 filters

📦 基础基础设施服务

基础 compose.yaml 文件定义了所有服务都依赖的共享基础设施。

compose.yaml (节选)

services:
database:
image: postgres:16-alpine
environment:
POSTGRES_USER: devuser
POSTGRES_PASSWORD: devpass
POSTGRES_DB: platform_db
ports:
- "5432:5432"
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U devuser -d platform_db"]
interval: 5s
timeout: 3s
retries: 10

message-queue:
image: rabbitmq:3-management-alpine
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
ports:
- "5672:5672"
- "15672:15672"
volumes:
- mq_data:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "ping"]
interval: 5s
timeout: 3s
retries: 10
关键设计决策
  • 健康检查 (Health Checks):始终包含健康检查,以便依赖服务可以使用 condition: service_healthy 来避免启动竞争条件。
  • 命名卷 (Named Volumes):使用命名卷在容器生命周期内保持数据持久化。
  • Alpine 镜像:优先使用基于 Alpine 的镜像,以获得更小的占用空间和更快的 CI/CD 拉取速度。

🛠 开发覆盖 (Overrides)

开发叠加文件 (compose.dev.yaml) 添加了本地源代码的绑定挂载、调试端口以及特定于应用程序的服务。

开发模式

services:
api:
build:
context: ../api-gateway
dockerfile: Dockerfile
target: dev # 多阶段:使用 dev 目标
command: npm run dev
ports:
- "3000:3000"
volumes:
- ../api-gateway:/workspace/api-gateway
- /workspace/api-gateway/node_modules # 防止宿主机覆盖 node_modules
depends_on:
database: { condition: service_healthy }
env_file:
- ./env/shared.base.env
- ./env/shared.dev.env
profiles:
- dev

🔐 环境变量策略

我们遵循 分层覆盖 模式:基础契约 → 环境覆盖 → 机密信息。

层级用途来源
Compose 插值控制镜像标签、项目名称--env-file 标志
共享基础服务发现、队列名称env_file (shared.base.env)
环境覆盖日志级别、TTLenv_file (shared.dev.env)
机密信息密码、密钥Vault / 外部管理器
安全警示

绝不 将实际的生产机密信息提交到版本控制。使用 .env.example 文件作为模板,并在运行时使用安全的机密管理器注入机密。


🌐 网络与服务发现

同一 Compose 项目中的所有服务共享一个默认的桥接网络,并可以通过 服务名称 相互解析。

连接示例

上下文协议地址
容器间Docker DNShttp://database:5432
宿主机到容器端口映射http://localhost:5432
跨服务共享网络http://ai-service:8001/api/infer

📑 多阶段 Dockerfile 模式

每个服务 必须 使用多阶段构建,以将开发工具与生产运行时分离。

模式对比

维度开发目标 (Dev Target)生产目标 (Prod Target)
调试工具包含 (Nodemon, Inspect)排除
依赖项完整 (开发 + 运行时)仅运行时
源代码绑定挂载复制并构建
安全性非 Root (映射 UID)最小化 (nobody/alpine)