kdeploy 1.2.5 β 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +371 -419
- data/README_EN.md +1031 -0
- data/lib/kdeploy/cli.rb +7 -1
- data/lib/kdeploy/configuration.rb +53 -0
- data/lib/kdeploy/executor.rb +2 -2
- data/lib/kdeploy/version.rb +2 -1
- metadata +2 -43
data/README_EN.md
ADDED
|
@@ -0,0 +1,1031 @@
|
|
|
1
|
+
# Kdeploy
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
_ _
|
|
5
|
+
/\ /\__| | ___ _ __ | | ___ _ _
|
|
6
|
+
/ //_/ _` |/ _ \ '_ \| |/ _ \| | | |
|
|
7
|
+
/ __ \ (_| | __/ |_) | | (_) | |_| |
|
|
8
|
+
\/ \/\__,_|\___| .__/|_|\___/ \__, |
|
|
9
|
+
|_| |___/
|
|
10
|
+
|
|
11
|
+
β‘ Lightweight Agentless Deployment Tool
|
|
12
|
+
π Deploy with confidence, scale with ease
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
A lightweight, agentless deployment automation tool written in Ruby. Kdeploy enables you to deploy applications, manage configurations, and execute tasks across multiple servers using SSH, without requiring any agents or daemons on target machines.
|
|
16
|
+
|
|
17
|
+
[](https://rubygems.org/gems/kdeploy)
|
|
18
|
+
[](https://github.com/kevin197011/kdeploy/actions/workflows/gem-push.yml)
|
|
19
|
+
[](https://opensource.org/licenses/MIT)
|
|
20
|
+
|
|
21
|
+
**Language**: [English](README_EN.md) | [δΈζ](README.md)
|
|
22
|
+
|
|
23
|
+
## Table of Contents
|
|
24
|
+
|
|
25
|
+
- [Features](#-features)
|
|
26
|
+
- [Installation](#-installation)
|
|
27
|
+
- [Quick Start](#-quick-start)
|
|
28
|
+
- [Usage Guide](#-usage-guide)
|
|
29
|
+
- [Configuration](#-configuration)
|
|
30
|
+
- [Advanced Usage](#-advanced-usage)
|
|
31
|
+
- [Error Handling](#-error-handling)
|
|
32
|
+
- [Best Practices](#-best-practices)
|
|
33
|
+
- [Troubleshooting](#-troubleshooting)
|
|
34
|
+
- [Architecture](#-architecture)
|
|
35
|
+
- [Development](#-development)
|
|
36
|
+
- [Contributing](#-contributing)
|
|
37
|
+
- [License](#-license)
|
|
38
|
+
|
|
39
|
+
## π Features
|
|
40
|
+
|
|
41
|
+
### Core Features
|
|
42
|
+
|
|
43
|
+
- π **Agentless Remote Deployment**: Uses SSH for secure remote execution, no agents required
|
|
44
|
+
- π **Elegant Ruby DSL**: Simple and expressive task definition syntax
|
|
45
|
+
- π **Concurrent Execution**: Efficient parallel task processing across multiple hosts
|
|
46
|
+
- π€ **File Upload Support**: Easy file and template deployment via SCP
|
|
47
|
+
- π **Task Status Tracking**: Real-time execution monitoring with detailed output
|
|
48
|
+
- π **ERB Template Support**: Dynamic configuration generation with variable substitution
|
|
49
|
+
- π― **Role-based Deployment**: Target specific server roles for organized deployments
|
|
50
|
+
- π **Dry Run Mode**: Preview tasks before execution without making changes
|
|
51
|
+
- π¨ **Color-coded Output**: Intuitive color scheme (Green: success, Red: errors, Yellow: warnings)
|
|
52
|
+
- βοΈ **Flexible Host Targeting**: Execute tasks on specific hosts, roles, or all hosts
|
|
53
|
+
- π **Multiple Authentication Methods**: Support for SSH keys and password authentication
|
|
54
|
+
- π **Execution Time Tracking**: Monitor task execution duration for performance analysis
|
|
55
|
+
|
|
56
|
+
### Technical Features
|
|
57
|
+
|
|
58
|
+
- **Thread-safe Execution**: Built on `concurrent-ruby` for reliable parallel processing
|
|
59
|
+
- **Custom Error Handling**: Detailed error types for better debugging
|
|
60
|
+
- **Configuration Management**: Centralized configuration with sensible defaults
|
|
61
|
+
- **Extensible Architecture**: Modular design for easy extension
|
|
62
|
+
- **Shell Completion**: Auto-completion support for Bash and Zsh
|
|
63
|
+
|
|
64
|
+
## π¦ Installation
|
|
65
|
+
|
|
66
|
+
### Requirements
|
|
67
|
+
|
|
68
|
+
- Ruby >= 2.7.0
|
|
69
|
+
- SSH access to target servers
|
|
70
|
+
- SSH keys or password authentication configured
|
|
71
|
+
|
|
72
|
+
### Install via RubyGems
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
gem install kdeploy
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Install via Bundler
|
|
79
|
+
|
|
80
|
+
Add this line to your application's `Gemfile`:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
gem 'kdeploy'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
And then execute:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
bundle install
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Verify Installation
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
kdeploy version
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
You should see the version information and banner.
|
|
99
|
+
|
|
100
|
+
### Shell Completion
|
|
101
|
+
|
|
102
|
+
Kdeploy automatically configures shell completion during installation. If needed, manually add to your shell config:
|
|
103
|
+
|
|
104
|
+
**For Bash** (`~/.bashrc`):
|
|
105
|
+
```bash
|
|
106
|
+
source "$(gem contents kdeploy | grep kdeploy.bash)"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**For Zsh** (`~/.zshrc`):
|
|
110
|
+
```bash
|
|
111
|
+
source "$(gem contents kdeploy | grep kdeploy.zsh)"
|
|
112
|
+
autoload -Uz compinit && compinit
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
After adding the configuration:
|
|
116
|
+
1. For Bash: `source ~/.bashrc`
|
|
117
|
+
2. For Zsh: `source ~/.zshrc`
|
|
118
|
+
|
|
119
|
+
Now you can use Tab completion for:
|
|
120
|
+
- Commands: `kdeploy [TAB]`
|
|
121
|
+
- File paths: `kdeploy execute [TAB]`
|
|
122
|
+
- Options: `kdeploy execute deploy.rb [TAB]`
|
|
123
|
+
|
|
124
|
+
## π Quick Start
|
|
125
|
+
|
|
126
|
+
### 1. Initialize a New Project
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
kdeploy init my-deployment
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This creates a new directory with:
|
|
133
|
+
- `deploy.rb` - Main deployment configuration file
|
|
134
|
+
- `config/` - Directory for configuration files and templates
|
|
135
|
+
- `README.md` - Project documentation
|
|
136
|
+
|
|
137
|
+
### 2. Configure Hosts and Tasks
|
|
138
|
+
|
|
139
|
+
Edit `deploy.rb`:
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
# Define hosts
|
|
143
|
+
host "web01", user: "ubuntu", ip: "10.0.0.1", key: "~/.ssh/id_rsa"
|
|
144
|
+
host "web02", user: "ubuntu", ip: "10.0.0.2", key: "~/.ssh/id_rsa"
|
|
145
|
+
|
|
146
|
+
# Define roles
|
|
147
|
+
role :web, %w[web01 web02]
|
|
148
|
+
|
|
149
|
+
# Define deployment task
|
|
150
|
+
task :deploy, roles: :web do
|
|
151
|
+
run <<~SHELL
|
|
152
|
+
sudo systemctl stop nginx
|
|
153
|
+
echo "Deploying application..."
|
|
154
|
+
SHELL
|
|
155
|
+
|
|
156
|
+
upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
|
|
157
|
+
domain_name: "example.com",
|
|
158
|
+
port: 3000
|
|
159
|
+
|
|
160
|
+
run "sudo systemctl start nginx"
|
|
161
|
+
end
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 3. Run Deployment
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
kdeploy execute deploy.rb deploy
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## π Usage Guide
|
|
171
|
+
|
|
172
|
+
### Command Reference
|
|
173
|
+
|
|
174
|
+
#### `kdeploy init [DIR]`
|
|
175
|
+
|
|
176
|
+
Initialize a new deployment project.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Initialize in current directory
|
|
180
|
+
kdeploy init .
|
|
181
|
+
|
|
182
|
+
# Initialize in named directory
|
|
183
|
+
kdeploy init my-deployment
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### `kdeploy execute TASK_FILE [TASK]`
|
|
187
|
+
|
|
188
|
+
Execute deployment tasks from a configuration file.
|
|
189
|
+
|
|
190
|
+
**Basic Usage:**
|
|
191
|
+
```bash
|
|
192
|
+
# Execute all tasks in the file
|
|
193
|
+
kdeploy execute deploy.rb
|
|
194
|
+
|
|
195
|
+
# Execute a specific task
|
|
196
|
+
kdeploy execute deploy.rb deploy_web
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Options:**
|
|
200
|
+
- `--limit HOSTS`: Limit execution to specific hosts (comma-separated)
|
|
201
|
+
- `--parallel NUM`: Number of parallel executions (default: 10)
|
|
202
|
+
- `--dry-run`: Preview mode - show what would be done without executing
|
|
203
|
+
|
|
204
|
+
**Examples:**
|
|
205
|
+
```bash
|
|
206
|
+
# Preview deployment without executing
|
|
207
|
+
kdeploy execute deploy.rb deploy_web --dry-run
|
|
208
|
+
|
|
209
|
+
# Execute on specific hosts only
|
|
210
|
+
kdeploy execute deploy.rb deploy_web --limit web01,web02
|
|
211
|
+
|
|
212
|
+
# Use custom parallel count
|
|
213
|
+
kdeploy execute deploy.rb deploy_web --parallel 5
|
|
214
|
+
|
|
215
|
+
# Combine options
|
|
216
|
+
kdeploy execute deploy.rb deploy_web --limit web01 --parallel 3 --dry-run
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### `kdeploy version`
|
|
220
|
+
|
|
221
|
+
Show version information.
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
kdeploy version
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### `kdeploy help [COMMAND]`
|
|
228
|
+
|
|
229
|
+
Show help information.
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Show general help
|
|
233
|
+
kdeploy help
|
|
234
|
+
|
|
235
|
+
# Show help for specific command
|
|
236
|
+
kdeploy help execute
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Host Definition
|
|
240
|
+
|
|
241
|
+
#### Basic Host Configuration
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
# Single host with SSH key
|
|
245
|
+
host "web01",
|
|
246
|
+
user: "ubuntu",
|
|
247
|
+
ip: "10.0.0.1",
|
|
248
|
+
key: "~/.ssh/id_rsa"
|
|
249
|
+
|
|
250
|
+
# Host with password authentication
|
|
251
|
+
host "web02",
|
|
252
|
+
user: "admin",
|
|
253
|
+
ip: "10.0.0.2",
|
|
254
|
+
password: "your-password"
|
|
255
|
+
|
|
256
|
+
# Host with custom SSH port
|
|
257
|
+
host "web03",
|
|
258
|
+
user: "ubuntu",
|
|
259
|
+
ip: "10.0.0.3",
|
|
260
|
+
key: "~/.ssh/id_rsa",
|
|
261
|
+
port: 2222
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### Host Configuration Options
|
|
265
|
+
|
|
266
|
+
| Option | Type | Required | Description |
|
|
267
|
+
|--------|------|----------|-------------|
|
|
268
|
+
| `user` | String | Yes | SSH username |
|
|
269
|
+
| `ip` | String | Yes | Server IP address or hostname |
|
|
270
|
+
| `key` | String | No* | Path to SSH private key file |
|
|
271
|
+
| `password` | String | No* | SSH password |
|
|
272
|
+
| `port` | Integer | No | SSH port (default: 22) |
|
|
273
|
+
|
|
274
|
+
\* Either `key` or `password` is required for authentication.
|
|
275
|
+
|
|
276
|
+
#### Dynamic Host Definition
|
|
277
|
+
|
|
278
|
+
```ruby
|
|
279
|
+
# Define multiple hosts programmatically
|
|
280
|
+
%w[web01 web02 web03].each do |name|
|
|
281
|
+
host name,
|
|
282
|
+
user: "ubuntu",
|
|
283
|
+
ip: "10.0.0.#{name[-1]}",
|
|
284
|
+
key: "~/.ssh/id_rsa"
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Define hosts from external source
|
|
288
|
+
require 'yaml'
|
|
289
|
+
hosts_config = YAML.load_file('hosts.yml')
|
|
290
|
+
hosts_config.each do |name, config|
|
|
291
|
+
host name, **config
|
|
292
|
+
end
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Role Management
|
|
296
|
+
|
|
297
|
+
Roles allow you to group hosts and target them collectively in tasks.
|
|
298
|
+
|
|
299
|
+
```ruby
|
|
300
|
+
# Define roles
|
|
301
|
+
role :web, %w[web01 web02 web03]
|
|
302
|
+
role :db, %w[db01 db02]
|
|
303
|
+
role :cache, %w[cache01]
|
|
304
|
+
role :all, %w[web01 web02 web03 db01 db02 cache01]
|
|
305
|
+
|
|
306
|
+
# Use roles in tasks
|
|
307
|
+
task :deploy_web, roles: :web do
|
|
308
|
+
# Executes on all web servers
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
task :backup_db, roles: :db do
|
|
312
|
+
# Executes on all database servers
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Multiple roles
|
|
316
|
+
task :deploy_all, roles: [:web, :cache] do
|
|
317
|
+
# Executes on web and cache servers
|
|
318
|
+
end
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Task Definition
|
|
322
|
+
|
|
323
|
+
#### Basic Task
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
task :hello do
|
|
327
|
+
run "echo 'Hello, World!'"
|
|
328
|
+
end
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### Role-based Task
|
|
332
|
+
|
|
333
|
+
```ruby
|
|
334
|
+
task :deploy_web, roles: :web do
|
|
335
|
+
run "sudo systemctl restart nginx"
|
|
336
|
+
end
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
#### Host-specific Task
|
|
340
|
+
|
|
341
|
+
```ruby
|
|
342
|
+
task :maintenance, on: %w[web01] do
|
|
343
|
+
run <<~SHELL
|
|
344
|
+
sudo systemctl stop nginx
|
|
345
|
+
sudo apt-get update && sudo apt-get upgrade -y
|
|
346
|
+
sudo systemctl start nginx
|
|
347
|
+
SHELL
|
|
348
|
+
end
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
#### Task with Multiple Commands
|
|
352
|
+
|
|
353
|
+
```ruby
|
|
354
|
+
task :deploy, roles: :web do
|
|
355
|
+
# Stop service
|
|
356
|
+
run "sudo systemctl stop nginx"
|
|
357
|
+
|
|
358
|
+
# Upload configuration
|
|
359
|
+
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
|
|
360
|
+
|
|
361
|
+
# Start service
|
|
362
|
+
run "sudo systemctl start nginx"
|
|
363
|
+
|
|
364
|
+
# Verify status
|
|
365
|
+
run "sudo systemctl status nginx"
|
|
366
|
+
end
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
#### Task Options
|
|
370
|
+
|
|
371
|
+
| Option | Type | Description |
|
|
372
|
+
|-------|------|-------------|
|
|
373
|
+
| `roles` | Symbol/Array | Execute on hosts with specified role(s) |
|
|
374
|
+
| `on` | Array | Execute on specific host(s) |
|
|
375
|
+
|
|
376
|
+
**Note**: If neither `roles` nor `on` is specified, the task executes on all defined hosts.
|
|
377
|
+
|
|
378
|
+
### Command Types
|
|
379
|
+
|
|
380
|
+
#### `run` - Execute Shell Commands
|
|
381
|
+
|
|
382
|
+
Execute commands on remote servers.
|
|
383
|
+
|
|
384
|
+
```ruby
|
|
385
|
+
# Single line command
|
|
386
|
+
run "sudo systemctl restart nginx"
|
|
387
|
+
|
|
388
|
+
# Multi-line command (recommended for complex commands)
|
|
389
|
+
run <<~SHELL
|
|
390
|
+
cd /var/www/app
|
|
391
|
+
git pull origin main
|
|
392
|
+
bundle install
|
|
393
|
+
sudo systemctl restart puma
|
|
394
|
+
SHELL
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Best Practice**: Use heredoc (`<<~SHELL`) for multi-line commands to improve readability.
|
|
398
|
+
|
|
399
|
+
#### `upload` - Upload Files
|
|
400
|
+
|
|
401
|
+
Upload files to remote servers.
|
|
402
|
+
|
|
403
|
+
```ruby
|
|
404
|
+
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
|
|
405
|
+
upload "./scripts/deploy.sh", "/tmp/deploy.sh"
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Parameters:**
|
|
409
|
+
- `source`: Local file path
|
|
410
|
+
- `destination`: Remote file path
|
|
411
|
+
|
|
412
|
+
#### `upload_template` - Upload ERB Templates
|
|
413
|
+
|
|
414
|
+
Upload and render ERB templates with variable substitution.
|
|
415
|
+
|
|
416
|
+
```ruby
|
|
417
|
+
upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
|
|
418
|
+
domain_name: "example.com",
|
|
419
|
+
port: 3000,
|
|
420
|
+
worker_processes: 4
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**Parameters:**
|
|
424
|
+
- `source`: Local ERB template file path
|
|
425
|
+
- `destination`: Remote file path
|
|
426
|
+
- `variables`: Hash of variables for template rendering
|
|
427
|
+
|
|
428
|
+
### Template Support
|
|
429
|
+
|
|
430
|
+
Kdeploy supports ERB (Embedded Ruby) templates for dynamic configuration generation.
|
|
431
|
+
|
|
432
|
+
#### Creating Templates
|
|
433
|
+
|
|
434
|
+
Create an ERB template file (e.g., `config/nginx.conf.erb`):
|
|
435
|
+
|
|
436
|
+
```erb
|
|
437
|
+
user nginx;
|
|
438
|
+
worker_processes <%= worker_processes %>;
|
|
439
|
+
error_log /var/log/nginx/error.log;
|
|
440
|
+
pid /run/nginx.pid;
|
|
441
|
+
|
|
442
|
+
events {
|
|
443
|
+
worker_connections <%= worker_connections %>;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
http {
|
|
447
|
+
include /etc/nginx/mime.types;
|
|
448
|
+
default_type application/octet-stream;
|
|
449
|
+
|
|
450
|
+
upstream app_servers {
|
|
451
|
+
server 127.0.0.1:<%= port %>;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
server {
|
|
455
|
+
listen 80;
|
|
456
|
+
server_name <%= domain_name %>;
|
|
457
|
+
|
|
458
|
+
location / {
|
|
459
|
+
proxy_pass http://app_servers;
|
|
460
|
+
proxy_http_version 1.1;
|
|
461
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
462
|
+
proxy_set_header Connection 'upgrade';
|
|
463
|
+
proxy_set_header Host $host;
|
|
464
|
+
proxy_cache_bypass $http_upgrade;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
#### Using Templates
|
|
471
|
+
|
|
472
|
+
```ruby
|
|
473
|
+
task :deploy_config do
|
|
474
|
+
upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
|
|
475
|
+
domain_name: "example.com",
|
|
476
|
+
port: 3000,
|
|
477
|
+
worker_processes: 4,
|
|
478
|
+
worker_connections: 2048
|
|
479
|
+
end
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### Template Features
|
|
483
|
+
|
|
484
|
+
- Full ERB syntax support
|
|
485
|
+
- Variable substitution
|
|
486
|
+
- Conditional logic
|
|
487
|
+
- Loops and iterations
|
|
488
|
+
- Ruby code execution
|
|
489
|
+
|
|
490
|
+
### Inventory Block
|
|
491
|
+
|
|
492
|
+
Use the `inventory` block to organize host definitions:
|
|
493
|
+
|
|
494
|
+
```ruby
|
|
495
|
+
inventory do
|
|
496
|
+
host 'web01', user: 'ubuntu', ip: '10.0.0.1', key: '~/.ssh/id_rsa'
|
|
497
|
+
host 'web02', user: 'ubuntu', ip: '10.0.0.2', key: '~/.ssh/id_rsa'
|
|
498
|
+
host 'db01', user: 'root', ip: '10.0.0.3', key: '~/.ssh/id_rsa'
|
|
499
|
+
end
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
## βοΈ Configuration
|
|
503
|
+
|
|
504
|
+
### Default Configuration
|
|
505
|
+
|
|
506
|
+
Kdeploy uses sensible defaults that can be customized:
|
|
507
|
+
|
|
508
|
+
- **Default Parallel Count**: 10 concurrent executions
|
|
509
|
+
- **SSH Timeout**: 30 seconds
|
|
510
|
+
- **Host Key Verification**: Disabled (for convenience, enable in production)
|
|
511
|
+
|
|
512
|
+
### Environment Variables
|
|
513
|
+
|
|
514
|
+
You can override defaults using environment variables:
|
|
515
|
+
|
|
516
|
+
```bash
|
|
517
|
+
export KDEPLOY_PARALLEL=5
|
|
518
|
+
export KDEPLOY_SSH_TIMEOUT=60
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Configuration File
|
|
522
|
+
|
|
523
|
+
For project-specific configuration, create a `.kdeploy.yml`:
|
|
524
|
+
|
|
525
|
+
```yaml
|
|
526
|
+
parallel: 5
|
|
527
|
+
ssh_timeout: 60
|
|
528
|
+
verify_host_key: true
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## π§ Advanced Usage
|
|
532
|
+
|
|
533
|
+
### Conditional Execution
|
|
534
|
+
|
|
535
|
+
Use Ruby conditionals in your deployment files:
|
|
536
|
+
|
|
537
|
+
```ruby
|
|
538
|
+
task :deploy do
|
|
539
|
+
if ENV['ENVIRONMENT'] == 'production'
|
|
540
|
+
run "sudo systemctl stop nginx"
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
|
|
544
|
+
|
|
545
|
+
if ENV['ENVIRONMENT'] == 'production'
|
|
546
|
+
run "sudo systemctl start nginx"
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Looping Over Hosts
|
|
552
|
+
|
|
553
|
+
```ruby
|
|
554
|
+
# Execute different commands based on host
|
|
555
|
+
task :custom_setup do
|
|
556
|
+
@hosts.each do |name, config|
|
|
557
|
+
if name.start_with?('web')
|
|
558
|
+
run "echo 'Web server: #{name}'"
|
|
559
|
+
elsif name.start_with?('db')
|
|
560
|
+
run "echo 'Database server: #{name}'"
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
end
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### Error Handling in Tasks
|
|
567
|
+
|
|
568
|
+
```ruby
|
|
569
|
+
task :deploy do
|
|
570
|
+
run "sudo systemctl stop nginx" || raise "Failed to stop nginx"
|
|
571
|
+
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
|
|
572
|
+
run "sudo systemctl start nginx" || raise "Failed to start nginx"
|
|
573
|
+
end
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Using External Libraries
|
|
577
|
+
|
|
578
|
+
```ruby
|
|
579
|
+
require 'yaml'
|
|
580
|
+
require 'json'
|
|
581
|
+
|
|
582
|
+
# Load configuration from external files
|
|
583
|
+
config = YAML.load_file('config.yml')
|
|
584
|
+
|
|
585
|
+
task :deploy do
|
|
586
|
+
config['commands'].each do |cmd|
|
|
587
|
+
run cmd
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### Task Dependencies
|
|
593
|
+
|
|
594
|
+
While Kdeploy doesn't have built-in task dependencies, you can achieve this with Ruby:
|
|
595
|
+
|
|
596
|
+
```ruby
|
|
597
|
+
task :setup do
|
|
598
|
+
run "echo 'Setting up...'"
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
task :deploy do
|
|
602
|
+
# Manually call setup task
|
|
603
|
+
self.class.kdeploy_tasks[:setup][:block].call.each do |cmd|
|
|
604
|
+
case cmd[:type]
|
|
605
|
+
when :run
|
|
606
|
+
run cmd[:command]
|
|
607
|
+
when :upload
|
|
608
|
+
upload cmd[:source], cmd[:destination]
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
run "echo 'Deploying...'"
|
|
613
|
+
end
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
## π¨ Error Handling
|
|
617
|
+
|
|
618
|
+
### Error Types
|
|
619
|
+
|
|
620
|
+
Kdeploy provides specific error types for better debugging:
|
|
621
|
+
|
|
622
|
+
- `Kdeploy::TaskNotFoundError` - Task not found
|
|
623
|
+
- `Kdeploy::HostNotFoundError` - Host not found
|
|
624
|
+
- `Kdeploy::SSHError` - SSH operation failed
|
|
625
|
+
- `Kdeploy::SCPError` - SCP upload failed
|
|
626
|
+
- `Kdeploy::TemplateError` - Template rendering failed
|
|
627
|
+
- `Kdeploy::ConfigurationError` - Configuration error
|
|
628
|
+
- `Kdeploy::FileNotFoundError` - File not found
|
|
629
|
+
|
|
630
|
+
### Error Output
|
|
631
|
+
|
|
632
|
+
Errors are displayed with:
|
|
633
|
+
- Red color coding
|
|
634
|
+
- Detailed error messages
|
|
635
|
+
- Host information
|
|
636
|
+
- Original error context
|
|
637
|
+
|
|
638
|
+
### Handling Errors
|
|
639
|
+
|
|
640
|
+
```ruby
|
|
641
|
+
# In your deployment file
|
|
642
|
+
begin
|
|
643
|
+
task :deploy do
|
|
644
|
+
run "risky-command"
|
|
645
|
+
end
|
|
646
|
+
rescue Kdeploy::SSHError => e
|
|
647
|
+
puts "SSH Error: #{e.message}"
|
|
648
|
+
# Handle error
|
|
649
|
+
end
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
## π‘ Best Practices
|
|
653
|
+
|
|
654
|
+
### 1. Use Heredoc for Multi-line Commands
|
|
655
|
+
|
|
656
|
+
```ruby
|
|
657
|
+
# β
Good
|
|
658
|
+
run <<~SHELL
|
|
659
|
+
cd /var/www/app
|
|
660
|
+
git pull origin main
|
|
661
|
+
bundle install
|
|
662
|
+
SHELL
|
|
663
|
+
|
|
664
|
+
# β Avoid
|
|
665
|
+
run "cd /var/www/app && git pull origin main && bundle install"
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
### 2. Organize with Roles
|
|
669
|
+
|
|
670
|
+
```ruby
|
|
671
|
+
# β
Good - Use roles for organization
|
|
672
|
+
role :web, %w[web01 web02]
|
|
673
|
+
role :db, %w[db01 db02]
|
|
674
|
+
|
|
675
|
+
task :deploy_web, roles: :web do
|
|
676
|
+
# ...
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
# β Avoid - Hardcoding host names
|
|
680
|
+
task :deploy do
|
|
681
|
+
# Hard to maintain
|
|
682
|
+
end
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
### 3. Use Templates for Dynamic Configuration
|
|
686
|
+
|
|
687
|
+
```ruby
|
|
688
|
+
# β
Good - Use templates
|
|
689
|
+
upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
|
|
690
|
+
domain_name: "example.com",
|
|
691
|
+
port: 3000
|
|
692
|
+
|
|
693
|
+
# β Avoid - Hardcoding values
|
|
694
|
+
run "echo 'server_name example.com;' > /etc/nginx/nginx.conf"
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### 4. Validate Before Deployment
|
|
698
|
+
|
|
699
|
+
```ruby
|
|
700
|
+
task :deploy do
|
|
701
|
+
# Validate configuration
|
|
702
|
+
run "nginx -t" || raise "Nginx configuration is invalid"
|
|
703
|
+
|
|
704
|
+
# Deploy
|
|
705
|
+
upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
|
|
706
|
+
run "sudo systemctl reload nginx"
|
|
707
|
+
end
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
### 5. Use Dry Run for Testing
|
|
711
|
+
|
|
712
|
+
Always test with `--dry-run` before actual deployment:
|
|
713
|
+
|
|
714
|
+
```bash
|
|
715
|
+
kdeploy execute deploy.rb deploy_web --dry-run
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### 6. Organize Files Properly
|
|
719
|
+
|
|
720
|
+
```
|
|
721
|
+
project/
|
|
722
|
+
βββ deploy.rb # Main deployment file
|
|
723
|
+
βββ config/ # Configuration files
|
|
724
|
+
β βββ nginx.conf.erb # Templates
|
|
725
|
+
β βββ app.conf # Static configs
|
|
726
|
+
βββ scripts/ # Helper scripts
|
|
727
|
+
βββ deploy.sh
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### 7. Version Control
|
|
731
|
+
|
|
732
|
+
- Commit `deploy.rb` and templates
|
|
733
|
+
- Use `.gitignore` for sensitive files
|
|
734
|
+
- Store secrets in environment variables
|
|
735
|
+
|
|
736
|
+
### 8. Parallel Execution
|
|
737
|
+
|
|
738
|
+
Adjust parallel count based on your infrastructure:
|
|
739
|
+
|
|
740
|
+
```bash
|
|
741
|
+
# For many hosts, increase parallel count
|
|
742
|
+
kdeploy execute deploy.rb deploy --parallel 20
|
|
743
|
+
|
|
744
|
+
# For limited resources, decrease
|
|
745
|
+
kdeploy execute deploy.rb deploy --parallel 3
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
## π Troubleshooting
|
|
749
|
+
|
|
750
|
+
### Common Issues
|
|
751
|
+
|
|
752
|
+
#### SSH Authentication Failed
|
|
753
|
+
|
|
754
|
+
**Problem**: `SSH authentication failed`
|
|
755
|
+
|
|
756
|
+
**Solutions**:
|
|
757
|
+
1. Verify SSH key path is correct
|
|
758
|
+
2. Check key permissions: `chmod 600 ~/.ssh/id_rsa`
|
|
759
|
+
3. Test SSH connection manually: `ssh user@host`
|
|
760
|
+
4. Verify username and IP address
|
|
761
|
+
|
|
762
|
+
#### Host Not Found
|
|
763
|
+
|
|
764
|
+
**Problem**: `No hosts found for task`
|
|
765
|
+
|
|
766
|
+
**Solutions**:
|
|
767
|
+
1. Verify host names in task match defined hosts
|
|
768
|
+
2. Check role definitions
|
|
769
|
+
3. Verify `--limit` option if used
|
|
770
|
+
|
|
771
|
+
#### Command Execution Failed
|
|
772
|
+
|
|
773
|
+
**Problem**: Commands fail on remote server
|
|
774
|
+
|
|
775
|
+
**Solutions**:
|
|
776
|
+
1. Test commands manually on target server
|
|
777
|
+
2. Check user permissions (may need sudo)
|
|
778
|
+
3. Verify command syntax
|
|
779
|
+
4. Check server logs
|
|
780
|
+
|
|
781
|
+
#### Template Rendering Error
|
|
782
|
+
|
|
783
|
+
**Problem**: Template upload fails
|
|
784
|
+
|
|
785
|
+
**Solutions**:
|
|
786
|
+
1. Verify ERB syntax in template
|
|
787
|
+
2. Check all required variables are provided
|
|
788
|
+
3. Validate template file exists
|
|
789
|
+
4. Test template rendering locally
|
|
790
|
+
|
|
791
|
+
#### Connection Timeout
|
|
792
|
+
|
|
793
|
+
**Problem**: SSH connection times out
|
|
794
|
+
|
|
795
|
+
**Solutions**:
|
|
796
|
+
1. Check network connectivity
|
|
797
|
+
2. Verify firewall rules
|
|
798
|
+
3. Increase timeout in configuration
|
|
799
|
+
4. Check SSH service on target server
|
|
800
|
+
|
|
801
|
+
### Debug Mode
|
|
802
|
+
|
|
803
|
+
Enable verbose output by checking the execution output. Kdeploy provides detailed information about:
|
|
804
|
+
- Task execution status
|
|
805
|
+
- Command output
|
|
806
|
+
- Error messages
|
|
807
|
+
- Execution duration
|
|
808
|
+
|
|
809
|
+
### Getting Help
|
|
810
|
+
|
|
811
|
+
- Check [GitHub Issues](https://github.com/kevin197011/kdeploy/issues)
|
|
812
|
+
- Review example projects
|
|
813
|
+
- Read the documentation
|
|
814
|
+
- Ask in discussions
|
|
815
|
+
|
|
816
|
+
## ποΈ Architecture
|
|
817
|
+
|
|
818
|
+
### Core Components
|
|
819
|
+
|
|
820
|
+
- **CLI** (`cli.rb`): Command-line interface using Thor
|
|
821
|
+
- **DSL** (`dsl.rb`): Domain-specific language for task definition
|
|
822
|
+
- **Executor** (`executor.rb`): SSH/SCP execution engine
|
|
823
|
+
- **Runner** (`runner.rb`): Concurrent task execution coordinator
|
|
824
|
+
- **CommandExecutor** (`command_executor.rb`): Individual command execution
|
|
825
|
+
- **CommandGrouper** (`command_grouper.rb`): Command grouping logic
|
|
826
|
+
- **Template** (`template.rb`): ERB template rendering
|
|
827
|
+
- **Output** (`output.rb`): Output formatting and display
|
|
828
|
+
- **Configuration** (`configuration.rb`): Configuration management
|
|
829
|
+
- **Errors** (`errors.rb`): Custom error types
|
|
830
|
+
|
|
831
|
+
### Execution Flow
|
|
832
|
+
|
|
833
|
+
1. **Parse Configuration**: Load and parse `deploy.rb`
|
|
834
|
+
2. **Resolve Hosts**: Determine target hosts based on task definition
|
|
835
|
+
3. **Group Commands**: Group commands by type for efficient execution
|
|
836
|
+
4. **Execute Concurrently**: Run tasks in parallel across hosts
|
|
837
|
+
5. **Collect Results**: Gather execution results and status
|
|
838
|
+
6. **Display Output**: Format and display results to user
|
|
839
|
+
|
|
840
|
+
### Concurrency Model
|
|
841
|
+
|
|
842
|
+
Kdeploy uses `concurrent-ruby` with a fixed thread pool:
|
|
843
|
+
- Default: 10 concurrent executions
|
|
844
|
+
- Configurable via `--parallel` option
|
|
845
|
+
- Thread-safe result collection
|
|
846
|
+
- Automatic resource cleanup
|
|
847
|
+
|
|
848
|
+
## π§ Development
|
|
849
|
+
|
|
850
|
+
### Setup Development Environment
|
|
851
|
+
|
|
852
|
+
```bash
|
|
853
|
+
# Clone repository
|
|
854
|
+
git clone https://github.com/kevin197011/kdeploy.git
|
|
855
|
+
cd kdeploy
|
|
856
|
+
|
|
857
|
+
# Install dependencies
|
|
858
|
+
bundle install
|
|
859
|
+
|
|
860
|
+
# Run tests
|
|
861
|
+
bundle exec rspec
|
|
862
|
+
|
|
863
|
+
# Run console
|
|
864
|
+
bin/console
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
### Project Structure
|
|
868
|
+
|
|
869
|
+
```
|
|
870
|
+
kdeploy/
|
|
871
|
+
βββ lib/
|
|
872
|
+
β βββ kdeploy/
|
|
873
|
+
β βββ cli.rb # CLI interface
|
|
874
|
+
β βββ dsl.rb # DSL definition
|
|
875
|
+
β βββ executor.rb # SSH/SCP executor
|
|
876
|
+
β βββ runner.rb # Task runner
|
|
877
|
+
β βββ command_executor.rb # Command executor
|
|
878
|
+
β βββ command_grouper.rb # Command grouper
|
|
879
|
+
β βββ template.rb # Template handler
|
|
880
|
+
β βββ output.rb # Output interface
|
|
881
|
+
β βββ configuration.rb # Configuration
|
|
882
|
+
β βββ errors.rb # Error types
|
|
883
|
+
β βββ ...
|
|
884
|
+
βββ spec/ # Tests
|
|
885
|
+
βββ exe/ # Executables
|
|
886
|
+
βββ sample/ # Example projects
|
|
887
|
+
βββ README.md # This file
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
### Running Tests
|
|
891
|
+
|
|
892
|
+
```bash
|
|
893
|
+
# Run all tests
|
|
894
|
+
bundle exec rspec
|
|
895
|
+
|
|
896
|
+
# Run specific test file
|
|
897
|
+
bundle exec rspec spec/kdeploy_spec.rb
|
|
898
|
+
|
|
899
|
+
# Run with coverage
|
|
900
|
+
COVERAGE=true bundle exec rspec
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
### Building the Gem
|
|
904
|
+
|
|
905
|
+
```bash
|
|
906
|
+
# Build gem
|
|
907
|
+
gem build kdeploy.gemspec
|
|
908
|
+
|
|
909
|
+
# Install locally
|
|
910
|
+
gem install ./kdeploy-*.gem
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
### Code Style
|
|
914
|
+
|
|
915
|
+
The project uses RuboCop for code style:
|
|
916
|
+
|
|
917
|
+
```bash
|
|
918
|
+
# Check style
|
|
919
|
+
bundle exec rubocop
|
|
920
|
+
|
|
921
|
+
# Auto-fix issues
|
|
922
|
+
bundle exec rubocop -a
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
## π€ Contributing
|
|
926
|
+
|
|
927
|
+
Contributions are welcome! Please follow these steps:
|
|
928
|
+
|
|
929
|
+
1. **Fork the repository**
|
|
930
|
+
2. **Create a feature branch**: `git checkout -b feature/my-new-feature`
|
|
931
|
+
3. **Make your changes**: Follow the code style and add tests
|
|
932
|
+
4. **Commit your changes**: Use conventional commit messages
|
|
933
|
+
5. **Push to the branch**: `git push origin feature/my-new-feature`
|
|
934
|
+
6. **Create a Pull Request**: Provide a clear description of changes
|
|
935
|
+
|
|
936
|
+
### Contribution Guidelines
|
|
937
|
+
|
|
938
|
+
- Follow existing code style
|
|
939
|
+
- Add tests for new features
|
|
940
|
+
- Update documentation
|
|
941
|
+
- Ensure all tests pass
|
|
942
|
+
- Follow conventional commit format
|
|
943
|
+
|
|
944
|
+
### Commit Message Format
|
|
945
|
+
|
|
946
|
+
Follow [Conventional Commits](https://www.conventionalcommits.org/):
|
|
947
|
+
|
|
948
|
+
```
|
|
949
|
+
<type>(<scope>): <subject>
|
|
950
|
+
|
|
951
|
+
<body>
|
|
952
|
+
|
|
953
|
+
<footer>
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
|
|
957
|
+
|
|
958
|
+
## π Examples
|
|
959
|
+
|
|
960
|
+
### Example Projects
|
|
961
|
+
|
|
962
|
+
Check out the [example project](https://github.com/kevin197011/kdeploy-app) for a complete deployment setup.
|
|
963
|
+
|
|
964
|
+
### Common Deployment Scenarios
|
|
965
|
+
|
|
966
|
+
#### Web Application Deployment
|
|
967
|
+
|
|
968
|
+
```ruby
|
|
969
|
+
host "web01", user: "deploy", ip: "10.0.0.1", key: "~/.ssh/id_rsa"
|
|
970
|
+
role :web, %w[web01]
|
|
971
|
+
|
|
972
|
+
task :deploy_app, roles: :web do
|
|
973
|
+
run <<~SHELL
|
|
974
|
+
cd /var/www/app
|
|
975
|
+
git pull origin main
|
|
976
|
+
bundle install
|
|
977
|
+
rake db:migrate
|
|
978
|
+
sudo systemctl restart puma
|
|
979
|
+
SHELL
|
|
980
|
+
end
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
#### Database Backup
|
|
984
|
+
|
|
985
|
+
```ruby
|
|
986
|
+
host "db01", user: "postgres", ip: "10.0.0.10", key: "~/.ssh/id_rsa"
|
|
987
|
+
role :db, %w[db01]
|
|
988
|
+
|
|
989
|
+
task :backup, roles: :db do
|
|
990
|
+
run <<~SHELL
|
|
991
|
+
pg_dump mydb > /tmp/backup_$(date +%Y%m%d).sql
|
|
992
|
+
gzip /tmp/backup_*.sql
|
|
993
|
+
aws s3 cp /tmp/backup_*.sql.gz s3://backups/
|
|
994
|
+
rm /tmp/backup_*.sql.gz
|
|
995
|
+
SHELL
|
|
996
|
+
end
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
#### Configuration Management
|
|
1000
|
+
|
|
1001
|
+
```ruby
|
|
1002
|
+
task :update_config, roles: :web do
|
|
1003
|
+
upload_template "./config/app.yml.erb", "/etc/app/config.yml",
|
|
1004
|
+
environment: "production",
|
|
1005
|
+
database_url: ENV['DATABASE_URL'],
|
|
1006
|
+
redis_url: ENV['REDIS_URL']
|
|
1007
|
+
|
|
1008
|
+
run "sudo systemctl reload app"
|
|
1009
|
+
end
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
## π License
|
|
1013
|
+
|
|
1014
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
1015
|
+
|
|
1016
|
+
## π Links
|
|
1017
|
+
|
|
1018
|
+
- **GitHub**: https://github.com/kevin197011/kdeploy
|
|
1019
|
+
- **RubyGems**: https://rubygems.org/gems/kdeploy
|
|
1020
|
+
- **Issues**: https://github.com/kevin197011/kdeploy/issues
|
|
1021
|
+
- **Example Project**: https://github.com/kevin197011/kdeploy-app
|
|
1022
|
+
|
|
1023
|
+
## π Acknowledgments
|
|
1024
|
+
|
|
1025
|
+
- Built with [Thor](https://github.com/rails/thor) for CLI
|
|
1026
|
+
- Uses [net-ssh](https://github.com/net-ssh/net-ssh) for SSH operations
|
|
1027
|
+
- Powered by [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby) for concurrency
|
|
1028
|
+
|
|
1029
|
+
---
|
|
1030
|
+
|
|
1031
|
+
**Made with β€οΈ for the DevOps community**
|