Docker: 综合实战
最后更新:2026-08-26
这是本课程的毕业项目——把 23 课的知识串起来,从零部署一个全栈微服务到生产环境。
1. 你将学到
- 全栈微服务架构设计
- 多阶段构建全流程实战
- 多服务 Compose 编排
- CI/CD 自动化部署
- 监控与告警体系搭建
2. 一个 3 天交付的故事
(1) 痛点:3 天内从本地到生产
Charlie 接到一个任务:在 3 天内将电商平台从本地开发部署到生产环境。架构包括 React frontend、Go API、PostgreSQL、Redis、RabbitMQ——5 个服务,0 个自动化流程。
(2) Docker 全栈工具链的解法
Charlie 用 Docker 全栈工具链,2 天完成交付:Dockerfile 编写 → Compose 编排 → CI/CD 自动部署 → 监控告警。
(3) 收益:2 天完成交付
从手动部署到全自动化,2 天内完成了架构设计、容器化、编排、CI/CD、监控——这就是掌握 Docker 全栈技能的价值。
3. 全栈架构设计
(1) 架构总览
graph TB
USER["Browser"] --> ING["Nginx<br/>:80<br/>React SPA + API Proxy"]
ING -->|"api/"| API1["Go API #1<br/>:8080"]
ING -->|"api/"| API2["Go API #2<br/>:8080"]
ING -->|"api/"| API3["Go API #3<br/>:8080"]
API1 --> PG["PostgreSQL<br/>:5432<br/>Primary DB"]
API2 --> PG
API3 --> PG
API1 --> REDIS["Redis<br/>:6379<br/>Cache"]
API2 --> REDIS
API3 --> MQ["RabbitMQ<br/>:5672<br/>Message Queue"]
MQ --> WRK["Worker<br/>Background Jobs"]
PROM["Prometheus<br/>:9090<br/>Metrics"] --> GRAF["Grafana<br/>:3000<br/>Dashboards"]
PROM --> API1
PROM --> PG
PROM --> REDIS
(2) 服务清单
| 服务 | 技术栈 | 镜像 | 端口 |
|---|---|---|---|
| Nginx | 反向代理 + 静态文件 | 自建(多阶段) | 80 |
| Go API | REST API | 自建(多阶段) | 8080 |
| PostgreSQL | 关系数据库 | postgres:15-alpine | 5432 |
| Redis | 缓存 + 会话 | redis:7-alpine | 6379 |
| RabbitMQ | 消息队列 | rabbitmq:3-management | 5672/15672 |
| Worker | 后台任务处理 | 自建(同 API 镜像) | - |
| Prometheus | 指标采集 | prom/prometheus | 9090 |
| Grafana | 可视化面板 | grafana/grafana | 3000 |
4. 前端 Dockerfile(React + Nginx)
▶ 示例:前端 Dockerfile 多阶段构建(难度⭐⭐⭐)
DOCKERFILE
# ============================================
# Stage 1: Build React application
# ============================================
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ============================================
# Stage 2: Serve with Nginx
# ============================================
FROM nginx:1.25-alpine
# Copy built assets
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy Nginx config for SPA routing
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Security: non-root user
RUN chown -R nginx:nginx /usr/share/nginx/html && \
chown -R nginx:nginx /var/cache/nginx && \
chown -R nginx:nginx /var/log/nginx
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=5s \
CMD wget -qO- http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]
5. 后端 Dockerfile(Go 多阶段)
▶ 示例:后端 Dockerfile 多阶段构建(难度⭐⭐⭐)
DOCKERFILE
# ============================================
# Stage 1: Build Go binary
# ============================================
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache git
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /app/server
# ============================================
# Stage 2: Minimal runtime
# ============================================
FROM alpine:3.19
RUN apk --no-cache add ca-certificates tzdata curl && \
adduser -D -u 1000 appuser
WORKDIR /app
COPY --from=builder /app/server .
RUN chown -R appuser:appuser /app
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
CMD ["/app/server"]
6. Docker Compose 编排
▶ 示例:完整 docker-compose.prod.yml(难度⭐⭐⭐)
YAML
# ============================================
# docker-compose.prod.yml - Full stack
# ============================================
services:
nginx:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "80:80"
depends_on:
api:
condition: service_healthy
restart: unless-stopped
networks:
- frontend
- backend
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
api:
build:
context: ./api
dockerfile: Dockerfile
environment:
DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/${DB_NAME}
REDIS_URL: redis://redis:6379
RABBITMQ_URL: amqp://guest:${MQ_PASSWORD}@rabbitmq:5672
deploy:
replicas: 3
resources:
limits:
cpus: "1.0"
memory: 512M
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
networks:
- backend
- db-net
- cache-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 10s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
worker:
build:
context: ./api
dockerfile: Dockerfile
command: ["/app/server", "worker"]
environment:
DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/${DB_NAME}
RABBITMQ_URL: amqp://guest:${MQ_PASSWORD}@rabbitmq:5672
depends_on:
postgres:
condition: service_healthy
rabbitmq:
condition: service_healthy
restart: unless-stopped
networks:
- backend
- db-net
postgres:
image: postgres:15-alpine
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
volumes:
- pg-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- db-net
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
restart: unless-stopped
networks:
- cache-net
rabbitmq:
image: rabbitmq:3-management-alpine
environment:
RABBITMQ_DEFAULT_PASS: ${MQ_PASSWORD}
ports:
- "15672:15672"
volumes:
- mq-data:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
interval: 15s
timeout: 10s
restart: unless-stopped
networks:
- backend
prometheus:
image: prom/prometheus:latest
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
ports:
- "9090:9090"
restart: unless-stopped
networks:
- backend
- db-net
- cache-net
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
volumes:
- grafana-data:/var/lib/grafana
depends_on:
- prometheus
restart: unless-stopped
networks:
- backend
volumes:
pg-data:
redis-data:
mq-data:
prometheus-data:
grafana-data:
networks:
frontend:
backend:
db-net:
internal: true
cache-net:
internal: true
7. CI/CD 配置
(1) GitHub Actions 全流程
YAML
# .github/workflows/deploy.yml
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ secrets.REGISTRY }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASS }}
- name: Build and push API
uses: docker/build-push-action@v5
with:
context: ./api
push: true
tags: ${{ secrets.REGISTRY }}/api:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push Frontend
uses: docker/build-push-action@v5
with:
context: ./frontend
push: true
tags: ${{ secrets.REGISTRY }}/frontend:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Deploy to production
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /opt/ecommerce
export API_TAG=${{ github.sha }}
export FRONTEND_TAG=${{ github.sha }}
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --remove-orphans
docker image prune -f
8. 监控配置
(1) Prometheus 配置
YAML
# monitoring/prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'api'
static_configs:
- targets: ['api:8080']
metrics_path: /metrics
- job_name: 'postgres'
static_configs:
- targets: ['postgres-exporter:9187']
- job_name: 'redis'
static_configs:
- targets: ['redis-exporter:9121']
- job_name: 'rabbitmq'
static_configs:
- targets: ['rabbitmq:15692']
9. 部署与验证
(1) 部署清单
| 步骤 | 操作 | 验证 |
|---|---|---|
| 1 | docker compose -f docker-compose.prod.yml up -d --build |
docker compose ps 全部 Up |
| 2 | 访问 http://localhost |
React 页面正常显示 |
| 3 | curl http://localhost/api/health |
{"status":"ok"} |
| 4 | 访问 http://localhost:3000 |
Grafana 登录页 |
| 5 | 访问 http://localhost:15672 |
RabbitMQ 管理页 |
| 6 | docker compose logs api |
API 日志无错误 |
(2) 对比表:裸机 vs Docker vs K8s
| 维度 | 裸机部署 | Docker Compose | Kubernetes |
|---|---|---|---|
| 部署时间 | 1-2 天 | 30 分钟 | 1-2 天(初始搭建) |
| 可重复性 | ❌ | ✅ | ✅ |
| 自动扩缩 | ❌ | ❌ | ✅ HPA |
| 自愈 | ❌ | restart 策略 | ✅ 自动重建 |
| 零停机更新 | 困难 | Compose 重启 | ✅ 滚动更新 |
| 监控 | 手动 | Prometheus+Grafana | 内置 + Prometheus |
| 复杂度 | 低 | 中 | 高 |
10. 完整示例:一键部署全栈
BASH
# ============================================
# Complete walkthrough: Full-stack deployment
# ============================================
# 1. Create .env file (NEVER commit this)
cat > .env << 'EOF'
DB_PASSWORD=secure_db_pass_2024
DB_NAME=ecommerce
REDIS_PASSWORD=secure_redis_pass
MQ_PASSWORD=secure_mq_pass
GRAFANA_PASSWORD=admin123
EOF
# 2. Build and start all services
docker compose -f docker-compose.prod.yml up -d --build
# 3. Wait for services to initialize
sleep 30
# 4. Verify all services
docker compose -f docker-compose.prod.yml ps
echo "=== Health Checks ==="
docker compose -f docker-compose.prod.yml ps --format "table {{.Name}}\t{{.Status}}"
# 5. Test the API
curl -s http://localhost/api/health
# 6. Check database connectivity
docker compose -f docker-compose.prod.yml exec postgres pg_isready -U appuser
# 7. Access monitoring
echo "Grafana: http://localhost:3000 (admin/${GRAFANA_PASSWORD})"
echo "RabbitMQ: http://localhost:15672 (guest/${MQ_PASSWORD})"
echo "Prometheus: http://localhost:9090"
# 8. View aggregated logs
docker compose -f docker-compose.prod.yml logs --tail 50 api
# 9. Scale API if needed
docker compose -f docker-compose.prod.yml up -d --scale api=5
# 10. Clean up
docker compose -f docker-compose.prod.yml down
❓ 常见问题
Q 微服务比单体复杂多少?
A 运维复杂度显著增加——网络配置、服务发现、日志聚合、分布式追踪都是新挑战。但收益是:独立部署、独立扩缩、故障隔离。建议:小团队(<5 人)用模块化单体,大团队用微服务。不要为了微服务而微服务。
Q CI/CD 中怎么做数据库迁移?
A 在部署步骤前添加迁移步骤:① 构建迁移镜像;②
docker run --rm migrate:latest alembic upgrade head;③ 部署新版本。关键:迁移必须向后兼容——新代码必须同时支持旧表和新表结构。Q 多服务如何统一日志?
A 三种方案:① ELK Stack(Elasticsearch + Logstash + Kibana)——企业标准;② Loki + Grafana(轻量,云原生推荐);③ 云服务商日志服务(AWS CloudWatch / 阿里云 SLS)。所有容器 stdout → 采集器 → 集中存储 → 搜索面板。
Q 生产环境怎么配置 HTTPS?
A 在 Nginx 容器中配置 TLS:① Let's Encrypt 免费证书 + certbot 自动续期;② 反向代理模式:Nginx 处理 TLS,内部通信 HTTP;③ 云服务商的负载均衡器处理 TLS(ALB/SLB),容器不需要证书。
Q 怎么监控整个微服务栈的健康状态?
A Prometheus + Grafana 黄金组合:① Prometheus 采集各服务的 /metrics 端点;② Grafana 展示仪表盘 + 告警规则;③ 关键指标:API 延迟(P50/P95/P99)、错误率、CPU/内存、数据库连接数。先监控后优化。
📖 小节
- 全栈微服务 = Frontend + API + DB + Cache + MQ + Monitoring + CI/CD
- 前端多阶段:Node 构建 → Nginx 运行,镜像从 1 GB → 25 MB
- 后端多阶段:Go 编译 → Alpine 运行,镜像从 780 MB → 15 MB
- Compose 编排:网络隔离(db-net internal)+ 健康检查 + 资源限制 + 日志轮转
- CI/CD:push → build → push → SSH deploy,全自动化零人工
- Prometheus + Grafana:指标采集 + 可视化 + 告警,运维必备
📝 作业
- 基础题(难度⭐):设计一个博客系统的微服务架构图(Nginx + API + DB + Cache),列出每个服务的镜像和端口。
- 进阶题(难度⭐⭐):用 Docker 全栈技术部署该架构,编写 docker-compose.prod.yml 并成功启动。
- 挑战题(难度⭐⭐⭐):配置 Prometheus + Grafana 监控面板,添加 API 延迟和错误率的仪表盘,设置邮件告警规则。