kdeploy 1.3.3 β†’ 1.3.4

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.
data/README_EN.md CHANGED
@@ -9,10 +9,9 @@
9
9
  |_| |___/
10
10
 
11
11
  ⚑ Lightweight Agentless Deployment Tool
12
- πŸš€ Deploy with confidence, scale with ease
13
12
  ```
14
13
 
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.
14
+ Define hosts and tasks in Ruby DSL; execute deployments and configuration across servers via SSH/SCP with no agent on targets.
16
15
 
17
16
  [![Gem Version](https://img.shields.io/gem/v/kdeploy)](https://rubygems.org/gems/kdeploy)
18
17
  [![Ruby](https://github.com/kevin197011/kdeploy/actions/workflows/gem-push.yml/badge.svg)](https://github.com/kevin197011/kdeploy/actions/workflows/gem-push.yml)
@@ -20,1216 +19,103 @@ A lightweight, agentless deployment automation tool written in Ruby. Kdeploy ena
20
19
 
21
20
  **Language**: [English](README_EN.md) | [δΈ­ζ–‡](README.md)
22
21
 
23
- ## Table of Contents
22
+ **Full requirements, DSL, API, architecture**: [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md)
24
23
 
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)
24
+ ## Features
38
25
 
39
- ## 🌟 Features
26
+ - Agentless SSH execution with multi-host concurrency
27
+ - Ruby DSL: hosts, roles, tasks; Chef-style resources (`package`, `service`, `template`, `sync`, etc.)
28
+ - File upload, ERB templates, directory sync (optional rsync fast path)
29
+ - Dry-run, JSON output, retry/timeout policies
40
30
 
41
- ### Core Features
31
+ **Stack**: Ruby, Thor, net-ssh, concurrent-ruby
42
32
 
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
33
+ ## Installation
55
34
 
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
35
+ Requires Ruby >= 2.7 and SSH access to targets.
73
36
 
74
37
  ```bash
75
38
  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
39
  kdeploy version
96
40
  ```
97
41
 
98
- You should see the version information and banner.
99
-
100
- **If `kdeploy` is not found**: the gem executable directory may not be in your PATH. Add to `~/.zshrc` or `~/.bashrc` then run `source ~/.zshrc`:
101
-
102
- ```bash
103
- export PATH="$(ruby -e 'puts Gem.bindir'):$PATH"
104
- ```
105
-
106
- ### Shell Completion
42
+ With Bundler: add `gem 'kdeploy'` and run `bundle install`.
107
43
 
108
- Kdeploy automatically configures shell completion during installation. If needed, manually add to your shell config:
44
+ If `kdeploy` is not found, add `$(ruby -e 'puts Gem.bindir')` to your `PATH`.
109
45
 
110
- **For Bash** (`~/.bashrc`):
111
- ```bash
112
- source "$(gem contents kdeploy | grep kdeploy.bash)"
113
- ```
46
+ ## Quick Start
114
47
 
115
- **For Zsh** (`~/.zshrc`):
116
48
  ```bash
117
- source "$(gem contents kdeploy | grep kdeploy.zsh)"
118
- autoload -Uz compinit && compinit
49
+ kdeploy init my-deploy
50
+ cd my-deploy
119
51
  ```
120
52
 
121
- After adding the configuration:
122
- 1. For Bash: `source ~/.bashrc`
123
- 2. For Zsh: `source ~/.zshrc`
124
-
125
- Now you can use Tab completion for:
126
- - Commands: `kdeploy [TAB]`
127
- - File paths: `kdeploy execute [TAB]`
128
- - Options: `kdeploy execute deploy.rb [TAB]`
129
-
130
- ## πŸš€ Quick Start
131
-
132
- ### 1. Initialize a New Project
133
-
134
- ```bash
135
- kdeploy init my-deployment
136
- ```
137
-
138
- This creates a new directory with:
139
- - `deploy.rb` - Main deployment configuration file
140
- - `config/` - Directory for configuration files and templates
141
- - `README.md` - Project documentation
142
-
143
- ### 2. Configure Hosts and Tasks
144
-
145
- Edit `deploy.rb` (using Chef-style resource DSL):
53
+ Edit `deploy.rb`:
146
54
 
147
55
  ```ruby
148
- # Define hosts
149
56
  host "web01", user: "ubuntu", ip: "10.0.0.1", key: "~/.ssh/id_rsa"
