docs: add Docker Compose deployment and README

Add a single-service docker-compose setup with bind-mounted config /
templates / apps / playbooks / data so users can iterate on inventory and
intents without rebuilding the image. Dockerfile uses python:3.12-slim
with tini for clean signal handling, and ships openssh-client for in-
container troubleshooting. Health check hits the /health endpoint.

README documents project background, the L1-L5 architecture, both local
and Docker deployment paths, configuration keys, intent template
extension, and the safety model.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 11:39:30 +09:00
parent dc2d2acc82
commit 36fce94692
5 changed files with 429 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
# VCS / 编辑器 / 工具
.git/
.gitignore
.gitattributes
.vscode/
.idea/
.claude/
.DS_Store
Thumbs.db
# Python 缓存
__pycache__/
*.py[cod]
*.egg-info/
.venv/
venv/
.pytest_cache/
.ruff_cache/
.mypy_cache/
# 本地数据 / 密钥
data/
*.db
*.sqlite*
.env
.env.local
config/inventory.yaml
# 文档(保留 README 以便容器内可见,但构建时不需要)
*.md
# 测试 & CI
tests/
.github/
+3
View File
@@ -25,6 +25,9 @@ data/
audit.log
logs/
# Docker
docker-compose.override.yml
# Inventory secrets (only ship the example)
config/inventory.yaml
!config/inventory.example.yaml
+43
View File
@@ -0,0 +1,43 @@
# syntax=docker/dockerfile:1.6
FROM python:3.12-slim AS base
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /app
# 基础系统依赖:
# - gcc/libffi-dev : 编译某些 wheel(如 cryptography/asyncssh 依赖)
# - openssh-client : 提供 ssh 客户端工具,便于排障
# - tini : 优雅处理信号
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libffi-dev \
openssh-client \
tini \
&& rm -rf /var/lib/apt/lists/*
# 先安装依赖(pyproject + src 一起,以便 setuptools 发现包)
COPY pyproject.toml ./
COPY src/ ./src/
RUN pip install .
# 复制运行时资源(这些目录在 compose 里默认会被卷挂载覆盖)
COPY templates/ ./templates/
COPY config/ ./config/
COPY apps/ ./apps/
COPY playbooks/ ./playbooks/
# data/ 用于审计日志 + SQLite,运行时挂载卷
RUN mkdir -p /app/data
# 默认监听所有接口(容器内)
ENV OPS_HOST=0.0.0.0 \
OPS_PORT=8000
EXPOSE 8000
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["ops", "serve"]
+300
View File
@@ -0,0 +1,300 @@
# AI App Ops Tools
> 面向运维工程师的 **AI 驱动自然语言运维终端** —— 用一句话统一操作 Linux、Windows 等异构主机。
[![Python](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
## 项目背景
日常运维中我们经常面对:
- **多种操作系统**Windows / Ubuntu / CentOS / Debian / macOS …
- **不同的命令体系**`df -h` vs `Get-PSDrive``systemctl restart` vs `Restart-Service``apt` vs `yum` vs `dnf`
- **重复劳动**:日常巡检、批量诊断、应用部署,过程难以沉淀
本项目尝试用 **AI + 跨 OS 意图模板** 这一组合,把"记住命令"的负担交给工具,让运维人员只关心"做什么",并把每一次操作沉淀为可复用的知识资产。
## 核心特性
- 🗣️ **自然语言操作**:基于 Claude Function Calling,用一句话完成跨主机操作
- 🛡️ **三级风险闸门**`READ` 自动 / `WRITE` 需确认 / `DESTRUCTIVE` 默认禁用
- 🌐 **统一异构 OS**:同一意图(如 `check_disk_usage`)在 Linux/Windows/macOS 下自动路由到不同实现
- 📜 **意图模板库**:所有命令以 YAML 形式版本化管理,是项目的核心知识资产
- 🔌 **多种连接器**SSHLinux/Unix)、WinRMWindows)、Local(本机测试)
- 📊 **全量审计日志**:谁、何时、用什么自然语言、对哪些主机执行了什么命令
- 🧱 **分层架构**:从单条命令到应用部署,逐层演进无需重构
## 架构分层
```
┌─────────────────────────────────────────────────────┐
│ L5 策略层 │ 灰度策略、变更窗口、AI 风险预判 │
├─────────────────────────────────────────────────────┤
│ L4 编排层 │ 多主机有序执行、依赖、健康检查门控 │
├─────────────────────────────────────────────────────┤
│ L3 应用层 │ 部署 / 升级 / 回滚 = 业务原子操作 │
├─────────────────────────────────────────────────────┤
│ L2 操作层 │ 装包 / 改配置 / 重启服务 / 拷文件 │
├─────────────────────────────────────────────────────┤
│ L1 命令层 │ df / ps / 跨 OS 命令模板 ← 当前阶段 │
└─────────────────────────────────────────────────────┘
```
数据流:
```
用户 NL 请求
AI 编排 (Claude + Function Calling,只能调用已注册的意图)
意图模板库 (按主机 OS 路由到对应实现)
风险闸门 (READ/WRITE/DESTRUCTIVE)
连接器 (SSH / WinRM / Local)
审计日志 + 结果归一化 + AI 摘要
```
## 项目结构
```
ai-app-ops-tools/
├── config/
│ ├── inventory.example.yaml # 主机清单模板
│ └── settings.yaml # 运行时策略(含 destructive 关键字)
├── templates/ # 意图模板库 ★ 核心知识资产
│ ├── disk.yaml
│ ├── system.yaml
│ └── service.yaml
├── apps/ # 预留:L3 应用台账
├── playbooks/ # 预留:L3-L4 部署剧本
├── src/ops_tools/
│ ├── config.py # Pydantic Settings
│ ├── inventory/ # 主机清单 + facts 探测
│ ├── intents/ # 意图模板加载
│ ├── connectors/ # local / ssh / winrm
│ ├── executor/ # 风险闸门 + 执行 + 审计
│ ├── audit/ # SQLite 审计日志
│ ├── ai/ # Claude 编排(Function Calling
│ ├── api/ # HTTP API
│ ├── main.py # FastAPI 入口
│ └── cli.py # Typer CLI
├── tests/
├── Dockerfile
├── docker-compose.yml
├── pyproject.toml
└── .env.example
```
## 快速开始
### 方式一:本地开发
#### 1. 准备 Python 环境(需要 Python ≥ 3.11
```bash
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
```
#### 2. 准备配置
```bash
cp .env.example .env
# 编辑 .env,至少填入 ANTHROPIC_API_KEY
cp config/inventory.example.yaml config/inventory.yaml
# 编辑 inventory.yaml 加入你的真实主机
```
#### 3. 体验 CLI
```bash
# 列出主机
ops hosts
# 列出已注册的意图
ops intents
# 在 localhost 上执行查磁盘
ops run check_disk_usage localhost
# 写入类意图会被拦截,附命令预览
ops run restart_service localhost --params '{"service": "Spooler"}'
# 加 --confirm 才会真正执行
ops run restart_service localhost --params '{"service": "Spooler"}' --confirm
# 自然语言对话(需 ANTHROPIC_API_KEY
ops chat "看一下 localhost 的磁盘和内存"
```
#### 4. 启动 HTTP 服务
```bash
ops serve
# 访问 http://127.0.0.1:8000/docs 查看 OpenAPI 文档
```
---
### 方式二:Docker Compose 部署(推荐用于服务器侧)
#### 1. 准备配置文件
```bash
cp .env.example .env
cp config/inventory.example.yaml config/inventory.yaml
# 按需编辑两个文件
```
#### 2. 构建 + 启动
```bash
docker compose up -d --build
```
容器启动后会自动:
- 监听 `0.0.0.0:8000`(宿主机端口可在 `.env` 中通过 `OPS_PORT` 覆盖)
-`./config /templates /apps /playbooks /data` 以 bind mount 挂载进容器,**编辑这些文件无需重建镜像**
- 把审计 + SQLite 数据持久化到宿主机的 `./data` 目录
- 自带健康检查(`/health` 端点)
#### 3. 验证服务
```bash
# 健康检查
curl http://127.0.0.1:8000/health
# 列出主机
curl http://127.0.0.1:8000/api/v1/hosts | jq
# 列出意图
curl http://127.0.0.1:8000/api/v1/intents | jq
# 直接执行意图
curl -X POST http://127.0.0.1:8000/api/v1/run \
-H 'Content-Type: application/json' \
-d '{"intent":"check_disk_usage","hosts":["localhost"]}'
# 自然语言对话
curl -X POST http://127.0.0.1:8000/api/v1/chat \
-H 'Content-Type: application/json' \
-d '{"message":"看一下生产环境的磁盘使用率"}'
```
#### 4. 进入容器执行 CLI
```bash
docker compose exec ops ops hosts
docker compose exec ops ops intents
docker compose exec ops ops chat "重启 nginx 服务"
```
#### 5. 常用运维命令
```bash
docker compose logs -f ops # 看日志
docker compose restart ops # 重启服务
docker compose down # 停止
docker compose up -d --build # 改代码后重建
```
#### 关于 SSH 密钥
如果要从容器内部 SSH 到目标 Linux 主机,需要把宿主机的 SSH 密钥挂进容器。在 `docker-compose.yml` 中解开对应的 `volumes` 行:
```yaml
# Linux / macOS
- ${HOME}/.ssh:/root/.ssh:ro
# Windows (示例,按你的实际路径)
- C:/Users/<your-name>/.ssh:/root/.ssh:ro
```
> ⚠️ 生产环境建议使用 SSH agent forwarding、Vault、跳板机等更安全的方案,而不是直接挂载本地密钥。
#### 升级到 PostgreSQL(可选)
SQLite 适合单机 MVP;如果要多实例部署或大量审计日志,把 `docker-compose.yml``db` 服务的注释解开,并修改 `OPS_DB_URL`
```env
OPS_DB_URL=postgresql+asyncpg://ops:changeme@db:5432/ops
```
并在 `pyproject.toml` 中加入 `asyncpg`
## 配置说明
### `.env` 关键项
| 变量 | 说明 | 默认 |
|---|---|---|
| `ANTHROPIC_API_KEY` | Anthropic API Keychat 功能必需) | 空 |
| `OPS_MODEL_MAIN` | 主模型 | `claude-sonnet-4-6` |
| `OPS_MODEL_FAST` | 轻量任务模型 | `claude-haiku-4-5-20251001` |
| `OPS_DB_URL` | 审计数据库 URL | `sqlite+aiosqlite:///./data/ops.db` |
| `OPS_AUTO_EXECUTE_WRITE` | WRITE 类是否自动执行 | `false` |
| `OPS_ALLOW_DESTRUCTIVE` | 是否允许 DESTRUCTIVE | `false` |
| `OPS_HOST` / `OPS_PORT` | API 监听地址 | `127.0.0.1` / `8000` |
### `config/inventory.yaml` 主机清单
支持 SSH(密钥 / 密码)、WinRM、Local 三种连接方式,详细字段见 `inventory.example.yaml`。密码字段支持 `${ENV_VAR}` 形式从环境变量插值,避免明文落盘。
### `config/settings.yaml` 运行时策略
- 默认超时
- SSH / WinRM 传输参数
- 风险策略(如自动升级为 DESTRUCTIVE 的关键字白名单)
## 扩展意图模板(核心知识沉淀)
`templates/` 下新建 YAML 即可。模板示例:
```yaml
intents:
- intent: check_listening_ports
description: 查看本机监听端口
risk_level: READ
params: []
implementations:
linux:
command: "ss -tlnp || netstat -tlnp"
windows:
command: "Get-NetTCPConnection -State Listen | Select-Object LocalAddress,LocalPort,OwningProcess | ConvertTo-Json"
```
**设计原则**
1. **意图名要表达"意图",而不是命令** —— `check_listening_ports` ✅,`run_ss`
2. **风险等级保守标注** —— 不确定就标 `WRITE`,确认行为安全后再降级
3. **参数显式声明** —— 模板里通过 `params` 列出,便于 AI 理解和参数校验
每加一个意图,AI 都能立刻自然语言调用 —— **意图模板库就是你的运维知识图谱**
## 安全模型
| 设计 | 防护目标 |
|---|---|
| LLM 不能生成 shell,只能调用已注册意图 | 防幻觉、防注入 |
| 参数通过 `shlex.quote` 转义 | 命令注入 |
| 三级风险闸门 + 渲染后再分级 | 误操作放大 |
| 全量审计日志(含原始 NL 输入) | 责任追溯 |
| `inventory.yaml` 被 git 忽略 | 凭据泄漏 |
| 密码字段支持 `${ENV_VAR}` 插值 | 明文落盘 |
> ⚠️ 当前版本面向受信任的内部使用场景;如对外暴露 API 必须叠加认证(OIDC / mTLS)和网络隔离。
## 路线图
- [x] **L1 命令层** — 跨 OS 自然语言查询(MVP,当前阶段)
- [ ] **L2 操作层** — 服务启停、装包、改配置(部分已就位)
- [ ] **L3 应用层** — 单应用部署 / 升级 / 回滚(应用台账 + 部署剧本)
- [ ] **L4 编排层** — 灰度、滚动、健康检查门控、多应用依赖
- [ ] **L5 策略层** — 变更窗口、AI 变更风险预判
## License
MIT
+49
View File
@@ -0,0 +1,49 @@
services:
ops:
build:
context: .
dockerfile: Dockerfile
image: ai-app-ops-tools:latest
container_name: ai-app-ops-tools
restart: unless-stopped
ports:
- "${OPS_PORT:-8000}:8000"
env_file:
- .env
environment:
# 容器内固定监听 0.0.0.0;对外端口通过上面的 ports 映射
OPS_HOST: "0.0.0.0"
OPS_PORT: "8000"
# SQLite 数据库路径与卷挂载点一致
OPS_DB_URL: "sqlite+aiosqlite:////app/data/ops.db"
volumes:
# 配置、模板、台账、剧本都用 bind mount,方便不重启即可编辑
- ./config:/app/config
- ./templates:/app/templates
- ./apps:/app/apps
- ./playbooks:/app/playbooks
# 审计日志 + SQLite 持久化
- ./data:/app/data
# SSH 密钥(按需启用;Windows 上路径需自行调整)
# - ${HOME}/.ssh:/root/.ssh:ro
healthcheck:
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)\""]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
# 未来如需切换到 PostgreSQL,可解开下面的注释并修改 OPS_DB_URL
# db:
# image: postgres:16-alpine
# container_name: ai-app-ops-tools-db
# restart: unless-stopped
# environment:
# POSTGRES_USER: ops
# POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme}
# POSTGRES_DB: ops
# volumes:
# - pgdata:/var/lib/postgresql/data
#
# volumes:
# pgdata: