基于 KeePass 凭据托管的 Nginx 负载均衡无感滚动部署工具。
Dockerless(零容器):不依赖 Docker、K8s 或任何容器运行时。直接在宿主机上操作——jar 服务走进程启停、static 资源走目录覆盖、流量切换用 sed 注释 Nginx 的 server 行 + nginx -s reload。目标机上除了要发布的程序本身,无需安装任何额外中间件。
一句话:把「拉代码 → 打包 → 备份 → 逐台上传 → Nginx 摘流量 → 停服替换 → 健康检查 → Nginx 恢复流量」这套上线流程,做成一个可重复、可回滚、fail-fast、且完全不需要容器的命令行 / 桌面 GUI 工具。
- Dockerless(零容器,零中间件):目标机无需安装 Docker / 容器运行时 / 任何 Agent。发布即直接操作宿主机进程与文件,流量切换靠
sed改 Nginx 配置。现有裸金属 / 虚拟机环境开箱即用,不侵入既有部署形态。 - 凭据零落地:SSH 主机密码、Nginx 主机密码统一存进 KeePass 数据库(
.kdbx),运行时不写明文到配置文件;支持环境变量 → 配置文件 → keyfile → 交互输入四级回退。 - 无感滚动:逐台发布,任意时刻最多一台离线;发布前 Nginx 摘节点流量、发布后恢复,业务无感知。
- 多种认证:主机与 Nginx 支持
keepass(KeePass 凭据引用)或manual(配置文件内明文用户名/密码)两种auth_mode。 - 两类产物:
jar(Java 服务,停服替换后重启)与static(前端静态资源,上传解压覆盖站点目录,无需重启)。 - 一键回滚:基于每次部署在远程
backup_dir落地的带时间戳备份({time_dir}/bak/)原样回滚,回滚复用同一套滚动流程。 - 本地打包:按应用维度的
compile_dir / fetch_cmd / package_cmd / target_dir在本地完成拉取与构建。 - 断点续发:
resume仅对上一次失败、且已摘流量未恢复的节点继续发布。 - 双形态入口:纯命令行
keeploy+ 桌面 GUI(Tkinter 纯客户端,无 Web 服务,支持深/浅色主题)。 - 可观测:本地 SQLite 记录每次部署/回滚历史,支持
status查询与演练(--dry-run)。
滚动发布(每台机器依次执行,保证任意时刻只有一台离线):
- 本地打包 + 上传新包(此阶段不影响线上)
- Nginx 注释该节点的
server行 →nginx -t→nginx -s reload - 等待存量连接处理完(drain)
- 停服 → 替换包 → 启服
- 健康检查轮询(未配置
health_check时降级为固定等待) - Nginx 恢复该节点 →
nginx -t→nginx -s reload
回滚走完全相同的流程,区别只在第 4 步从 bak/ 而非 new/ 取包。
fail-fast 与安全中止:全程任一步失败立即终止,不再处理后续机器。若失败发生在「已摘流量」之后,会生成带恢复命令的告警,由人工确认服务状态后再恢复流量。
Keeploy/
├── main.py # CLI 入口(python main.py <command> ...)
├── keeploy_gui.py # 桌面 GUI 入口(python keeploy_gui.py [-c config])
├── requirements.txt # CLI(无 GUI)依赖
├── requirements-gui.txt # GUI 额外依赖(tk 相关)
├── config/
│ └── example.json # 配置样例(部署配置)
├── keeploy/ # 核心库
│ ├── __init__.py # 版本号 __version__
│ ├── cli.py # Click 命令行解析
│ ├── config.py # 配置加载 / 校验 / 主机·应用选择
│ ├── credentials.py # KeePass / 密码解析(CredentialProvider)
│ ├── deploy.py # 交互确认(input/prompt)
│ ├── local_builder.py # 本地拉代码 + 打包
│ ├── remote.py # SSH 封装(exec/scp/put/exists)
│ ├── nginx.py # NginxManager(摘/恢复流量、配置校验)
│ ├── strategies.py # 部署策略(jar / static)
│ ├── workflow.py # 编排引擎(deploy/rollback/resume)
│ ├── health.py # 健康检查轮询
│ ├── history.py # SQLite 部署历史
│ └── errors.py # 异常与中止提示
├── gui/ # 桌面 GUI 包(Tkinter 纯客户端,无 Web 服务)
│ ├── app.py # 整体布局 / 导航 / 主题切换 / 视图分发
│ ├── runner.py # 后台部署运行器(进度解析 + 日志累积)
│ ├── theme.py # 深 / 浅色主题令牌
│ ├── dialogs.py # 密码框 / 确认框等模态对话框
│ ├── exporter.py # 历史导出
│ ├── widgets.py # 通用组件(面板 / 按钮 / 状态点等)
│ ├── views/ # 各页面(配置管理 / 部署执行 / 历史记录 / 新建配置)
│ └── *.py # 其他 GUI 支撑模块
└── docs/
└── canvas_alignment.md # GUI 画布像素对齐校验报告(设计稿 vs 实现)
需要 Python 3.8+。
# CLI(无 GUI)
pip install -r requirements.txt
# 如需桌面 GUI
pip install -r requirements-gui.txtKeePass 凭据默认通过 pykeepass 读取;若未安装,运行涉及 KeePass 凭据的操作时会提示:
请执行 pip install -r requirements.txt,或移除配置中的 keepass 段
- 复制
config/example.json为你的环境配置(如config/prod.json),按需填写主机、应用与 KeePass 信息。 - 校验配置:
python main.py status -c config/prod.json
- 先做一次演练,确认流程正确(不实际改线上):
python main.py deploy -c config/prod.json --dry-run
- 正式部署:
python main.py deploy -c config/prod.json
- (可选)桌面 GUI:
python keeploy_gui.py -c config/prod.json
python main.py <command> [options]
| 命令 | 说明 |
|---|---|
deploy |
部署:本地打包 → 上传 → 逐台滚动发布 |
rollback |
回滚:基于历史备份恢复到上一成功版本 |
resume |
续发:仅对上次失败且已摘流量未恢复的节点继续发布 |
status |
查询本地部署历史记录(默认最近 20 条) |
-c, --config PATH:JSON 配置文件路径(必需,指定目标环境)。--ask-password:强制交互输入 KeePass 主密码(不依赖环境变量 / 配置文件)。-y, --yes:跳过所有确认交互,用于无人值守。--hosts:逗号分隔的主机名子集(仅对这些主机操作)。--apps:逗号分隔的应用名子集(仅部署这些应用)。--dry-run:演练模式,打印流程但不实际改线上(部署/回滚均支持)。
--skip-package:跳过本地拉取与打包,直接复用上次产物(需target_dir已有包)。--companion-restart APPS:伴随重启:仅指定的、且本机承载但未被选中的应用,随目标应用一起重启。--dry-run:见上。
--time TIME_DIR:指定回滚用的备份时间戳(远程backup_dir下的目录名)。省略则自动取该环境最近一次成功部署。--companion-restart APPS:同 deploy。--dry-run:见上。
--nodes HOSTS:逗号分隔的节点主机名,仅对这些节点续发(默认续发所有上次失败且已摘流量未恢复的节点)。
# 部署全部主机与应用
python main.py deploy -c config/prod.json
# 只部署 payment / recon 两个应用,且跳过确认
python main.py deploy -c config/prod.json --apps demo-payment,demo-recon -y
# 只部署 192.168.10.21 一台
python main.py deploy -c config/prod.json --hosts 192.168.10.21
# 演练(不实际改线上)
python main.py deploy -c config/prod.json --dry-run
# 回滚到指定时间戳版本
python main.py rollback -c config/prod.json --time 20260814-153000
# 查看最近 50 条历史
python main.py status -c config/prod.json --limit 50启动器:keeploy_gui.py,纯 Tkinter 客户端(无 Web 服务)。
# 直接启动(自动发现 config/ 下的 JSON)
python keeploy_gui.py
# 指定默认加载的配置文件
python keeploy_gui.py -c config/prod.jsonGUI 提供三大视图:
- 配置管理:编辑 / 校验
config/下的 JSON 配置。 - 部署执行:选择主机子集与应用子集,实时展示阶段进度(打包 / 上传 / 摘流量 / 替换 / 健康检查 / 恢复)、逐台日志与按应用分桶进度;支持中途中止。
- 历史记录:浏览部署/回滚历史,可导出。
主题:左下角开关切换深 / 浅色(偏好保存在 ~/.keeploy_gui_theme)。
GUI 完全基于现有
keeploy包实现,不改动任何 CLI 代码;后台部署通过重定向stdout捕获进度日志,并通过注入stop_event支持中止。
配置文件为 JSON,包含两个一级区块 hosts(目标服务器)与 apps(待部署应用),以及 name / keepass / nginx 等全局设置。
⚠️ 注意:config/example.json中仍使用旧版扁平字段(如health_url),当前代码解析的是health_check子段。请以本参考的字段为准(或按本段更新你的配置)。
| 字段 | 说明 |
|---|---|
name |
环境名(如 prod-demoapp),用于历史记录归类 |
manage_nginx |
是否启用 Nginx 摘/恢复流量(true/false) |
confirm_steps |
是否对关键步骤逐条交互确认(true/false) |
keepass.kdbx_path |
KeePass 数据库路径(.kdbx) |
keepass.keyfile |
keyfile 路径(可空) |
keepass.password |
KeePass 主密码(可空;建议留空,由环境变量/交互输入提供) |
keepass.env_var |
读取主密码的环境变量名(如 KEEPLOY_KDBX_PASSWORD) |
| 字段 | 说明 |
|---|---|
hostname |
主机名 / IP(SSH 连接地址) |
port |
SSH 端口(字符串,如 "22") |
inet |
内网地址,用于同机房机器间直传(省一次公网上传) |
auth_mode |
keepass 或 manual;缺省时按是否配置了 credential 自动推断 |
credential |
KeePass 中的凭据条目路径(如 演示/节点-01),auth_mode=keepass 时必填 |
username / password |
auth_mode=manual 时的明文账号密码 |
backup_dir |
远程备份根目录(带时间戳的 new/、bak/ 在其下) |
app_names |
该主机承载的应用名列表(与 apps[].app_name 对应) |
| 字段 | 说明 |
|---|---|
app_name |
应用名(全局唯一,被 hosts[].app_names 引用) |
type |
jar 或 static |
package_name |
产物名(jar 为 xxx.jar;static 为站点目录名,上传时打包为 xxx.zip) |
work_dir |
远程工作目录(产物部署位置) |
compile_dir |
本地代码目录(用于 fetch_cmd 拉取) |
fetch_cmd |
拉取代码的命令(如 svn up / git pull) |
package_cmd |
本地打包命令(如 mvn clean package / npm run build) |
pre_build_cmd |
打包前置命令(可空) |
target_dir |
本地打包产物目录(jar 必填;static 可空,由 dist_dir 决定) |
stop_cmd / start_cmd |
jar 的停服 / 启动命令(static 无需,留空) |
jvm_opts |
jar 未配 start_cmd 时的 JVM 参数(可空) |
log_file |
jar 未配 start_cmd 时的日志路径(可空,默认 work_dir/nohup.out) |
ng_port |
接入 Nginx 负载均衡的端口(有值才在发布流程中摘/恢复该应用流量) |
dist_dir |
static 打包后的产物子目录(如 dist) |
health_check |
健康检查配置(子段),结构与说明见下 |
| 字段 | 说明 |
|---|---|
url |
健康检查地址(如 http://{inet}:9216/actuator/health,{inet} 会替换为该主机的 inet) |
expect_status |
期望 HTTP 状态码(默认 200) |
timeout |
总超时秒数(默认 30) |
interval |
轮询间隔秒数(默认 3) |
drain_seconds |
Nginx 摘流量后等待存量连接 draining 的秒数(亦可在 nginx 一级用 drain_seconds 全局指定) |
未配置
health_check时,健康检查降级为固定等待(由drain_seconds/ 默认值决定),视为启动完成。
仅当 manage_nginx=true 且应用配置了 ng_port 时生效。
| 字段 | 说明 |
|---|---|
hostname |
Nginx 主机地址 |
port |
SSH 端口 |
conf_path |
nginx.conf 路径 |
cmd_path |
nginx 可执行路径 |
auth_mode |
keepass 或 manual |
credential |
KeePass 凭据条目路径 |
username / password |
auth_mode=manual 时的明文账号密码 |
drain_seconds |
摘流量后等待 draining 的全局默认秒数(可被 health_check.drain_seconds 覆盖) |
KeePass 主密码按以下顺序解析,命中即止:
- 环境变量(如
KEEPLOY_KDBX_PASSWORD) - 配置文件
keepass.password - keyfile(
keepass.keyfile) - 交互输入(
--ask-password或运行时提示)
主机 / Nginx 的 SSH 凭据:从 KeePass 对应 credential 条目读取用户名与密码;auth_mode=manual 时直接使用配置文件内明文。
- 配置文件不写 KeePass 主密码明文;主密码优先来自环境变量或运行期交互输入。
- 远程备份按时间戳落地于
backup_dir,回滚依赖这些备份,请勿清理正在用的时间戳目录。 - fail-fast:任一步失败即终止后续机器;若失败在摘流量之后,会提示人工恢复流量的命令,避免节点长期离线。
- 新增产物类型(如 docker):在
strategies.py实现DeployStrategy子类并注册到_STRATEGIES,无需改动workflow.py。 - 部署历史存储于本地 SQLite(
history.py),可按需扩展查询 / 导出(GUI 已提供导出)。 - GUI 与 CLI 共享同一
keeploy包语义,GUI 不修改任何 CLI 代码。