150
- host "web02", user: "ubuntu", ip: "10.0.0.2", key: "~/.ssh/id_rsa"
151
- role :web, %w[web01 web02]
152
-
153
- # Define deployment task
154
- task :deploy_web, roles: :web do
155
- package "nginx"
156
- directory "/etc/nginx/conf.d"
157
- template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb",
158
- variables: { domain_name: "example.com", port: 3000 }
159
- file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
160
- run "nginx -t", sudo: true
161
- service "nginx", action: %i[enable restart]
162
- end
163
- ```
164
-
165
- ### 3. Run Deployment
166
-
167
- ```bash
168
- kdeploy execute deploy.rb deploy_web
169
- ```
170
-
171
- ## πŸ“– Usage Guide
172
-
173
- ### Command Reference
174
-
175
- #### `kdeploy init [DIR]`
176
-
177
- Initialize a new deployment project.
178
-
179
- ```bash
180
- # Initialize in current directory
181
- kdeploy init .
182
-
183
- # Initialize in named directory
184
- kdeploy init my-deployment
185
- ```
186
-
187
- #### `kdeploy execute TASK_FILE [TASK]`
188
-
189
- Execute deployment tasks from a configuration file.
190
-
191
- **Basic Usage:**
192
- ```bash
193
- # Execute all tasks in the file
194
- kdeploy execute deploy.rb
195
-
196
- # Execute a specific task
197
- kdeploy execute deploy.rb deploy_web
198
- ```
199
-
200
- **Options:**
201
- - `--limit HOSTS`: Limit execution to specific hosts (comma-separated)
202
- - `--parallel NUM`: Number of parallel executions (default: 10)
203
- - `--dry-run`: Preview mode - show what would be done without executing
204
- - `--debug`: Debug mode - show detailed stdout/stderr output for `run` steps
205
- - `--no-banner`: Do not print banner (automation-friendly)
206
- - `--format FORMAT`: Output format (`text`|`json`, default `text`)
207
- - `--retries N`: Retry count for network operations (default `0`)
208
- - `--retry-delay SECONDS`: Delay between retries in seconds (default `1`)
209
- - `--retry-on-nonzero`: Retry commands on nonzero exit status (default `false`)
210
- - `--timeout SECONDS`: Per-host execution timeout in seconds (default: none)
211
- - `--step-timeout SECONDS`: Per-step execution timeout in seconds (default: none)
212
- - `--retry-policy JSON`: Retry policy JSON (overrides `.kdeploy.yml`)
213
- - `--retry-policy-file PATH`: Retry policy JSON file (overrides `.kdeploy.yml`)
214
-
215
- **Examples:**
216
- ```bash
217
- # Preview deployment without executing
218
- kdeploy execute deploy.rb deploy_web --dry-run
219
-
220
- # Execute on specific hosts only
221
- kdeploy execute deploy.rb deploy_web --limit web01,web02
222
-
223
- # Use custom parallel count
224
- kdeploy execute deploy.rb deploy_web --parallel 5
225
-
226
- # Show detailed stdout/stderr output
227
- kdeploy execute deploy.rb deploy_web --debug
228
-
229
- # Machine-readable JSON output
230
- kdeploy execute deploy.rb deploy_web --format json --no-banner
231
-
232
- # Retry transient network failures
233
- kdeploy execute deploy.rb deploy_web --retries 3 --retry-delay 1
234
-
235
- # Retry on nonzero exit status
236
- kdeploy execute deploy.rb deploy_web --retries 2 --retry-on-nonzero
237
-
238
- # Set per-host timeout (seconds)
239
- kdeploy execute deploy.rb deploy_web --timeout 120
240
-
241
- # Set per-step timeout (seconds)
242
- kdeploy execute deploy.rb deploy_web --step-timeout 30
243
-
244
- # Override retry policy via CLI JSON
245
- kdeploy execute deploy.rb deploy_web --retry-policy '{"run":{"retries":2,"retry_on_exit_codes":[2]}}'
246
-
247
- # Override retry policy via file
248
- kdeploy execute deploy.rb deploy_web --retry-policy-file ./retry_policy.example.json
249
-
250
- # Combine options
251
- kdeploy execute deploy.rb deploy_web --limit web01 --parallel 3 --dry-run
252
- ```
253
-
254
- #### `kdeploy version`
255
-
256
- Show version information.
257
-
258
- ```bash
259
- kdeploy version
260
- ```
261
-
262
- #### `kdeploy help [COMMAND]`
263
-
264
- Show help information.
265
-
266
- ```bash
267
- # Show general help
268
- kdeploy help
269
-
270
- # Show help for specific command
271
- kdeploy help execute
272
- ```
273
-
274
- ### Host Definition
275
-
276
- #### Basic Host Configuration
277
-
278
- ```ruby
279
- # Single host with SSH key
280
- host "web01",
281
- user: "ubuntu",
282
- ip: "10.0.0.1",
283
- key: "~/.ssh/id_rsa"
284
-
285
- # Host with password authentication
286
- host "web02",
287
- user: "admin",
288
- ip: "10.0.0.2",
289
- password: "your-password"
290
-
291
- # Host with custom SSH port
292
- host "web03",
293
- user: "ubuntu",
294
- ip: "10.0.0.3",
295
- key: "~/.ssh/id_rsa",
296
- port: 2222
297
-
298
- # Host with sudo (all commands automatically use sudo)
299
- host "web04",
300
- user: "ubuntu",
301
- ip: "10.0.0.4",
302
- key: "~/.ssh/id_rsa",
303
- use_sudo: true
304
- ```
305
-
306
- #### Host Configuration Options
307
-
308
- | Option | Type | Required | Description |
309
- |--------|------|----------|-------------|
310
- | `user` | String | Yes | SSH username |
311
- | `ip` | String | Yes | Server IP address or hostname |
312
- | `key` | String | No* | Path to SSH private key file |
313
- | `password` | String | No* | SSH password |
314
- | `port` | Integer | No | SSH port (default: 22) |
315
- | `use_sudo` | Boolean | No | Automatically use sudo for all commands (default: false) |
316
- | `sudo_password` | String | No | sudo password (if password authentication is required) |
317
-
318
- \* Either `key` or `password` is required for authentication.
319
-
320
- #### Dynamic Host Definition
321
-
322
- ```ruby
323
- # Define multiple hosts programmatically
324
- %w[web01 web02 web03].each do |name|
325
- host name,
326
- user: "ubuntu",
327
- ip: "10.0.0.#{name[-1]}",
328
- key: "~/.ssh/id_rsa"
329
- end
330
-
331
- # Define hosts from external source
332
- require 'yaml'
333
- hosts_config = YAML.load_file('hosts.yml')
334
- hosts_config.each do |name, config|
335
- host name, **config
336
- end
337
- ```
338
-
339
- ### Role Management
340
-
341
- Roles allow you to group hosts and target them collectively in tasks.
342
-
343
- ```ruby
344
- # Define roles
345
- role :web, %w[web01 web02 web03]
346
- role :db, %w[db01 db02]
347
- role :cache, %w[cache01]
348
- role :all, %w[web01 web02 web03 db01 db02 cache01]
349
-
350
- # Use roles in tasks
351
- task :deploy_web, roles: :web do
352
- # Executes on all web servers
353
- end
354
-
355
- task :backup_db, roles: :db do
356
- # Executes on all database servers
357
- end
358
-
359
- # Multiple roles
360
- task :deploy_all, roles: [:web, :cache] do
361
- # Executes on web and cache servers
362
- end
363
- ```
364
-
365
- ### Task Definition
366
-
367
- #### Basic Task
368
-
369
- ```ruby
370
- task :hello do
371
- run "echo 'Hello, World!'"
372
- end
373
- ```
374
-
375
- #### Role-based Task
57
+ role :web, %w[web01]
376
58
 
377
- ```ruby
378
59
  task :deploy_web, roles: :web do
