SadServers 是一个在线平台,提供真实 Linux 服务器环境,用于 Linux 和 DevOps 故障排除的 CTF(Capture The Flag)挑战。用户通过浏览器 SSH 访问临时服务器,诊断问题如 Docker 容器启动失败、Nginx 配置错误或数据库复制中断。每个挑战有明确描述、测试命令和时限(如 15-30 分钟),成功后自动验证。
但在线平台受限于免费配额和网络,工程师希望本地复现这些挑战,用于面试准备、团队训练或多日渐进式学习。本文聚焦单一技术点:用 Docker Compose 创建可复现、多日系统管理 CTF 环境。Compose 通过 docker-compose.yml 定义多容器服务、网络、卷,实现隔离、可扩展谜题,支持自动化评分,模拟 SadServers 的“真实基础设施”实践。
为什么选择 Docker Compose?
传统 CTF 多为单机脚本或 VM 镜像,难以复现复杂 infra(如 Docker + systemd + web 服务)。Docker Compose 优势在于:
- 可复现性:版本控制 yml 文件,一键
docker compose up 重建环境。参数化 volumes 和环境变量,支持分支演化谜题。
- 隔离性:自定义网络(bridge/overlay),服务间通信受控,避免宿主机污染。每个挑战独立 project_name,避免容器冲突。
- 渐进式谜题:多日挑战从简单(如容器不启动)到复杂(如 HAProxy 负载均衡 + Nginx),用 depends_on 控制启动顺序,volumes 持久故障状态。
- 自动化评分:Compose 集成健康检查(healthcheck),或 agent 容器运行 check.sh 脚本,模拟 SadServers 的“Check My Solution”。
- 资源效率:nano 实例模拟,limits/cpus/reservations 限 CPU/内存,防 OOM 或 CPU 垄断。
SadServers 场景如“Salta”(Docker 容器不启动)、“Tarifa”(docker-compose.yml 中 HAProxy + 双 Nginx 负载不均)完美契合 Compose。
最小化示例:复现“Salta”挑战
SadServers “Salta”:Node.js app 在 /home/admin/app,无法 docker run 暴露 :8888,返回“Hello World!”。
用 Compose 复现:
version: '3.8'
services:
app:
build: ./app
ports:
- "8888:3000"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 10s
timeout: 5s
retries: 3
deploy:
resources:
limits:
cpus: '0.5'
memory: 128M
Dockerfile 示例(app/):
FROM node:20-alpine
WORKDIR /app
COPY . .
EXPOSE 3000
CMD ["node", "server.js"] # server.js: http.createServer((req,res)=>res.end('Hello World!'))
故障注入:故意错 ports 或 build context。学员诊断 docker compose logs app,修复 yml 后 up --build,curl localhost:8888 验证。
评分:健康检查失败时重试,成功输出“Check passed”。
构建多日渐进挑战:Tarifa 示例扩展
SadServers “Tarifa”:docker-compose.yml 中 HAProxy (:5000) 前置双 Nginx,未负载均衡。
扩展为 3 日挑战:
Day 1:基础启动,Nginx 返回“hello from nginx_0/1”。
services:
haproxy:
image: haproxy:2.8
ports: ["5000:5000"]
volumes: ['./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro']
depends_on: [nginx0, nginx1]
nginx0:
image: nginx:alpine
networks:
- backend
nginx1:
image: nginx:alpine
networks:
- backend
networks:
backend:
haproxy.cfg 故障:错 backend server 地址。学员修复 cfg,compose up,多次 curl :5000 见轮询。
Day 2:加卷持久日志,注入磁盘满(volume: ./logs:/var/log/nginx),诊断 df -h,清理或 quota。
volumes:
logs:
driver: local
Day 3:网络隔离谜题,Nginx 只听 backend 网,HAProxy 服务器行错 IP。加 Prometheus 监控(服务发现)。
持久:named volumes 存故障状态,多日不丢(如数据库 WAL 未 sync)。
自动化评分与监控
SadServers 用 agent/check.sh 验证(如 curl 返回预期)。
Compose 中:
- 专用 grader 服务:
grader:
image: alpine
command: sh /check.sh
volumes: ['./check.sh:/check.sh:ro']
depends_on: [app]
check.sh:
#!/bin/sh
if curl -f localhost:8888 | grep -q "Hello World!"; then
echo "✓ Solved!"
else
echo "✗ Failed"
exit 1
fi
docker compose run --rm grader 评分。
- 参数化:.env 文件设 DIFFICULTY=hard,动态故障(如 redis 密码错)。
- 监控:Prometheus + Grafana 服务,暴露 /metrics,学员诊断 scrape 失败(SadServers “Warsaw”)。
阈值:deploy.resources 限资源,防滥用。
最佳实践与清单
- 安全性:network_mode: "none" 隔离,read-only volumes,user: 1000:1000 非 root。
- 回滚:
compose down -v 清卷,git 版本 yml。
- 多日参数:
| 参数 |
值 |
作用 |
| COMPOSE_PROJECT_NAME |
ctf-day${DAY} |
隔离项目 |
| PUID/PGID |
1000:1000 |
用户映射 |
| DEBUG |
true |
日志 verbosity |
- 扩展:Kubernetes Playground(SadServers 支持),Compose 到 k8s yaml 转换。
- 风险:卷泄露敏感数据,用 tmpfs 内存卷;CPU 限防 DoS。
示例仓库:假设 GitHub sadservers-compose-ctf。
来源: