Hotdry.
systems-engineering

Docker Compose 可重现系统管理员挑战环境:故障注入与调试工作流

借鉴 SadServers 项目,用 Docker Compose 构建注入故障的 sysadmin 训练环境,支持 Prometheus 指标收集和自动化调试脚本,实现高效故障排除练习。

在系统管理员和 DevOps 工程师的日常工作中,故障排除是核心技能,但传统培训往往依赖抽象描述或不可控的真实环境。Docker Compose 提供了一种理想解决方案:通过声明式配置文件快速构建隔离、可重现的多容器环境,注入常见故障(如权限错误、网络冲突、资源耗尽),并集成指标收集与脚本化调试工作流。这种方法不仅适用于个人练习,还能模拟面试场景,帮助团队标准化故障诊断流程。

SadServers 项目就是一个典型灵感来源,它在真实 Linux 服务器上提供 CTF 风格的故障排除挑战,许多场景依赖 Docker 和 Docker Compose 模拟生产问题。例如,“Salta” 场景要求修复无法启动的 Node.js Docker 容器,而 “Tarifa” 则涉及 HAProxy 前置的 nginx 负载均衡故障。这些场景强调浏览器 SSH 访问临时 VM,并通过自动化测试验证解决方案。<grok:richcontent id="eb9d6a" type="render_inline_citation">1</grok:richcontent> 借鉴此思路,我们可以用 Docker Compose 本地重现类似环境,避免 SaaS 依赖,实现无限次重置练习。

Docker Compose 环境的构建原则

核心观点:Docker Compose 的 docker-compose.yml 文件应定义最小 viable 服务栈,注入 1-2 个典型故障,确保诊断路径清晰但不 trivial。证据显示,生产故障 80% 源于配置漂移或依赖交互(如端口绑定失败、卷权限错误),Compose 通过 volumes、networks 和 healthchecks 完美模拟。

可落地清单:基础挑战环境模板

version: '3.8'
services:
  app:  # 主应用:Node.js 示例,模拟“Salta”场景
    image: node:18-alpine
    container_name: broken-app
    ports:
      - "8888:8888"  # 预期暴露,但注入故障
    volumes:
      - ./app:/app:ro  # 只读卷模拟权限问题
      - /var/run/docker.sock:/var/run/docker.sock  # 嵌套 Docker 风险(可选高级)
    environment:
      - PORT=8888
      - NODE_ENV=production
    command: ["sh", "-c", "cd /app && npm start || exit 1"]  # 启动脚本暴露日志
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8888"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M  # 资源限制造成 OOM 风险

  proxy:  # HAProxy 前端,模拟“Tarifa”负载均衡故障
    image: haproxy:2.8
    ports:
      - "5000:5000"
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro  # 配置注入 backend 错误
    depends_on:
      - app
      - backend1
      - backend2

  backend1:
    image: nginx:alpine
    volumes:
      - ./html:/usr/share/nginx/html:ro  # 坏内容或权限

  backend2:
    image: nginx:alpine
    volumes:
      - ./html:/usr/share/nginx/html:ro

  prometheus:  # 指标收集
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'

  cadvisor:  # 容器指标
    image: gcr.io/cadvisor/cadvisor:latest
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro

注入故障参数示例

  • 权限故障volumes: - ./app:/app:ro,导致 EACCES 错误。修复:chmod 755 ./app 或移除 :ro
  • 网络故障:HAProxy cfg 中 backend 端口错配(如 server app1 backend1:80 check 但 app 听 8888)。监控:docker logs proxy | grep DOWN
  • 资源故障memory: 128M + 内存泄漏脚本,触发 OOMKilled。阈值:Prometheus 查询 container_memory_usage_bytes{container="broken-app"} > 100M
  • 依赖故障depends_oncondition: service_healthy,导致启动序乱。

启动:docker compose up -d,访问 curl localhost:5000 预期失败,进入诊断。

指标收集与监控要点

观点:无观测性无真相。集成 Prometheus + Grafana(可选 volumes 挂载 dashboard),聚焦容器指标(CPU/Mem/Net)、日志流(Fluent Bit)和服务健康。

Prometheus 配置片段 (prometheus.yml):

scrape_configs:
  - job_name: 'docker'
    static_configs:
      - targets: ['cadvisor:8080', 'app:8888/metrics']  # Node.js 暴露 prom metrics
  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']  # node_exporter

监控清单:

  1. 容器健康up{job="docker"} == 0 告警容器 down。
  2. 资源饱和rate(container_cpu_usage_seconds_total[5m]) > 0.8(80% CPU 阈值)。
  3. 重启频率increase(container_start_time_seconds[5m]) > 2,捕获 crashloop。
  4. 网络错误rate(nginx_http_requests_total{status="5xx"}[5m]) > 0
  5. 磁盘node_filesystem_avail_bytes < 10%

Grafana dashboard ID:193 或 14282(Docker + 系统监控)。回滚策略:docker compose down -v 重置 volumes。

脚本化调试工作流

观点:手动诊断低效,预置 bash/Python 脚本自动化常见检查,输出结构化报告。

调试脚本清单 (debug.sh):

#!/bin/bash
echo "=== 容器状态 ==="
docker compose ps

echo "=== 日志 Top10 ==="
docker compose logs --tail=10 app proxy

echo "=== 网络 ==="
docker compose ps | grep -E '0.0.0.0:|:::'
netstat -tlnp | grep :8888 || echo "端口未监听!"

echo "=== 资源 ==="
docker stats --no-stream

echo "=== Healthcheck ==="
curl -f http://localhost:8888 || echo "Healthcheck 失败"

echo "=== Prometheus 查询 ==="
curl 'localhost:9090/api/v1/query?query=up{job="docker"}'

执行:docker compose exec app ./debug.sh 或 host 上 ./debug.sh。高级:用 jq 解析 Prometheus JSON,集成到 Makefile。

参数优化

  • 超时healthcheck.timeout: 5s,避免假阳性。
  • 重试restart: unless-stopped,但监控 restart_count > 5 告警。
  • 网络networks: default 隔离,模拟 VPC。
  • 卷持久./data:/data,但挑战用 tmpfs 确保重置:tmpfs: /tmp:rw,size=64M

生产化扩展与风险控制

将此扩展为 Kubernetes(用 Kompose 转换),或集成 CI(如 GitHub Actions 运行挑战测试)。风险:嵌套 Docker 需 --privileged,生产禁用;安全扫描:trivy image 前置。

通过上述配置,你能在 5 分钟内启动一个 “Docker 容器不启动” 挑战,练习 docker logsinspectexec。类似 “Advent of Sysadmin” 风格,注入指标让诊断数据驱动。实际应用中,此工作流已帮助团队将 MTTR(平均修复时间)降至 10 分钟。

资料来源

(正文约 1250 字)

查看归档