379
- service "nginx", action: :restart
380
- end
381
- ```
382
-
383
- #### Host-specific Task
384
-
385
- ```ruby
386
- task :maintenance, on: %w[web01] do
387
- service "nginx", action: :stop
388
- run "apt-get update && apt-get upgrade -y", sudo: true
389
- service "nginx", action: %i[start enable]
390
- end
391
- ```
392
-
393
- #### Task with Multiple Commands
394
-
395
- ```ruby
396
- task :deploy_web, roles: :web do
397
- package "nginx"
398
- directory "/etc/nginx/conf.d"
399
- template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb", variables: { port: 3000 }
400
- file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
401
- run "nginx -t", sudo: true
402
- service "nginx", action: %i[enable restart]
403
- end
404
- ```
405
-
406
- #### Task Options
407
-
408
- | Option | Type | Description |
409
- |-------|------|-------------|
410
- | `roles` | Symbol/Array | Execute on hosts with specified role(s) |
411
- | `on` | Array | Execute on specific host(s) |
412
-
413
- **Note**: If neither `roles` nor `on` is specified, the task executes on all defined hosts.
414
-
415
- ### Command Types
416
-
417
- #### `run` - Execute Shell Commands
418
-
419
- Execute commands on remote servers.
420
-
421
- ```ruby
422
- # Single line command
423
- run "sudo systemctl restart nginx"
424
-
425
- # Multi-line command (recommended for complex commands)
426
- run <<~SHELL
427
- cd /var/www/app
428
- git pull origin main
429
- bundle install
430
- sudo systemctl restart puma
431
- SHELL
432
- ```
433
-
434
- **Parameters:**
435
- - `command`: Command string to execute
436
- - `sudo`: Boolean, whether to execute this command with sudo (optional, default: nil, inherits host configuration)
437
-
438
- **Using sudo:**
439
-
440
- 1. **At host level** (all commands automatically use sudo):
441
- ```ruby
442
- host "web01",
443
- user: "ubuntu",
444
- ip: "10.0.0.1",
445
- key: "~/.ssh/id_rsa",
446
- use_sudo: true # All commands automatically use sudo
447
- ```
448
-
449
- 2. **At command level** (only specific commands use sudo):
450
- ```ruby
451
- task :deploy do
452
- run "systemctl restart nginx", sudo: true # Only this command uses sudo
453
- run "echo 'Deployed'" # This command does not use sudo
454
- end
455
- ```
456
-
457
- 3. **With sudo password** (if password authentication is required):
458
- ```ruby
459
- host "web01",
460
- user: "ubuntu",
461
- ip: "10.0.0.1",
462
- key: "~/.ssh/id_rsa",
463
- use_sudo: true,
464
- sudo_password: "your-sudo-password" # Only configure if password is required
465
- ```
466
-
467
- **Notes:**
468
- - If the command already starts with `sudo`, the tool will not add it again
469
- - It's recommended to use NOPASSWD sudo configuration to avoid storing passwords in configuration files
470
- - Command-level `sudo` option overrides host-level `use_sudo` configuration
471
-
472
- **Best Practice**: Use heredoc (`<<~SHELL`) for multi-line commands to improve readability.
473
-
474
- #### `upload` - Upload Files
475
-
476
- Upload files to remote servers.
477
-
478
- ```ruby
479
- upload "./config/nginx.conf", "/etc/nginx/nginx.conf"
480
- upload "./scripts/deploy.sh", "/tmp/deploy.sh"
481
- ```
482
-
483
- **Parameters:**
484
- - `source`: Local file path
485
- - `destination`: Remote file path
486
-
487
- #### `upload_template` - Upload ERB Templates
488
-
489
- Upload and render ERB templates with variable substitution.
490
-
491
- ```ruby
492
- upload_template "./config/nginx.conf.erb", "/etc/nginx/nginx.conf",
493
- domain_name: "example.com",
494
- port: 3000,
495
- worker_processes: 4
496
- ```
497
-
498
- **Parameters:**
499
- - `source`: Local ERB template file path
500
- - `destination`: Remote file path
501
- - `variables`: Hash of variables for template rendering
502
-
503
- #### `sync` - Directory Sync
504
-
505
- Recursively sync a local directory to a remote server with filtering options.
506
-
507
- ```ruby
508
- # Basic sync
509
- sync "./app", "/var/www/app"
510
-
511
- # Ignore specific files/dirs
512
- sync "./app", "/var/www/app",
513
- ignore: [".git", "*.log", "node_modules", "*.tmp"]
514
-
515
- # Delete remote files not present locally
516
- sync "./app", "/var/www/app",
517
- ignore: [".git", "*.log"],
518
- delete: true
519
-
520
- # Exclude files (alias of ignore)
521
- sync "./config", "/etc/app",
522
- exclude: ["*.example", "*.bak", ".env.local"]
523
-
524
- # Fast sync (prefer rsync when available)
525
- sync "./app", "/var/www/app",
526
- fast: true
527
-
528
- # Parallel sync uploads
529
- sync "./app", "/var/www/app",
530
- parallel: 4
531
- ```
532
-
533
- **Parameters:**
534
- - `source`: Local source directory path
535
- - `destination`: Remote destination directory path
536
- - `ignore`: Patterns to ignore (gitignore-style)
537
- - `exclude`: Same as `ignore` for clarity
538
- - `delete`: Delete remote files not present locally (default: false)
539
- - `fast`: Enable fast sync path (prefer rsync when available, default: false)
540
- - `parallel`: Upload concurrency for sync (default: 1)
541
-
542
- ### Chef-Style Resource DSL
543
-
544
- Kdeploy provides a declarative resource DSL similar to Chef, which can replace or mix with low-level primitives (`run`, `upload`, `upload_template`).
545
-
546
- #### `package` - Install System Packages
547
-
548
- ```ruby
549
- package "nginx"
550
- package "nginx", version: "1.18"
551
- package "nginx", platform: :yum # CentOS/RHEL
552
- ```
553
-
554
- Uses apt (Ubuntu/Debian) by default; `platform: :yum` generates yum commands.
555
-
556
- #### `service` - Manage System Services (systemd)
557
-
558
- ```ruby
559
- service "nginx", action: [:enable, :start]
560
- service "nginx", action: :restart
561
- service "nginx", action: [:stop, :disable]
562
- ```
563
-
564
- Supports `:start`, `:stop`, `:restart`, `:reload`, `:enable`, `:disable`.
565
-
566
- #### `template` - Deploy ERB Templates
567
-
568
- ```ruby
569
- template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb", variables: { port: 3000 }
570
- # Or block syntax
571
- template "/etc/app.conf" do
572
- source "./config/app.erb"
573
- variables(domain: "example.com")
574
- end
575
- ```
576
-
577
- #### `file` - Upload Local Files
578
-
579
- ```ruby
580
- file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
581
- ```
582
-
583
- #### `directory` - Ensure Remote Directory Exists
584
-
585
- ```ruby
586
- directory "/etc/nginx/conf.d"
587
- directory "/var/log/app", mode: "0755"
588
- ```
589
-
590
- **Example: Deploy Nginx Using Resource DSL**
591
-
592
- ```ruby
593
- task :deploy_nginx, roles: :web do
594
60
  package "nginx"
