Appearance
课 1 · Docker Compose 完整部署
本课目标
把模块 1 的开发环境 Compose 升级为完整部署配置,覆盖启动顺序、依赖等待、健康检查和日志收集。
关键理解:开发环境 Compose 和部署 Compose 的核心区别是"谁等谁"——部署时必须等基础服务完全就绪才启动应用。
开发 vs 部署配置的区别
| 开发(模块 1) | 部署(本课) | |
|---|---|---|
| 启动顺序 | 手动 pnpm dev:infra | depends_on + condition: service_healthy |
| 代码更新 | 本机 tsx watch | 构建镜像 |
| 环境变量 | .env 本地文件 | Docker secrets 或环境变量 |
| 日志 | 控制台输出 | 集中到文件或日志服务 |
完整 Compose 配置
yaml
# infra/docker-compose.yml
version: '3.9'
services:
redis:
image: redis:7-alpine
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 5s
timeout: 3s
retries: 5
volumes:
- redis-data:/data
elasticsearch:
image: elasticsearch:8.13.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms512m -Xmx512m
healthcheck:
test: ['CMD-SHELL', 'curl -sf http://localhost:9200/_cluster/health | grep -q yellow\\|green']
interval: 10s
timeout: 5s
retries: 12
volumes:
- es-data:/usr/share/elasticsearch/data
api:
build:
context: ..
dockerfile: apps/api/Dockerfile
ports:
- '3000:3000'
environment:
- NODE_ENV=production
- REDIS_URL=redis://redis:6379
- ELASTICSEARCH_URL=http://elasticsearch:9200
depends_on:
redis:
condition: service_healthy
elasticsearch:
condition: service_healthy
healthcheck:
test: ['CMD-SHELL', 'curl -sf http://localhost:3000/health']
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
worker:
build:
context: ..
dockerfile: apps/worker/Dockerfile
environment:
- NODE_ENV=production
- REDIS_URL=redis://redis:6379
- ELASTICSEARCH_URL=http://elasticsearch:9200
depends_on:
api:
condition: service_healthy # Worker 等 API 和基础设施都就绪
restart: unless-stopped
web:
build:
context: ..
dockerfile: apps/web/Dockerfile
ports:
- '8080:80'
depends_on:
api:
condition: service_healthy
volumes:
redis-data:
es-data:Dockerfile(API 示例)
dockerfile
# apps/api/Dockerfile
FROM node:20-alpine AS base
RUN corepack enable pnpm
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
COPY apps/api/package.json ./apps/api/
COPY packages/ ./packages/
RUN pnpm install --frozen-lockfile
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm --filter api build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/apps/api/dist ./dist
COPY --from=deps /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]启动顺序可视化
redis ──healthy──┐
├──> api ──healthy──┬──> worker
elasticsearch ───┘ └──> webdepends_on: condition: service_healthy 保证上游服务通过 healthcheck 才会启动下游服务,不靠"等几秒"来猜测。
常用部署命令
bash
# 构建并启动所有服务
docker compose up --build -d
# 查看服务状态
docker compose ps
# 查看某个服务的日志
docker compose logs -f api
# 停止所有服务
docker compose down
# 停止并删除数据卷(完全重置)
docker compose down -v本节产物
infra/
docker-compose.yml # 完整部署配置(含健康检查和依赖)
apps/api/Dockerfile
apps/worker/Dockerfile
apps/web/Dockerfile面试追问
你的项目如何控制成本?
三个方面:1)请求限流(模块 3),防止单用户或 Bug 导致大量 LLM 调用;2)问答缓存(模块 3),相同问题命中缓存不再调用模型;3)成本统计(模块 8 课 2),追踪每次调用的 token 数,及时发现异常消耗。部署阶段还会设置 LLM API 账户的每日消费限额,作为最后一道防线。
Docker Compose 和 Kubernetes 在什么情况下选哪个?
Docker Compose 适合:单机部署、开发环境、团队规模小、不需要自动扩缩容。Kubernetes 适合:多节点集群、需要自动扩缩容、高可用、有 DevOps 团队维护。进阶项目是单机课程项目,Docker Compose 已经足够,面试时说清楚选型理由即可。