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