595
- directory "/etc/nginx/conf.d"
596
61
  template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb", variables: { port: 3000 }
597
- file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
598
62
  run "nginx -t", sudo: true
599
63
  service "nginx", action: %i[enable restart]
600
64
  end
601
65
  ```
602
66
 
603
- ### Template Support
604
-
605
- Kdeploy supports ERB (Embedded Ruby) templates for dynamic configuration generation.
606
-
607
- #### Creating Templates
608
-
609
- Create an ERB template file (e.g., `config/nginx.conf.erb`):
610
-
611
- ```erb
612
- user nginx;
613
- worker_processes <%= worker_processes %>;
614
- error_log /var/log/nginx/error.log;
615
- pid /run/nginx.pid;
616
-
617
- events {
618
- worker_connections <%= worker_connections %>;
619
- }
620
-
621
- http {
622
- include /etc/nginx/mime.types;
623
- default_type application/octet-stream;
624
-
625
- upstream app_servers {
626
- server 127.0.0.1:<%= port %>;
627
- }
628
-
629
- server {
630
- listen 80;
631
- server_name <%= domain_name %>;
632
-
633
- location / {
634
- proxy_pass http://app_servers;
635
- proxy_http_version 1.1;
636
- proxy_set_header Upgrade $http_upgrade;
637
- proxy_set_header Connection 'upgrade';
638
- proxy_set_header Host $host;
639
- proxy_cache_bypass $http_upgrade;
640
- }
641
- }
642
- }
643
- ```
644
-
645
- #### Using Templates
646
-
647
- ```ruby
648
- task :deploy_config do
649
- template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb",
650
- variables: { domain_name: "example.com", port: 3000, worker_processes: 4, worker_connections: 2048 }
651
- end
652
- ```
653
-
654
- #### Template Features
655
-
656
- - Full ERB syntax support
657
- - Variable substitution
658
- - Conditional logic
659
- - Loops and iterations
660
- - Ruby code execution
661
-
662
- ### Inventory Block
663
-
664
- Use the `inventory` block to organize host definitions:
665
-
666
- ```ruby
667
- inventory do
668
- host 'web01', user: 'ubuntu', ip: '10.0.0.1', key: '~/.ssh/id_rsa'
669
- host 'web02', user: 'ubuntu', ip: '10.0.0.2', key: '~/.ssh/id_rsa'
670
- host 'db01', user: 'root', ip: '10.0.0.3', key: '~/.ssh/id_rsa'
671
- end
672
- ```
673
-
674
- ## βš™οΈ Configuration
675
-
676
- ### Default Configuration
677
-
678
- Kdeploy uses sensible defaults that can be customized:
679
-
680
- - **Default Parallel Count**: 10 concurrent executions
681
- - **SSH Timeout**: 30 seconds
682
- - **Host Key Verification**: Disabled (for convenience, enable in production)
683
-
684
- ### Environment Variables
685
-
686
- You can override defaults using environment variables:
67
+ Run:
687
68
 
688
69
  ```bash
