Ansible 好用,但团队规模一上来,谁跑了什么 Playbook、改了哪台机器、上次部署是啥时候——全靠口头交接和
history | grep ansible。AWX(Tower 开源版)太重,光部署就要 K8s + PostgreSQL + Redis。Semaphore 只需要一个二进制 + SQLite,5 分钟就能给 Ansible 加上 Web UI、权限管控、执行历史和 Webhook 触发。
痛点:Ansible 裸跑的 3 个致命问题
团队 5 个人共用一台跳板机跑 Ansible:
- 无审计 — 谁在凌晨 3 点跑了
site.yml把生产数据库配置覆盖了?history被清了,无从追溯 - 无权限隔离 — 实习生和架构师共享同一个 inventory,一个
--limit忘加就是全量推送 - 无调度 — 定时巡检靠 crontab + 脚本,失败了没人知道
AWX 能解决这些,但它自身就是一套分布式系统:PostgreSQL、Redis、3 个容器、K8s Operator。一个管理工具比被管理的服务还复杂,本末倒置。
方案:Semaphore — Ansible 的轻量 Web 控制台
Semaphore(GitHub 10k+ star)是一个开源的 Ansible UI,核心特性:
| 特性 | Semaphore | AWX |
|---|---|---|
| 部署复杂度 | 单二进制 / Docker 单容器 | K8s + PostgreSQL + Redis |
| 资源占用 | 128MB RAM 起 | 4GB RAM 起 |
| 执行历史 | ✅ 完整日志 | ✅ |
| 权限管控 | ✅ 项目级 RBAC | ✅ 更细粒度 |
| Webhook/API 触发 | ✅ | ✅ |
| 定时任务 | ✅ cron 表达式 | ✅ |
| 学习曲线 | 10 分钟上手 | 1-2 天 |
适用场景:中小团队(2-20 人)、不需要多租户、够用就好。
实操:3 步部署 Semaphore
第 1 步:Docker Compose 一键部署
创建 docker-compose.yml:
version: "3.8"
services:
semaphore:
image: semaphoreui/semaphore:v2.10.22
container_name: semaphore
ports:
- "3000:3000"
environment:
SEMAPHORE_DB_DIALECT: bolt # 用 BoltDB,免装数据库
SEMAPHORE_ADMIN_PASSWORD: "YourStr0ngP@ss"
SEMAPHORE_ADMIN_NAME: "admin"
SEMAPHORE_ADMIN_EMAIL: "admin@example.com"
SEMAPHORE_ADMIN: "admin"
SEMAPHORE_ACCESS_KEY_ENCRYPTION: "your-32-char-encryption-key!!" # 必须 32 位
volumes:
- ./data:/var/lib/semaphore
- ./playbooks:/opt/playbooks # 挂载你的 Playbook 仓库
- ~/.ssh:/home/semaphore/.ssh:ro # SSH 密钥(只读)
restart: unless-stopped
启动:
docker compose up -d
# 检查状态
docker logs semaphore | tail -5
# 输出: Listening on 0.0.0.0:3000
浏览器访问 http://<your-ip>:3000,用 admin 账号登录。
第 2 步:配置项目 + Inventory + 密钥
在 Web UI 中按顺序操作:
# 1. 创建 Key Store — 添加 SSH 私钥
# 类型: SSH Key,粘贴你的私钥内容
# 2. 创建 Inventory — 指定主机清单
# 类型: File,路径指向容器内文件 /opt/playbooks/inventory/production.ini
# 或者选 Static,直接粘贴 INI 格式内容:
[webservers]
10.0.1.10 ansible_user=deploy
10.0.1.11 ansible_user=deploy
[dbservers]
10.0.2.20 ansible_user=deploy
# 3. 创建 Repository — 关联 Playbook 来源
# 类型: Local,路径: /opt/playbooks
# 或 Git,填入仓库 URL + Deploy Key
# 4. 创建 Task Template — 定义可执行任务
# Playbook 文件名: deploy-app.yml
# 关联 Inventory + Key + Repository
第 3 步:配置 Webhook 触发 + 定时任务
CI/CD 集成 — GitHub Actions 触发部署:
在 Task Template 设置中开启 Webhook,拿到 URL:
# 在 GitHub Actions workflow 中添加:
- name: Trigger Ansible Deploy
run: |
curl -X POST \
"https://semaphore.example.com/api/project/1/tasks" \
-H "Authorization: Bearer ${{ secrets.SEMAPHORE_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{"template_id": 1}'
定时巡检 — cron 表达式:
在 Task Template 中设置 Schedule:
# 每天早上 8 点执行巡检 Playbook
0 8 * * *
执行历史自动保留,失败会在 UI 标红,支持配置邮件/Telegram 通知。
3 个常见坑
坑 1:SSH 连接超时,容器内无法访问目标机器
# 症状:Task 报 "unreachable"
# 原因:容器网络隔离,无法直达目标 IP
# 解决:使用 host 网络模式
services:
semaphore:
network_mode: host # 直接用宿主机网络
ports: [] # host 模式不需要端口映射
坑 2:Playbook 路径找不到
# 症状:Task 报 "Could not find playbook"
# 原因:Repository 路径和 Template 中 Playbook Filename 不匹配
# 解决:Template 里填的是相对于 Repository 根目录的路径
# 如果 Repo 路径是 /opt/playbooks,Playbook 在 /opt/playbooks/roles/deploy.yml
# 那么 Template 填:roles/deploy.yml
坑 3:升级后数据丢失
# 症状:Docker 重建容器后历史任务全没了
# 原因:BoltDB 文件在容器内,没挂载 volume
# 解决:确保 /var/lib/semaphore 挂载到宿主机
# 生产环境建议切换到 MySQL/PostgreSQL:
SEMAPHORE_DB_DIALECT: mysql
SEMAPHORE_DB_HOST: 127.0.0.1
SEMAPHORE_DB_PORT: 3306
SEMAPHORE_DB_NAME: semaphore
SEMAPHORE_DB_USER: semaphore
SEMAPHORE_DB_PASS: "db-password"
总结
| 维度 | 效果 |
|---|---|
| 部署时间 | 5 分钟(Docker 单容器) |
| 资源开销 | 128MB RAM + 50MB 磁盘 |
| 解决问题 | 审计追溯、权限隔离、定时调度 |
| 适用团队 | 2-20 人中小运维团队 |
Semaphore 不是 AWX 的完全替代——它没有多租户、工作流编排等高级功能。但对于绝大多数中小团队,能看到谁在什么时间跑了什么、能控制谁能跑什么、失败了能收到通知——这三件事就够了。
与其花两天部署 AWX 然后再花一周学它的概念模型,不如 5 分钟起一个 Semaphore,把精力留给真正的自动化逻辑。