# keepd **Repository Path**: opsx-tools/keepd ## Basic Information - **Project Name**: keepd - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-19 - **Last Updated**: 2026-07-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # keepd · 轻量守护进程管理平台 keepd 是一个单机版轻量守护进程管理平台:后端 **Go 1.22 + Gin**,前端 **Vue 3 + Vite + Element Plus**,无需数据库,单配置文件即可运行。它可以托管任意 shell 命令为守护进程,提供类 k8s 的健康检查探针、崩溃自动拉起、进程组级可靠杀停、实时日志与系统进程视图,并内置单 admin 账号的 JWT 认证。 生产构建产物通过 `go:embed` 把前端打进单个二进制 `backend/keepd`,交付物只有一个可执行文件 + 自动生成的 `config.yaml`。 > 目录结构、启动脚本(`run.sh`/`Makefile`/`.gitignore`/`.env.example`)借鉴自同仓库 `opsx-web-lite`。 ## 功能特性 - **守护进程管理**:配置 `command/args/work_dir/env` 启动任意进程;支持启动 / 停止 / 重启 / 编辑 / 删除;崩溃后按 `restart_backoff_seconds` 退避自动拉起,受 `max_restarts` 上限保护。 - **三类健康检查探针(类 k8s)**: - `http`:GET 指定 URL,`expect_status` 匹配即通过(填 0 表示任意 2xx 通过); - `tcp`:`net.DialTimeout` 探测地址端口可连通即通过; - `exec`:执行命令,退出码为 0 即通过。 - 公共参数:`initial_delay_seconds`(首次探测前延迟)、`interval_seconds`(探测间隔)、`timeout_seconds`(单次超时)、`failure_threshold`(连续失败阈值)。**连续失败达阈值即判定假死/异常,自动 kill 整个进程组并用启动命令重新执行**。 - **加锁保护**:同一 daemon 运行时**禁止重复启动**——内存互斥锁 + pidfile 存活检测双重防护;停止/重启时子进程以独立进程组运行(`Setpgid`),通过**负 pid kill 整个进程组**,杜绝孤儿进程残留。 - **日志**:每个 daemon 的 stdout/stderr 捕获到内存环形缓冲(最近 500 行)并落盘 `data/logs/.log`,API/前端支持按 tail 行数拉取。 - **⏱ 统一定时任务调度(v1.1)**:全部健康检查由 `robfig/cron/v3` 驱动的**中央探针调度器**(`scheduler.go`)统一执行——spawn 后按 `initial_delay` 延迟注册 `@every Ns` 定时任务,进程停止/重启即注销,探针慢于间隔时自动跳过重叠执行;不再为每个 daemon 单独开 ticker goroutine。 - **🔍 表单内进程选择(v1.1)**:独立的「系统进程」菜单已移除;在新建/编辑表单「命令」旁一键弹出进程选择器(搜索 + CPU/内存排序),选中自动回填 `command` + `args`。 - **🚀 创建后立即启动(v1.1)**:新建守护进程成功后一键「立即启动」,少一次往返。 - **仪表盘聚合**:托管总数 / 运行中 / 异常 / 已停止 / 累计重启 + 系统 CPU、内存、主机运行时长,3 秒轮询。 - **认证与安全**:单 admin 账号,JWT(HS256)认证;修改密码需校验旧密码,bcrypt 重新哈希写回 `config.yaml`;除登录外全部 API 需 `Authorization: Bearer `。 - **🧪 探针「测试」按钮**:新建/编辑表单里填完健康检查配置可**保存前**点一下「测试探针」,立即执行一次 http/tcp/exec 探针并返回成功/失败 + 耗时,避免配错要等 `failure_threshold` 才发现。 - **🔍 从运行进程选择**:表单「命令」旁一键弹出当前系统进程列表(支持搜索),选中后自动回填 `command` + `args`,免手抄命令行。 - **📦 守护进程导入/导出**:守护进程页一键导出 `daemons.json` / 从本地 JSON 导入(按名称去重合并),换机器秒迁配置。 - **⚙️ 配置 flag/env 覆盖**:支持 `--port`/`--config`/`--data-dir` flag 与 `KEEPD_PORT`/`KEEPD_CONFIG`/`KEEPD_DATA_DIR` env 覆盖 `config.yaml`,部署无需改文件。 - **🐧 单 Linux 二进制**:`./build.sh linux` 交叉编译 `CGO_ENABLED=0` 的 Linux 单文件(前端已 embed),scp 到服务器即可跑,零外部依赖。 ## 快速开始 ### 环境要求 - Go 1.22+ - Node.js 20+ / npm(构建前端时需要) ### 方式一:开发模式(前后端分离) ```bash # 安装依赖 make install # 或: cd backend && go mod download && cd ../frontend && npm install # 一键启动前后端(后端 :9002 / 前端 :5182) ./run.sh start # 等价于 make dev ./run.sh status # 查看状态 ./run.sh stop # 停止 ``` 访问地址: - 前端:`http://localhost:5182` - 后端:`http://localhost:9002` 默认账号:`admin / admin123`(首次登录后请立即修改密码)。 ### 方式二:生产单文件(前端 embed 进二进制) ```bash ./build.sh # 构建前端 → 同步到 backend/internal_web/dist → go build(当前平台) cd backend && ./keepd # 运行单二进制,监听 :9002,前端已 embed ``` 打开浏览器访问 `http://localhost:9002/` 即可(深色侧边栏 + 仪表盘 / 守护进程两个页面;系统进程能力已内聚到守护进程表单的「从进程选择」)。 ### 方式三:Linux 服务器部署(单二进制) ```bash ./build.sh linux # 交叉编译 → backend/keepd-linux-amd64(CGO_ENABLED=0,零依赖) # 或 arm64:./build.sh linux arm64 scp backend/keepd-linux-amd64 user@server:~/keepd ssh user@server 'chmod +x keepd && ./keepd --port 9002' ``` 运行时可用 flag/env 覆盖 `config.yaml`(优先级:flag > env > config.yaml): ```bash ./keepd --port 9100 --data-dir /var/lib/keepd # flag 覆盖 KEEPD_PORT=9100 ./keepd # env 覆盖 ./keepd --config /etc/keepd/config.yaml # 指定配置路径 ``` ### 默认账号 | 用户名 | 密码 | |---|---| | `admin` | `admin123` | 删除 `backend/config.yaml` 后重启会重新生成(密码重置为 `admin123`,JWT 密钥重新随机,旧 token 全部失效)。 ## 常用命令 ```bash make help # 查看所有命令 make install # 安装前后端依赖 make dev # 启动开发环境(前后端) make build # 生产构建(单二进制) make status # 查看服务状态 make stop # 停止服务 make restart # 重启服务 make logs # 查看实时日志 make clean # 清理构建产物 ``` ## 配置说明 ### 后端 `backend/config.yaml`(首次启动自动生成) ```yaml server: port: 9002 # HTTP 监听端口 admin: username: admin # 管理员用户名 password_hash: $2a$10$... # 密码 bcrypt 哈希(修改密码时自动重写) auth: jwt_secret: <64位hex> # 随机 32 字节 hex,JWT HS256 签名密钥 token_ttl_hours: 24 # token 有效期(小时) ``` ### 环境变量 见 `.env.example`。`PORT`(默认 9002)、`GIN_MODE`(debug/release)由 `run.sh` 注入。 ## API 摘要 除 `/api/login` 外,所有接口均需请求头 `Authorization: Bearer `。字段全部为 snake_case。详细契约见 [docs/SPEC.md](docs/SPEC.md)。 | Method | Path | 说明 | |---|---|---| | POST | `/api/login` | 登录,body `{username, password}` → `{token}` | | POST | `/api/admin/password` | 修改密码 `{old_password, new_password}` → `{message}` | | GET | `/api/overview` | 仪表盘聚合 | | GET | `/api/system/processes` | 系统进程列表 | | POST | `/api/probe/test` | 探针测试(保存前验证)`{health_check}` → `{success, message, elapsed_ms}` | | GET | `/api/daemons/export` | 导出全部守护进程定义(attachment `daemons.json`) | | POST | `/api/daemons/import` | 导入守护进程 `{daemons:[...]}` → `{imported, skipped}`(按 name 去重) | | GET | `/api/daemons` | daemon 列表(定义 + 实时 `status`) | | POST | `/api/daemons` | 创建 daemon | | PUT | `/api/daemons/:id` | 更新定义(运行中允许改,下次重启生效) | | DELETE | `/api/daemons/:id` | 先 stop 再删除,并清理 pidfile | | POST | `/api/daemons/:id/start` | 启动(已运行则 400,加锁保护) | | POST | `/api/daemons/:id/stop` | 停止(kill 整个进程组,清 pidfile) | | POST | `/api/daemons/:id/restart` | 重启 | | GET | `/api/daemons/:id/status` | 实时状态 | | GET | `/api/daemons/:id/logs?tail=200` | 日志 tail `{lines: [...]}` | `state` 取值:`stopped / starting / running / unhealthy`。 ## 目录结构 ``` keepd/ ├── backend/ # Go 1.22 + Gin 后端 │ ├── main.go # 入口:加载配置、初始化 store/supervisor、Gin 路由、embed 前端、优雅退出 │ ├── config.go # config.yaml 加载/首次生成(端口 9002、随机 JWT 密钥、admin123 bcrypt)、改密写回 │ ├── store.go # Daemon 定义与 data/daemons.json 持久化(RWMutex) │ ├── auth.go # 登录、JWT 中间件、修改密码 │ ├── supervisor.go # 守护进程状态机:spawn/进程组/退避重启/pidfile/日志环形缓冲 │ ├── scheduler.go # 中央探针调度器(robfig/cron 统一定时任务,initial_delay/interval/防重入) │ ├── probe.go # http / tcp / exec 三类健康检查 │ ├── sysproc.go # gopsutil 系统进程枚举 │ ├── handlers.go # CRUD、overview 聚合与路由注册 │ ├── internal_web/dist/ # build.sh 拷入的前端构建产物(go:embed,gitignore) │ ├── go.mod / go.sum # module keepd │ └── logs/ # 运行期日志(gitignore) ├── frontend/ # Vue3 + Vite + Element Plus 前端 │ ├── index.html vite.config.js package.json │ ├── public/favicon.svg │ └── src/ │ ├── api/ # axios 封装(自动带 token,401 跳登录,token key keepd_token) │ ├── router/ # vue-router(登录守卫) │ ├── store/ # pinia │ ├── views/ # Login / Layout / Dashboard / Daemons │ └── components/ # DaemonFormDrawer(含进程选择器+探针测试) / LogDrawer / PasswordDialog ├── run.sh # 一键启动脚本(start/stop/restart/status/backend/frontend/help) ├── build.sh # 生产构建:前端 embed 进 backend/keepd 单二进制 ├── Makefile # 常用命令快捷方式 ├── .env.example # 环境变量模板 ├── .gitignore ├── README.md └── docs/ # SPEC.md(接口契约)、plan.md(设计记录) ``` ## 运行数据与清理 运行期自动生成(均已 gitignore,删除即可重置): - `backend/config.yaml` — 配置与账号 - `backend/data/daemons.json` — daemon 定义 - `backend/data/run/*.pid` — pidfile - `backend/data/logs/*.log` — daemon 日志 - `backend/logs/server.log` — 后端服务日志 - `frontend/logs/dev.log` — 前端开发日志