689
- export KDEPLOY_PARALLEL=5
690
- export KDEPLOY_SSH_TIMEOUT=60
691
- ```
692
-
693
- ### Configuration File
694
-
695
- For project-specific configuration, create a `.kdeploy.yml`:
696
-
697
- ```yaml
698
- parallel: 5
699
- ssh_timeout: 60
700
- verify_host_key: true
701
- retries: 2
702
- retry_delay: 1
703
- retry_on_nonzero: false
704
- step_timeout: 30
705
- sync_fast: false
706
- sync_parallel: 4
707
- retry_policy:
708
- run:
709
- retries: 2
710
- retry_on_exit_codes: [2, 255]
711
- upload:
712
- retries: 0
70
+ kdeploy execute deploy.rb deploy_web --dry-run # preview
71
+ kdeploy execute deploy.rb deploy_web # execute
713
72
  ```
714
73
 
715
- **Retry policy example file**: `retry_policy.example.json`
74
+ Common flags: `--limit web01`, `--parallel 5`, `--format json`, `--retries 3`. See [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md#fr-cli-04-execute-选鑹) for all options.
716
75
 
717
- ## πŸ”§ Advanced Usage
76
+ **Docker multi-host lab**: `cd docker/lab && docker compose --profile test up --build runner` ([docker/lab/README.md](docker/lab/README.md))
718
77
 
719
- ### Conditional Execution
720
-
721
- Use Ruby conditionals in your deployment files:
722
-
723
- ```ruby
724
- task :deploy do
725
- service "nginx", action: :stop if ENV['ENVIRONMENT'] == 'production'
726
-
727
- file "/etc/nginx/nginx.conf", source: "./config/nginx.conf"
728
-
729
- service "nginx", action: :start if ENV['ENVIRONMENT'] == 'production'
730
- end
731
- ```
78
+ ## Configuration
732
79
 
733
- ### Retry Policy Example
80
+ Place `.kdeploy.yml` in your project (walks up from CWD):
734
81
 
735
- You can override retry policy via file:
736
-
737
- ```bash
738
- kdeploy execute deploy.rb deploy_web --retry-policy-file ./retry_policy.example.json
739
- ```
740
-
741
- Example files: `retry_policy.example.json` / `retry_policy.example.yml`
742
-
743
- ### Looping Over Hosts
744
-
745
- ```ruby
746
- # Execute different commands based on host
747
- task :custom_setup do
748
- @hosts.each do |name, config|
749
- if name.start_with?('web')
750
- run "echo 'Web server: #{name}'"
751
- elsif name.start_with?('db')
752
- run "echo 'Database server: #{name}'"
753
- end
754
- end
755
- end
756
- ```
757
-
758
- ### Error Handling in Tasks
759
-
760
- ```ruby
761
- task :deploy do
762
- service "nginx", action: :stop
763
- file "/etc/nginx/nginx.conf", source: "./config/nginx.conf"
764
- run "nginx -t", sudo: true # run raises on invalid config
765
- service "nginx", action: :start
766
- end
767
- ```
768
-
769
- ### Using External Libraries
770
-
771
- ```ruby
772
- require 'yaml'
773
- require 'json'
774
-
775
- # Load configuration from external files
776
- config = YAML.load_file('config.yml')
777
-
778
- task :deploy do
779
- config['commands'].each do |cmd|
780
- run cmd
781
- end
782
- end
783
- ```
784
-
785
- ### Task Dependencies
786
-
787
- While Kdeploy doesn't have built-in task dependencies, you can achieve this with Ruby:
788
-
789
- ```ruby
790
- task :setup do
791
- run "echo 'Setting up...'"
792
- end
793
-
794
- task :deploy do
795
- # Manually call setup task
796
- self.class.kdeploy_tasks[:setup][:block].call.each do |cmd|
797
- case cmd[:type]
798
- when :run
799
- run cmd[:command]
800
- when :upload
801
- upload cmd[:source], cmd[:destination]
802
- end
803
- end
804
-
805
- run "echo 'Deploying...'"
806
- end
807
- ```
808
-
809
- ## 🚨 Error Handling
810
-
811
- ### Error Types
812
-
813
- Kdeploy provides specific error types for better debugging:
814
-
815
- - `Kdeploy::TaskNotFoundError` - Task not found
816
- - `Kdeploy::HostNotFoundError` - Host not found
817
- - `Kdeploy::SSHError` - SSH operation failed
818
- - `Kdeploy::SCPError` - SCP upload failed
819
- - `Kdeploy::TemplateError` - Template rendering failed
820
- - `Kdeploy::ConfigurationError` - Configuration error
821
- - `Kdeploy::FileNotFoundError` - File not found
822
-
823
- ### Error Output
824
-
825
- Errors are displayed with:
826
- - Red color coding
827
- - Detailed error messages
828
- - Host information
829
- - Original error context
830
-
831
- ### Handling Errors
832
-
833
- ```ruby
834
- # In your deployment file
835
- begin
836
- task :deploy do
837
- run "risky-command"
838
- end
839
- rescue Kdeploy::SSHError => e
840
- puts "SSH Error: #{e.message}"
841
- # Handle error
842
- end
843
- ```
844
-
845
- ## πŸ’‘ Best Practices
846
-
847
- ### 1. Use Heredoc for Multi-line Commands
848
-
849
- ```ruby
850
- # βœ… Good
851
- run <<~SHELL
852
- cd /var/www/app
853
- git pull origin main
854
- bundle install
855
- SHELL
856
-
857
- # ❌ Avoid
858
- run "cd /var/www/app && git pull origin main && bundle install"
859
- ```
860
-
861
- ### 2. Organize with Roles
862
-
863
- ```ruby
864
- # βœ… Good - Use roles for organization
865
- role :web, %w[web01 web02]
866
- role :db, %w[db01 db02]
867
-
868
- task :deploy_web, roles: :web do
869
- # ...
870
- end
871
-
872
- # ❌ Avoid - Hardcoding host names
873
- task :deploy do
874
- # Hard to maintain
875
- end
876
- ```
877
-
878
- ### 3. Use Templates for Dynamic Configuration
879
-
880
- ```ruby
881
- # βœ… Good - Use template resource
882
- template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb",
883
- variables: { domain_name: "example.com", port: 3000 }
884
-
885
- # ❌ Avoid - Hardcoding values
886
- run "echo 'server_name example.com;' > /etc/nginx/nginx.conf"
887
- ```
888
-
889
- ### 4. Validate Before Deployment
890
-
891
- ```ruby
892
- task :deploy do
893
- template "/etc/nginx/nginx.conf", source: "./config/nginx.conf.erb", variables: { port: 3000 }
894
- file "/etc/nginx/conf.d/app.conf", source: "./config/app.conf"
895
- run "nginx -t", sudo: true # run raises on invalid config
896
- service "nginx", action: :reload
897
- end
82
+ ```yaml
83
+ parallel: 10
84
+ ssh_timeout: 30
85
+ verify_host_key: never
86
+ retries: 0
898
87
  ```
