Kdeploy
_ _
/\ /\__| | ___ _ __ | | ___ _ _
/ //_/ _` |/ _ \ '_ \| |/ _ \| | | |
/ __ \ (_| | __/ |_) | | (_) | |_| |
\/ \/\__,_|\___| .__/|_|\___/ \__, |
|_| |___/
⚡ 轻量级无代理部署工具
🚀 自动部署,轻松扩展
一个用 Ruby 编写的轻量级、无代理的部署自动化工具。Kdeploy 使您能够使用 SSH 在多个服务器上部署应用程序、管理配置和执行任务,而无需在目标机器上安装任何代理或守护进程。
目录
- 功能特性
- 安装
- 快速开始
- 使用指南
- 配置
- 高级用法
- 错误处理
- 最佳实践
- 故障排除
- 架构
- 开发
- 贡献
- 许可证
🌟 功能特性
核心功能
- 🔑 无代理远程部署: 使用 SSH 进行安全的远程执行,无需安装代理
- 📝 优雅的 Ruby DSL: 简单而富有表现力的任务定义语法
- 🚀 并发执行: 跨多个主机的高效并行任务处理
- 📤 文件上传支持: 通过 SCP 轻松部署文件和模板
- 📁 目录同步功能: 递归同步目录,支持文件过滤和删除多余文件
- 📊 任务状态跟踪: 实时执行监控,提供详细输出
- 🔄 ERB 模板支持: 支持变量替换的动态配置生成
- 🎯 基于角色的部署: 针对特定服务器角色进行有组织的部署
- 🔍 试运行模式: 在执行前预览任务,不进行实际更改
- 🎨 彩色输出: 直观的颜色方案(绿色:成功,红色:错误,黄色:警告)
- ⚙️ 灵活的主机定位: 在特定主机、角色或所有主机上执行任务
- 🔐 多种身份验证方法: 支持 SSH 密钥和密码身份验证
- 📈 执行时间跟踪: 监控任务执行持续时间以进行性能分析
技术特性
-
线程安全执行: 基于
concurrent-ruby实现可靠的并行处理 - 自定义错误处理: 详细的错误类型,便于调试
- 配置管理: 集中式配置,提供合理的默认值
- 可扩展架构: 模块化设计,易于扩展
- Shell 自动补全: 支持 Bash 和 Zsh 的自动补全
📦 安装
要求
- Ruby >= 2.7.0
- 对目标服务器的 SSH 访问权限
- 已配置 SSH 密钥或密码身份验证
通过 RubyGems 安装
gem install kdeploy通过 Bundler 安装
将以下行添加到应用程序的 Gemfile 中:
gem 'kdeploy'然后执行:
bundle install验证安装
kdeploy version您应该看到版本信息和横幅。
Shell 自动补全
Kdeploy 在安装期间自动配置 shell 自动补全。如果需要,可以手动添加到 shell 配置中:
对于 Bash (~/.bashrc):
source "$(gem contents kdeploy | grep kdeploy.bash)"对于 Zsh (~/.zshrc):
source "$(gem contents kdeploy | grep kdeploy.zsh)"
autoload -Uz compinit && compinit添加配置后:
- 对于 Bash:
source ~/.bashrc - 对于 Zsh:
source ~/.zshrc
现在您可以使用 Tab 补全:
- 命令:
kdeploy [TAB] - 文件路径:
kdeploy execute [TAB] - 选项:
kdeploy execute deploy.rb [TAB]
🚀 快速开始
1. 初始化新项目
kdeploy init my-deployment这将创建一个新目录,包含:
-
deploy.rb- 主部署配置文件 -
config/- 配置文件和模板目录 -
README.md- 项目文档
2. 配置主机和任务
编辑 deploy.rb:
# 定义主机
host "web01", user: "ubuntu", ip: "10.0.0.1", key: "~/.ssh/id_rsa"
host "web02", user: "ubuntu", ip: "10.0.0.2", key: "~/.ssh/id_rsa"
# 定义角色
role :web, %w[web01 web02]
# 定义部署任务
task :deploy, roles: :web do
run <<~SHELL
sudo systemctl stop nginx
echo "正在部署应用程序..."
SHELL
upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
domain_name: "example.com",
port: 3000
run "sudo systemctl start nginx"
end3. 运行部署
kdeploy execute deploy.rb deploy📖 使用指南
命令参考
kdeploy init [DIR]
初始化新的部署项目。
# 在当前目录初始化
kdeploy init .
# 在指定目录初始化
kdeploy init my-deploymentkdeploy execute TASK_FILE [TASK]
从配置文件执行部署任务。
基本用法:
# 执行文件中的所有任务
kdeploy execute deploy.rb
# 执行特定任务
kdeploy execute deploy.rb deploy_web选项:
-
--limit HOSTS: 限制执行到特定主机(逗号分隔) -
--parallel NUM: 并行执行数量(默认: 10) -
--dry-run: 预览模式 - 显示将要执行的操作而不实际执行
示例:
# 预览部署而不执行
kdeploy execute deploy.rb deploy_web --dry-run
# 仅在特定主机上执行
kdeploy execute deploy.rb deploy_web --limit web01,web02
# 使用自定义并行数量
kdeploy execute deploy.rb deploy_web --parallel 5
# 组合选项
kdeploy execute deploy.rb deploy_web --limit web01 --parallel 3 --dry-runkdeploy version
显示版本信息。
kdeploy versionkdeploy help [COMMAND]
显示帮助信息。
# 显示一般帮助
kdeploy help
# 显示特定命令的帮助
kdeploy help execute主机定义
基本主机配置
# 使用 SSH 密钥的单个主机
host "web01",
user: "ubuntu",
ip: "10.0.0.1",
key: "~/.ssh/id_rsa"
# 使用密码身份验证的主机
host "web02",
user: "admin",
ip: "10.0.0.2",
password: "your-password"
# 使用自定义 SSH 端口的主机
host "web03",
user: "ubuntu",
ip: "10.0.0.3",
key: "~/.ssh/id_rsa",
port: 2222
# 使用 sudo 的主机(所有命令自动使用 sudo)
host "web04",
user: "ubuntu",
ip: "10.0.0.4",
key: "~/.ssh/id_rsa",
use_sudo: true主机配置选项
| 选项 | 类型 | 必需 | 描述 |
|---|---|---|---|
user |
String | 是 | SSH 用户名 |
ip |
String | 是 | 服务器 IP 地址或主机名 |
key |
String | 否* | SSH 私钥文件路径 |
password |
String | 否* | SSH 密码 |
port |
Integer | 否 | SSH 端口(默认: 22) |
use_sudo |
Boolean | 否 | 是否对所有命令自动使用 sudo(默认: false) |
sudo_password |
String | 否 | sudo 密码(如果需要密码验证) |
* 身份验证需要 key 或 password 之一。
动态主机定义
# 以编程方式定义多个主机
%w[web01 web02 web03].each do |name|
host name,
user: "ubuntu",
ip: "10.0.0.#{name[-1]}",
key: "~/.ssh/id_rsa"
end
# 从外部源定义主机
require 'yaml'
hosts_config = YAML.load_file('hosts.yml')
hosts_config.each do |name, config|
host name, **config
end角色管理
角色允许您对主机进行分组,并在任务中集体定位它们。
# 定义角色
role :web, %w[web01 web02 web03]
role :db, %w[db01 db02]
role :cache, %w[cache01]
role :all, %w[web01 web02 web03 db01 db02 cache01]
# 在任务中使用角色
task :deploy_web, roles: :web do
# 在所有 Web 服务器上执行
end
task :backup_db, roles: :db do
# 在所有数据库服务器上执行
end
# 多个角色
task :deploy_all, roles: [:web, :cache] do
# 在 Web 和缓存服务器上执行
end任务定义
基本任务
task :hello do
run "echo 'Hello, World!'"
end基于角色的任务
task :deploy_web, roles: :web do
run "sudo systemctl restart nginx"
end特定主机任务
task :maintenance, on: %w[web01] do
run <<~SHELL
sudo systemctl stop nginx
sudo apt-get update && sudo apt-get upgrade -y
sudo systemctl start nginx
SHELL
end多命令任务
task :deploy, roles: :web do
# 停止服务
run "sudo systemctl stop nginx"
# 上传配置
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
# 启动服务
run "sudo systemctl start nginx"
# 验证状态
run "sudo systemctl status nginx"
end任务选项
| 选项 | 类型 | 描述 |
|---|---|---|
roles |
Symbol/Array | 在具有指定角色的主机上执行 |
on |
Array | 在特定主机上执行 |
注意: 如果未指定 roles 或 on,任务将在所有已定义的主机上执行。
命令类型
run - 执行 Shell 命令
在远程服务器上执行命令。
# 单行命令
run "sudo systemctl restart nginx"
# 多行命令(推荐用于复杂命令)
run <<~SHELL
cd /var/www/app
git pull origin main
bundle install
sudo systemctl restart puma
SHELL参数:
-
command: 要执行的命令字符串 -
sudo: 布尔值,是否使用 sudo 执行此命令(可选,默认: nil,继承主机配置)
sudo 使用方式:
- 在主机级别配置(所有命令自动使用 sudo):
host "web01",
user: "ubuntu",
ip: "10.0.0.1",
key: "~/.ssh/id_rsa",
use_sudo: true # 所有命令自动使用 sudo- 在命令级别配置(仅特定命令使用 sudo):
task :deploy do
run "systemctl restart nginx", sudo: true # 仅此命令使用 sudo
run "echo 'Deployed'" # 此命令不使用 sudo
end- 使用 sudo 密码(如果需要密码验证):
host "web01",
user: "ubuntu",
ip: "10.0.0.1",
key: "~/.ssh/id_rsa",
use_sudo: true,
sudo_password: "your-sudo-password" # 仅在需要密码时配置注意:
- 如果命令已经以
sudo开头,工具不会重复添加 - 推荐使用 NOPASSWD 配置 sudo,避免在配置文件中存储密码
- 命令级别的
sudo选项会覆盖主机级别的use_sudo配置
最佳实践: 对多行命令使用 heredoc (<<~SHELL) 以提高可读性。
upload - 上传文件
将文件上传到远程服务器。
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
upload "./scripts/deploy.sh", "/tmp/deploy.sh"参数:
-
source: 本地文件路径 -
destination: 远程文件路径
upload_template - 上传 ERB 模板
上传并渲染 ERB 模板,支持变量替换。
upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
domain_name: "example.com",
port: 3000,
worker_processes: 4参数:
-
source: 本地 ERB 模板文件路径 -
destination: 远程文件路径 -
variables: 用于模板渲染的变量哈希
sync - 同步目录
递归同步本地目录到远程服务器,支持文件过滤和删除多余文件。
# 基本同步
sync "./app", "/var/www/app"
# 同步并忽略特定文件/目录
sync "./app", "/var/www/app",
ignore: [".git", "*.log", "node_modules", "*.tmp"]
# 同步并删除远程多余文件
sync "./app", "/var/www/app",
ignore: [".git", "*.log"],
delete: true
# 排除特定文件(与 ignore 相同,但语义更清晰)
sync "./config", "/etc/app",
exclude: ["*.example", "*.bak", ".env.local"]参数:
-
source: 本地源目录路径 -
destination: 远程目标目录路径 -
ignore: 要忽略的文件/目录模式数组(支持 .gitignore 风格的通配符) -
exclude: 与ignore相同,用于语义清晰 -
delete: 布尔值,是否删除远程目录中不存在于源目录的文件(默认: false)
忽略模式支持:
-
*.log- 匹配所有 .log 文件 -
node_modules- 匹配 node_modules 目录或文件 -
**/*.tmp- 递归匹配所有 .tmp 文件 -
.git- 匹配 .git 目录 -
config/*.local- 匹配 config 目录下的所有 .local 文件
使用场景:
- 部署应用程序代码
- 同步配置文件目录
- 同步静态资源文件
- 保持本地和远程目录结构一致
模板支持
Kdeploy 支持 ERB(嵌入式 Ruby)模板,用于动态配置生成。
创建模板
创建 ERB 模板文件(例如,config/nginx.conf.erb):
user nginx;
worker_processes <%= worker_processes %>;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections <%= worker_connections %>;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
upstream app_servers {
server 127.0.0.1:<%= port %>;
}
server {
listen 80;
server_name <%= domain_name %>;
location / {
proxy_pass http://app_servers;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
}使用模板
task :deploy_config do
upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
domain_name: "example.com",
port: 3000,
worker_processes: 4,
worker_connections: 2048
end模板特性
- 完整的 ERB 语法支持
- 变量替换
- 条件逻辑
- 循环和迭代
- Ruby 代码执行
清单块
使用 inventory 块来组织主机定义:
inventory do
host 'web01', user: 'ubuntu', ip: '10.0.0.1', key: '~/.ssh/id_rsa'
host 'web02', user: 'ubuntu', ip: '10.0.0.2', key: '~/.ssh/id_rsa'
host 'db01', user: 'root', ip: '10.0.0.3', key: '~/.ssh/id_rsa'
end⚙️ 配置
默认配置
Kdeploy 使用可自定义的合理默认值:
- 默认并行数量: 10 个并发执行
- SSH 超时: 30 秒
- 主机密钥验证: 禁用(为方便起见,在生产环境中启用)
环境变量
您可以使用环境变量覆盖默认值:
export KDEPLOY_PARALLEL=5
export KDEPLOY_SSH_TIMEOUT=60配置文件
对于项目特定的配置,创建 .kdeploy.yml:
parallel: 5
ssh_timeout: 60
verify_host_key: true配置文件会自动从当前目录向上查找,直到找到 .kdeploy.yml 文件。
🔧 高级用法
条件执行
在部署文件中使用 Ruby 条件:
task :deploy do
if ENV['ENVIRONMENT'] == 'production'
run "sudo systemctl stop nginx"
end
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
if ENV['ENVIRONMENT'] == 'production'
run "sudo systemctl start nginx"
end
end循环主机
# 根据主机执行不同的命令
task :custom_setup do
@hosts.each do |name, config|
if name.start_with?('web')
run "echo 'Web 服务器: #{name}'"
elsif name.start_with?('db')
run "echo '数据库服务器: #{name}'"
end
end
end任务中的错误处理
task :deploy do
run "sudo systemctl stop nginx" || raise "停止 nginx 失败"
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
run "sudo systemctl start nginx" || raise "启动 nginx 失败"
end使用外部库
require 'yaml'
require 'json'
# 从外部文件加载配置
config = YAML.load_file('config.yml')
task :deploy do
config['commands'].each do |cmd|
run cmd
end
end🚨 错误处理
错误类型
Kdeploy 提供特定的错误类型以便更好地调试:
-
Kdeploy::TaskNotFoundError- 任务未找到 -
Kdeploy::HostNotFoundError- 主机未找到 -
Kdeploy::SSHError- SSH 操作失败 -
Kdeploy::SCPError- SCP 上传失败 -
Kdeploy::TemplateError- 模板渲染失败 -
Kdeploy::ConfigurationError- 配置错误 -
Kdeploy::FileNotFoundError- 文件未找到
错误输出
错误显示包括:
- 红色颜色编码
- 详细的错误消息
- 主机信息
- 原始错误上下文
💡 最佳实践
1. 对多行命令使用 Heredoc
# ✅ 好的做法
run <<~SHELL
cd /var/www/app
git pull origin main
bundle install
SHELL
# ❌ 避免
run "cd /var/www/app && git pull origin main && bundle install"2. 使用角色进行组织
# ✅ 好的做法 - 使用角色进行组织
role :web, %w[web01 web02]
role :db, %w[db01 db02]
task :deploy_web, roles: :web do
# ...
end
# ❌ 避免 - 硬编码主机名
task :deploy do
# 难以维护
end3. 使用模板进行动态配置
# ✅ 好的做法 - 使用模板
upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
domain_name: "example.com",
port: 3000
# ❌ 避免 - 硬编码值
run "echo 'server_name example.com;' > /etc/nginx/nginx.conf"4. 部署前验证
task :deploy do
# 验证配置
run "nginx -t" || raise "Nginx 配置无效"
# 部署
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
run "sudo systemctl reload nginx"
end5. 使用试运行进行测试
在实际部署之前,始终使用 --dry-run 进行测试:
kdeploy execute deploy.rb deploy_web --dry-run6. 正确组织文件
project/
├── deploy.rb # 主部署文件
├── config/ # 配置文件
│ ├── nginx.conf.erb # 模板
│ └── app.conf # 静态配置
└── scripts/ # 辅助脚本
└── deploy.sh
7. 版本控制
- 提交
deploy.rb和模板 - 使用
.gitignore处理敏感文件 - 将密钥存储在环境变量中
8. 并行执行
根据您的基础设施调整并行数量:
# 对于许多主机,增加并行数量
kdeploy execute deploy.rb deploy --parallel 20
# 对于有限资源,减少
kdeploy execute deploy.rb deploy --parallel 3🔍 故障排除
常见问题
SSH 身份验证失败
问题: SSH authentication failed
解决方案:
- 验证 SSH 密钥路径是否正确
- 检查密钥权限:
chmod 600 ~/.ssh/id_rsa - 手动测试 SSH 连接:
ssh user@host - 验证用户名和 IP 地址
主机未找到
问题: No hosts found for task
解决方案:
- 验证任务中的主机名是否与已定义的主机匹配
- 检查角色定义
- 如果使用了
--limit选项,请验证
命令执行失败
问题: 远程服务器上的命令失败
解决方案:
- 在目标服务器上手动测试命令
- 检查用户权限(可能需要 sudo)
- 验证命令语法
- 检查服务器日志
模板渲染错误
问题: 模板上传失败
解决方案:
- 验证模板中的 ERB 语法
- 检查是否提供了所有必需的变量
- 验证模板文件是否存在
- 在本地测试模板渲染
连接超时
问题: SSH 连接超时
解决方案:
- 检查网络连接
- 验证防火墙规则
- 在配置中增加超时时间
- 检查目标服务器上的 SSH 服务
🏗️ 架构
核心组件
-
CLI (
cli.rb): 使用 Thor 的命令行界面 -
DSL (
dsl.rb): 用于任务定义的领域特定语言 -
Executor (
executor.rb): SSH/SCP 执行引擎 -
Runner (
runner.rb): 并发任务执行协调器 -
CommandExecutor (
command_executor.rb): 单个命令执行 -
CommandGrouper (
command_grouper.rb): 命令分组逻辑 -
Template (
template.rb): ERB 模板渲染 -
Output (
output.rb): 输出格式化和显示 -
Configuration (
configuration.rb): 配置管理 -
Errors (
errors.rb): 自定义错误类型
执行流程
-
解析配置: 加载并解析
deploy.rb - 解析主机: 根据任务定义确定目标主机
- 分组命令: 按类型分组命令以提高执行效率
- 并发执行: 跨主机并行运行任务
- 收集结果: 收集执行结果和状态
- 显示输出: 格式化并向用户显示结果
并发模型
Kdeploy 使用带有固定线程池的 concurrent-ruby:
- 默认: 10 个并发执行
- 可通过
--parallel选项配置 - 线程安全的结果收集
- 自动资源清理
🔧 开发
设置开发环境
# 克隆仓库
git clone https://github.com/kevin197011/kdeploy.git
cd kdeploy
# 安装依赖
bundle install
# 运行测试
bundle exec rspec
# 运行控制台
bin/console项目结构
kdeploy/
├── lib/
│ └── kdeploy/
│ ├── cli.rb # CLI 接口
│ ├── dsl.rb # DSL 定义
│ ├── executor.rb # SSH/SCP 执行器
│ ├── runner.rb # 任务运行器
│ ├── command_executor.rb # 命令执行器
│ ├── command_grouper.rb # 命令分组器
│ ├── template.rb # 模板处理器
│ ├── output.rb # 输出接口
│ ├── configuration.rb # 配置
│ ├── errors.rb # 错误类型
│ └── ...
├── spec/ # 测试
├── exe/ # 可执行文件
├── sample/ # 示例项目
└── README.md # 本文档
运行测试
# 运行所有测试
bundle exec rspec
# 运行特定测试文件
bundle exec rspec spec/kdeploy_spec.rb
# 运行覆盖率
COVERAGE=true bundle exec rspec构建 Gem
# 构建 gem
gem build kdeploy.gemspec
# 本地安装
gem install ./kdeploy-*.gem代码风格
项目使用 RuboCop 进行代码风格检查:
# 检查风格
bundle exec rubocop
# 自动修复问题
bundle exec rubocop -a🤝 贡献
欢迎贡献!请遵循以下步骤:
- Fork 仓库
-
创建功能分支:
git checkout -b feature/my-new-feature - 进行更改: 遵循代码风格并添加测试
- 提交更改: 使用约定式提交消息
-
推送到分支:
git push origin feature/my-new-feature - 创建 Pull Request: 提供清晰的更改描述
贡献指南
- 遵循现有代码风格
- 为新功能添加测试
- 更新文档
- 确保所有测试通过
- 遵循约定式提交格式
提交消息格式
遵循 约定式提交:
<type>(<scope>): <subject>
<body>
<footer>
类型: feat, fix, docs, style, refactor, test, chore
📚 示例
示例项目
查看 示例项目 以获取完整的部署设置。
常见部署场景
Web 应用程序部署
host "web01", user: "deploy", ip: "10.0.0.1", key: "~/.ssh/id_rsa"
role :web, %w[web01]
task :deploy_app, roles: :web do
run <<~SHELL
cd /var/www/app
git pull origin main
bundle install
rake db:migrate
sudo systemctl restart puma
SHELL
end数据库备份
host "db01", user: "postgres", ip: "10.0.0.10", key: "~/.ssh/id_rsa"
role :db, %w[db01]
task :backup, roles: :db do
run <<~SHELL
pg_dump mydb > /tmp/backup_$(date +%Y%m%d).sql
gzip /tmp/backup_*.sql
aws s3 cp /tmp/backup_*.sql.gz s3://backups/
rm /tmp/backup_*.sql.gz
SHELL
end配置管理
task :update_config, roles: :web do
upload_template "./config/app.yml.erb", "/etc/app/config.yml",
environment: "production",
database_url: ENV['DATABASE_URL'],
redis_url: ENV['REDIS_URL']
run "sudo systemctl reload app"
end目录同步部署
task :deploy_app, roles: :web do
# 同步应用程序代码,忽略开发文件
sync "./app", "/var/www/app",
ignore: [".git", "*.log", "node_modules", ".env.local", "*.tmp"],
delete: true
# 同步配置文件
sync "./config", "/etc/app",
exclude: ["*.example", "*.bak"]
run "sudo systemctl restart app"
end📝 许可证
该 gem 在 MIT 许可证 条款下作为开源提供。
🔗 链接
- GitHub: https://github.com/kevin197011/kdeploy
- RubyGems: https://rubygems.org/gems/kdeploy
- Issues: https://github.com/kevin197011/kdeploy/issues
- 示例项目: https://github.com/kevin197011/kdeploy-app
🙏 致谢
- 使用 Thor 构建 CLI
- 使用 net-ssh 进行 SSH 操作
- 由 concurrent-ruby 提供并发支持
为 DevOps 社区用 ❤️ 制作