899
88
 
900
- ### 5. Use Dry Run for Testing
89
+ Retry policy examples: `retry_policy.example.json`
901
90
 
902
- Always test with `--dry-run` before actual deployment:
91
+ ## Samples
903
92
 
904
93
  ```bash
94
+ cd samples
905
95
  kdeploy execute deploy.rb deploy_web --dry-run
906
96
  ```
907
97
 
908
- ### 6. Organize Files Properly
98
+ Includes Nginx, Node Exporter, directory sync; Vagrant available for local testing.
909
99
 
910
- ```
911
- project/
912
- β”œβ”€β”€ deploy.rb # Main deployment file
913
- β”œβ”€β”€ config/ # Configuration files
914
- β”‚ β”œβ”€β”€ nginx.conf.erb # Templates
915
- β”‚ └── app.conf # Static configs
916
- └── scripts/ # Helper scripts
917
- └── deploy.sh
918
- ```
919
-
920
- ### 7. Version Control
921
-
922
- - Commit `deploy.rb` and templates
923
- - Use `.gitignore` for sensitive files
924
- - Store secrets in environment variables
925
-
926
- ### 8. Parallel Execution
927
-
928
- Adjust parallel count based on your infrastructure:
100
+ ## Development
929
101
 
930
102
  ```bash
931
- # For many hosts, increase parallel count
932
- kdeploy execute deploy.rb deploy --parallel 20
933
-
934
- # For limited resources, decrease
935
- kdeploy execute deploy.rb deploy --parallel 3
936
- ```
937
-
938
- ## πŸ” Troubleshooting
939
-
940
- ### Common Issues
941
-
942
- #### SSH Authentication Failed
943
-
944
- **Problem**: `SSH authentication failed`
945
-
946
- **Solutions**:
947
- 1. Verify SSH key path is correct
948
- 2. Check key permissions: `chmod 600 ~/.ssh/id_rsa`
949
- 3. Test SSH connection manually: `ssh user@host`
950
- 4. Verify username and IP address
951
-
952
- #### Host Not Found
953
-
954
- **Problem**: `No hosts found for task`
955
-
956
- **Solutions**:
957
- 1. Verify host names in task match defined hosts
958
- 2. Check role definitions
959
- 3. Verify `--limit` option if used
960
-
961
- #### Command Execution Failed
962
-
963
- **Problem**: Commands fail on remote server
964
-
965
- **Solutions**:
966
- 1. Test commands manually on target server
967
- 2. Check user permissions (may need sudo)
968
- 3. Verify command syntax
969
- 4. Check server logs
970
-
971
- #### Template Rendering Error
972
-
973
- **Problem**: Template upload fails
974
-
975
- **Solutions**:
976
- 1. Verify ERB syntax in template
977
- 2. Check all required variables are provided
978
- 3. Validate template file exists
979
- 4. Test template rendering locally
980
-
981
- #### Connection Timeout
982
-
983
- **Problem**: SSH connection times out
984
-
985
- **Solutions**:
986
- 1. Check network connectivity
987
- 2. Verify firewall rules
988
- 3. Increase timeout in configuration
989
- 4. Check SSH service on target server
990
-
991
- ### Debug Mode
992
-
993
- Enable verbose output by checking the execution output. Kdeploy provides detailed information about:
994
- - Task execution status
995
- - Command output
996
- - Error messages
997
- - Execution duration
998
-
999
- ### Getting Help
1000
-
1001
- - Check [GitHub Issues](https://github.com/kevin197011/kdeploy/issues)
1002
- - Review example projects
1003
- - Read the documentation
1004
- - Ask in discussions
1005
-
1006
- ## πŸ—οΈ Architecture
1007
-
1008
- ### Core Components
1009
-
1010
- - **CLI** (`cli.rb`): Command-line interface using Thor
1011
- - **DSL** (`dsl.rb`): Domain-specific language for task definition
1012
- - **Executor** (`executor.rb`): SSH/SCP execution engine
1013
- - **Runner** (`runner.rb`): Concurrent task execution coordinator
1014
- - **CommandExecutor** (`command_executor.rb`): Individual command execution
1015
- - **Template** (`template.rb`): ERB template rendering
1016
- - **Output** (`output.rb`): Output formatting and display
1017
- - **Configuration** (`configuration.rb`): Configuration management
1018
- - **Errors** (`errors.rb`): Custom error types
1019
-
1020
- ### Execution Flow
1021
-
1022
- 1. **Parse Configuration**: Load and parse `deploy.rb`
1023
- 2. **Resolve Hosts**: Determine target hosts based on task definition
1024
- 3. **Execute Concurrently**: Run tasks in parallel across hosts, executing commands in order per host
1025
- 4. **Collect Results**: Gather execution results and status
1026
- 5. **Display Output**: Format and display results to user
1027
-
1028
- ### Concurrency Model
1029
-
1030
- Kdeploy uses `concurrent-ruby` with a fixed thread pool:
1031
- - Default: 10 concurrent executions
1032
- - Configurable via `--parallel` option
1033
- - Thread-safe result collection
1034
- - Automatic resource cleanup
1035
-
1036
- ## πŸ”§ Development
1037
-
1038
- ### Setup Development Environment
1039
-
1040
- ```bash
1041
- # Clone repository
1042
- git clone https://github.com/kevin197011/kdeploy.git
1043
- cd kdeploy
1044
-
1045
- # Install dependencies
103
+ git clone git@github.com:kevin197011/kdeploy.git && cd kdeploy
1046
104
  bundle install
1047
-
1048
- # Run tests
1049
105
  bundle exec rspec
1050
-
1051
- # Run console
1052
- bin/console
1053
- ```
1054
-
1055
- ### Project Structure
1056
-
1057
- ```
1058
- kdeploy/
1059
- β”œβ”€β”€ lib/
1060
- β”‚ └── kdeploy/
1061
- β”‚ β”œβ”€β”€ cli.rb # CLI interface
1062
- β”‚ β”œβ”€β”€ dsl.rb # DSL definition
1063
- β”‚ β”œβ”€β”€ executor.rb # SSH/SCP executor
1064
- β”‚ β”œβ”€β”€ runner.rb # Task runner
1065
- β”‚ β”œβ”€β”€ command_executor.rb # Command executor
1066
- β”‚ β”œβ”€β”€ template.rb # Template handler
1067
- β”‚ β”œβ”€β”€ output.rb # Output interface
1068
- β”‚ β”œβ”€β”€ configuration.rb # Configuration
1069
- β”‚ β”œβ”€β”€ errors.rb # Error types
1070
- β”‚ └── ...
1071
- β”œβ”€β”€ spec/ # Tests
1072
- β”œβ”€β”€ exe/ # Executables
1073
- β”œβ”€β”€ sample/ # Example projects
1074
- └── README.md # This file
1075
- ```
1076
-
1077
- ### Running Tests
1078
-
1079
- ```bash
1080
- # Run all tests
1081
- bundle exec rspec
1082
-
1083
- # Run specific test file
1084
- bundle exec rspec spec/kdeploy_spec.rb
1085
-
1086
- # Run with coverage
1087
- COVERAGE=true bundle exec rspec
1088
- ```
1089
-
1090
- ### Building the Gem
1091
-
1092
- ```bash
1093
- # Build gem
1094
- gem build kdeploy.gemspec
1095
-
1096
- # Install locally
1097
- gem install ./kdeploy-*.gem
1098
- ```
1099
-
1100
- ### Code Style
1101
-
1102
- The project uses RuboCop for code style:
1103
-
1104
- ```bash
1105
- # Check style
1106
106
  bundle exec rubocop
1107
-
1108
- # Auto-fix issues
1109
- bundle exec rubocop -a
1110
- ```
1111
-
1112
- ## 🀝 Contributing
1113
-
1114
- Contributions are welcome! Please follow these steps:
1115
-
1116
- 1. **Fork the repository**
1117
- 2. **Create a feature branch**: `git checkout -b feature/my-new-feature`
1118
- 3. **Make your changes**: Follow the code style and add tests
1119
- 4. **Commit your changes**: Use conventional commit messages
1120
- 5. **Push to the branch**: `git push origin feature/my-new-feature`
1121
- 6. **Create a Pull Request**: Provide a clear description of changes
1122
-
1123
- ### Contribution Guidelines
1124
-
1125
- - Follow existing code style
1126
- - Add tests for new features
1127
- - Update documentation
1128
- - Ensure all tests pass
1129
- - Follow conventional commit format
1130
-
1131
- ### Commit Message Format
1132
-
1133
- Follow [Conventional Commits](https://www.conventionalcommits.org/):
1134
-
1135
- ```
1136
- <type>(<scope>): <subject>
1137
-
1138
- <body>
1139
-
1140
- <footer>
1141
- ```
1142
-
1143
- Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
1144
-
1145
- ## πŸ“š Examples
1146
-
1147
- ### Example Project
1148
-
1149
- The [sample/](sample/) directory in this repo provides a complete example with Nginx, Node Exporter, directory sync tasks, and Vagrant support for local testing:
1150
-
1151
- ```bash
1152
- cd sample
1153
- vagrant up
1154
- kdeploy execute deploy.rb deploy_web --dry-run # Preview
1155
- kdeploy execute deploy.rb deploy_web # Execute
1156
- ```
1157
-
1158
- ### Common Deployment Scenarios
1159
-
1160
- #### Web Application Deployment
1161
-
1162
- ```ruby
1163
- host "web01", user: "deploy", ip: "10.0.0.1", key: "~/.ssh/id_rsa"
1164
- role :web, %w[web01]
1165
-
1166
- task :deploy_app, roles: :web do
1167
- run <<~SHELL
1168
- cd /var/www/app
1169
- git pull origin main
1170
- bundle install
1171
- rake db:migrate
1172
- sudo systemctl restart puma
1173
- SHELL
1174
- end
1175
107
  ```
1176
108
 
1177
- #### Database Backup
1178
-
1179
- ```ruby
1180
- host "db01", user: "postgres", ip: "10.0.0.10", key: "~/.ssh/id_rsa"
1181
- role :db, %w[db01]
1182
-
1183
- task :backup, roles: :db do
1184
- run <<~SHELL
1185
- pg_dump mydb > /tmp/backup_$(date +%Y%m%d).sql
1186
- gzip /tmp/backup_*.sql
1187
- aws s3 cp /tmp/backup_*.sql.gz s3://backups/
1188
- rm /tmp/backup_*.sql.gz
1189
- SHELL
1190
- end
1191
- ```
1192
-
1193
- #### Configuration Management
1194
-
1195
- ```ruby
1196
- task :update_config, roles: :web do
1197
- template "/etc/app/config.yml", source: "./config/app.yml.erb",
1198
- variables: { environment: "production", database_url: ENV['DATABASE_URL'], redis_url: ENV['REDIS_URL'] }
1199
- service "app", action: :reload
1200
- end
1201
- ```
1202
-
1203
- #### Directory Sync Deployment
1204
-
1205
- ```ruby
1206
- task :deploy_app, roles: :web do
1207
- sync "./app", "/var/www/app",
1208
- ignore: [".git", "*.log", "node_modules", ".env.local", "*.tmp"],
1209
- delete: true,
1210
- fast: true # prefer rsync when available
1211
- sync "./config", "/etc/app", exclude: ["*.example", "*.bak"]
1212
- service "app", action: :restart
1213
- end
1214
- ```
1215
-
1216
- ## πŸ“ License
1217
-
1218
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
109
+ Requirements and acceptance criteria: [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md)
1219
110
 
1220
- ## πŸ”— Links
111
+ ## Contributing
1221
112
 
1222
- - **GitHub**: https://github.com/kevin197011/kdeploy
1223
- - **RubyGems**: https://rubygems.org/gems/kdeploy
1224
- - **Issues**: https://github.com/kevin197011/kdeploy/issues
1225
- - **Sample**: [sample/](sample/) directory (includes Vagrant config)
113
+ Fork β†’ feature branch β†’ tests pass β†’ PR. Use [Conventional Commits](https://www.conventionalcommits.org/).
1226
114
 
1227
- ## πŸ™ Acknowledgments
115
+ ## License
1228
116
 
1229
- - Built with [Thor](https://github.com/rails/thor) for CLI
1230
- - Uses [net-ssh](https://github.com/net-ssh/net-ssh) for SSH operations
1231
- - Powered by [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby) for concurrency
117
+ [MIT](https://opensource.org/licenses/MIT)
1232
118
 
1233
- ---
119
+ ## Links
1234
120
 
1235
- **Made with ❀️ for the DevOps community**
121
+ - [GitHub](https://github.com/kevin197011/kdeploy) Β· [RubyGems](https://rubygems.org/gems/kdeploy) Β· [Issues](https://github.com/kevin197011/kdeploy/issues)