kamal 2.11.0 → 2.12.0
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/lib/kamal/cli/accessory.rb +48 -39
- data/lib/kamal/cli/app.rb +57 -48
- data/lib/kamal/cli/base.rb +99 -11
- data/lib/kamal/cli/build.rb +9 -6
- data/lib/kamal/cli/lock.rb +5 -16
- data/lib/kamal/cli/main.rb +59 -53
- data/lib/kamal/cli/proxy.rb +9 -9
- data/lib/kamal/cli/prune.rb +3 -3
- data/lib/kamal/cli/server.rb +24 -15
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/post-deploy.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-build.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-proxy-reboot.sample +1 -1
- data/lib/kamal/cli/templates/secrets +4 -0
- data/lib/kamal/commander.rb +54 -1
- data/lib/kamal/commands/accessory.rb +2 -2
- data/lib/kamal/commands/app/logging.rb +1 -1
- data/lib/kamal/commands/app.rb +1 -1
- data/lib/kamal/commands/builder/clone.rb +2 -1
- data/lib/kamal/configuration/accessory.rb +13 -5
- data/lib/kamal/configuration/docs/configuration.yml +18 -3
- data/lib/kamal/configuration/docs/env.yml +6 -4
- data/lib/kamal/configuration/docs/output.yml +25 -0
- data/lib/kamal/configuration/docs/role.yml +1 -0
- data/lib/kamal/configuration/docs/ssh.yml +8 -0
- data/lib/kamal/configuration/output.rb +34 -0
- data/lib/kamal/configuration/proxy/run.rb +9 -0
- data/lib/kamal/configuration/role.rb +18 -6
- data/lib/kamal/configuration/ssh.rb +5 -1
- data/lib/kamal/configuration/validator.rb +14 -2
- data/lib/kamal/configuration.rb +6 -1
- data/lib/kamal/git.rb +1 -1
- data/lib/kamal/otel_shipper.rb +176 -0
- data/lib/kamal/output/base_logger.rb +29 -0
- data/lib/kamal/output/file_logger.rb +51 -0
- data/lib/kamal/output/formatter.rb +36 -0
- data/lib/kamal/output/otel_logger.rb +70 -0
- data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +10 -2
- data/lib/kamal/secrets/adapters/passbolt.rb +1 -1
- data/lib/kamal/secrets.rb +1 -1
- data/lib/kamal/sshkit_with_ext.rb +9 -4
- data/lib/kamal/version.rb +1 -1
- metadata +9 -2
data/lib/kamal/cli/main.rb
CHANGED
|
@@ -4,7 +4,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
|
4
4
|
option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
|
|
5
5
|
def setup
|
|
6
6
|
print_runtime do
|
|
7
|
-
|
|
7
|
+
modify(lock: true) do
|
|
8
8
|
invoke_options = deploy_options
|
|
9
9
|
|
|
10
10
|
say "Ensure Docker is installed...", :magenta
|
|
@@ -19,88 +19,94 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
|
19
19
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
|
20
20
|
option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
|
|
21
21
|
def deploy(boot_accessories: false)
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
modify do
|
|
23
|
+
runtime = print_runtime do
|
|
24
|
+
invoke_options = deploy_options
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
if options[:skip_push]
|
|
27
|
+
say "Pull app image...", :magenta
|
|
28
|
+
invoke "kamal:cli:build:pull", [], invoke_options
|
|
29
|
+
else
|
|
30
|
+
say "Build and push app image...", :magenta
|
|
31
|
+
invoke "kamal:cli:build:deliver", [], invoke_options
|
|
32
|
+
end
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
modify(lock: true) do
|
|
35
|
+
run_hook "pre-deploy", secrets: true
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
say "Ensure kamal-proxy is running...", :magenta
|
|
38
|
+
invoke "kamal:cli:proxy:boot", [], invoke_options
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options if boot_accessories
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
say "Detect stale containers...", :magenta
|
|
43
|
+
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
invoke "kamal:cli:app:boot", [], invoke_options
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
say "Prune old containers and images...", :magenta
|
|
48
|
+
invoke "kamal:cli:prune:all", [], invoke_options
|
|
49
|
+
end
|
|
48
50
|
end
|
|
49
|
-
end
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
|
|
53
|
+
end
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
desc "redeploy", "Deploy app to servers without bootstrapping servers, starting kamal-proxy and pruning"
|
|
55
57
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
|
56
58
|
option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
|
|
57
59
|
def redeploy
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
modify do
|
|
61
|
+
runtime = print_runtime do
|
|
62
|
+
invoke_options = deploy_options
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
if options[:skip_push]
|
|
65
|
+
say "Pull app image...", :magenta
|
|
66
|
+
invoke "kamal:cli:build:pull", [], invoke_options
|
|
67
|
+
else
|
|
68
|
+
say "Build and push app image...", :magenta
|
|
69
|
+
invoke "kamal:cli:build:deliver", [], invoke_options
|
|
70
|
+
end
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
modify(lock: true) do
|
|
73
|
+
run_hook "pre-deploy", secrets: true
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
say "Detect stale containers...", :magenta
|
|
76
|
+
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
invoke "kamal:cli:app:boot", [], invoke_options
|
|
79
|
+
end
|
|
76
80
|
end
|
|
77
|
-
end
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
|
|
83
|
+
end
|
|
80
84
|
end
|
|
81
85
|
|
|
82
86
|
desc "rollback [VERSION]", "Rollback app to VERSION"
|
|
83
87
|
def rollback(version)
|
|
84
88
|
rolled_back = false
|
|
85
|
-
runtime = print_runtime do
|
|
86
|
-
with_lock do
|
|
87
|
-
invoke_options = deploy_options
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
modify do
|
|
91
|
+
runtime = print_runtime do
|
|
92
|
+
modify(lock: true) do
|
|
93
|
+
invoke_options = deploy_options
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
run_hook "pre-deploy", secrets: true
|
|
95
|
+
KAMAL.config.version = version
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
if container_available?(version)
|
|
98
|
+
run_hook "pre-deploy", secrets: true
|
|
99
|
+
|
|
100
|
+
invoke "kamal:cli:app:boot", [], invoke_options.merge(version: version)
|
|
101
|
+
rolled_back = true
|
|
102
|
+
else
|
|
103
|
+
say "The app version '#{version}' is not available as a container (use 'kamal app containers' for available versions)", :red
|
|
104
|
+
end
|
|
99
105
|
end
|
|
100
106
|
end
|
|
101
|
-
end
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s if rolled_back
|
|
109
|
+
end
|
|
104
110
|
end
|
|
105
111
|
|
|
106
112
|
desc "details", "Show details about all containers"
|
|
@@ -182,7 +188,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
|
182
188
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
|
183
189
|
def remove
|
|
184
190
|
confirming "This will remove all containers and images. Are you sure?" do
|
|
185
|
-
|
|
191
|
+
modify(lock: true) do
|
|
186
192
|
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
|
187
193
|
invoke "kamal:cli:proxy:remove", [], options.without(:confirmed)
|
|
188
194
|
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
|
@@ -196,7 +202,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
|
196
202
|
option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time"
|
|
197
203
|
def upgrade
|
|
198
204
|
confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
|
|
199
|
-
|
|
205
|
+
modify(lock: true) do
|
|
200
206
|
if options[:rolling]
|
|
201
207
|
KAMAL.hosts.each do |host|
|
|
202
208
|
KAMAL.with_specific_hosts(host) do
|
data/lib/kamal/cli/proxy.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
2
2
|
desc "boot", "Boot proxy on servers"
|
|
3
3
|
def boot
|
|
4
|
-
|
|
4
|
+
modify(lock: true) do
|
|
5
5
|
on(KAMAL.hosts) do |host|
|
|
6
6
|
execute *KAMAL.docker.create_network
|
|
7
7
|
rescue SSHKit::Command::Failed => e
|
|
@@ -108,7 +108,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
108
108
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
|
109
109
|
def reboot
|
|
110
110
|
confirming "This will cause a brief outage on each host. Are you sure?" do
|
|
111
|
-
|
|
111
|
+
modify(lock: true) do
|
|
112
112
|
host_groups = options[:rolling] ? KAMAL.proxy_hosts : [ KAMAL.proxy_hosts ]
|
|
113
113
|
host_groups.each do |hosts|
|
|
114
114
|
host_list = Array(hosts).join(",")
|
|
@@ -174,7 +174,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
174
174
|
|
|
175
175
|
desc "start", "Start existing proxy container on servers"
|
|
176
176
|
def start
|
|
177
|
-
|
|
177
|
+
modify(lock: true) do
|
|
178
178
|
on(KAMAL.proxy_hosts) do |host|
|
|
179
179
|
execute *KAMAL.auditor.record("Started proxy"), verbosity: :debug
|
|
180
180
|
execute *KAMAL.proxy(host).start
|
|
@@ -184,7 +184,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
184
184
|
|
|
185
185
|
desc "stop", "Stop existing proxy container on servers"
|
|
186
186
|
def stop
|
|
187
|
-
|
|
187
|
+
modify(lock: true) do
|
|
188
188
|
on(KAMAL.proxy_hosts) do |host|
|
|
189
189
|
execute *KAMAL.auditor.record("Stopped proxy"), verbosity: :debug
|
|
190
190
|
execute *KAMAL.proxy(host).stop, raise_on_non_zero_exit: false
|
|
@@ -194,7 +194,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
194
194
|
|
|
195
195
|
desc "restart", "Restart existing proxy container on servers"
|
|
196
196
|
def restart
|
|
197
|
-
|
|
197
|
+
modify(lock: true) do
|
|
198
198
|
stop
|
|
199
199
|
start
|
|
200
200
|
end
|
|
@@ -236,7 +236,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
236
236
|
desc "remove", "Remove proxy container and image from servers"
|
|
237
237
|
option :force, type: :boolean, default: false, desc: "Force removing proxy when apps are still installed"
|
|
238
238
|
def remove
|
|
239
|
-
|
|
239
|
+
modify(lock: true) do
|
|
240
240
|
if removal_allowed?(options[:force])
|
|
241
241
|
stop
|
|
242
242
|
remove_container
|
|
@@ -248,7 +248,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
248
248
|
|
|
249
249
|
desc "remove_container", "Remove proxy container from servers", hide: true
|
|
250
250
|
def remove_container
|
|
251
|
-
|
|
251
|
+
modify(lock: true) do
|
|
252
252
|
on(KAMAL.proxy_hosts) do
|
|
253
253
|
execute *KAMAL.auditor.record("Removed proxy container"), verbosity: :debug
|
|
254
254
|
execute *KAMAL.proxy(host).remove_container
|
|
@@ -258,7 +258,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
258
258
|
|
|
259
259
|
desc "remove_image", "Remove proxy image from servers", hide: true
|
|
260
260
|
def remove_image
|
|
261
|
-
|
|
261
|
+
modify(lock: true) do
|
|
262
262
|
on(KAMAL.proxy_hosts) do
|
|
263
263
|
execute *KAMAL.auditor.record("Removed proxy image"), verbosity: :debug
|
|
264
264
|
execute *KAMAL.proxy(host).remove_image
|
|
@@ -268,7 +268,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
268
268
|
|
|
269
269
|
desc "remove_proxy_directory", "Remove the proxy directory from servers", hide: true
|
|
270
270
|
def remove_proxy_directory
|
|
271
|
-
|
|
271
|
+
modify(lock: true) do
|
|
272
272
|
on(KAMAL.proxy_hosts) do
|
|
273
273
|
execute *KAMAL.proxy(host).remove_proxy_directory, raise_on_non_zero_exit: false
|
|
274
274
|
end
|
data/lib/kamal/cli/prune.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class Kamal::Cli::Prune < Kamal::Cli::Base
|
|
2
2
|
desc "all", "Prune unused images and stopped containers"
|
|
3
3
|
def all
|
|
4
|
-
|
|
4
|
+
modify(lock: true) do
|
|
5
5
|
containers
|
|
6
6
|
images
|
|
7
7
|
end
|
|
@@ -9,7 +9,7 @@ class Kamal::Cli::Prune < Kamal::Cli::Base
|
|
|
9
9
|
|
|
10
10
|
desc "images", "Prune unused images"
|
|
11
11
|
def images
|
|
12
|
-
|
|
12
|
+
modify(lock: true) do
|
|
13
13
|
on(KAMAL.hosts) do
|
|
14
14
|
execute *KAMAL.auditor.record("Pruned images"), verbosity: :debug
|
|
15
15
|
execute *KAMAL.prune.dangling_images
|
|
@@ -24,7 +24,7 @@ class Kamal::Cli::Prune < Kamal::Cli::Base
|
|
|
24
24
|
retain = options.fetch(:retain, KAMAL.config.retain_containers)
|
|
25
25
|
raise "retain must be at least 1" if retain < 1
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
modify(lock: true) do
|
|
28
28
|
on(KAMAL.hosts) do
|
|
29
29
|
execute *KAMAL.auditor.record("Pruned containers"), verbosity: :debug
|
|
30
30
|
execute *KAMAL.prune.app_containers(retain: retain)
|
data/lib/kamal/cli/server.rb
CHANGED
|
@@ -1,33 +1,42 @@
|
|
|
1
1
|
class Kamal::Cli::Server < Kamal::Cli::Base
|
|
2
2
|
desc "exec", "Run a custom command on the server (use --help to show options)"
|
|
3
3
|
option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)"
|
|
4
|
+
option :raw, type: :boolean, default: false, desc: "Output raw, unmodified stdout"
|
|
4
5
|
def exec(*cmd)
|
|
5
|
-
|
|
6
|
+
raw = options[:raw]
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
if raw && options[:interactive]
|
|
9
|
+
raise ArgumentError, "Raw is not compatible with interactive"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
with_raw_output(raw) do
|
|
13
|
+
pre_connect_if_required
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
cmd = Kamal::Utils.join_commands(cmd)
|
|
16
|
+
hosts = KAMAL.hosts
|
|
17
|
+
quiet = options[:quiet]
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
case
|
|
20
|
+
when options[:interactive]
|
|
21
|
+
host = KAMAL.primary_host
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
else
|
|
19
|
-
say "Running '#{cmd}' on #{hosts.join(', ')}...", :magenta
|
|
23
|
+
say "Running '#{cmd}' on #{host} interactively...", :magenta
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
run_locally { exec KAMAL.server.run_over_ssh(cmd, host: host) }
|
|
26
|
+
else
|
|
27
|
+
say "Running '#{cmd}' on #{hosts.join(', ')}...", :magenta
|
|
28
|
+
|
|
29
|
+
on(hosts) do |host|
|
|
30
|
+
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on #{host}"), verbosity: :debug
|
|
31
|
+
puts_by_host host, capture_with_info(cmd, strip: !raw), quiet: quiet, raw: raw
|
|
32
|
+
end
|
|
24
33
|
end
|
|
25
34
|
end
|
|
26
35
|
end
|
|
27
36
|
|
|
28
37
|
desc "bootstrap", "Set up Docker to run Kamal apps"
|
|
29
38
|
def bootstrap
|
|
30
|
-
|
|
39
|
+
modify(lock: true) do
|
|
31
40
|
missing = []
|
|
32
41
|
|
|
33
42
|
on(KAMAL.hosts) do |host|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
|
|
2
2
|
# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
|
|
3
3
|
# password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.
|
|
4
|
+
#
|
|
5
|
+
# When deploying with destinations, shared secrets can go in .kamal/secrets-common and
|
|
6
|
+
# destination-specific secrets in .kamal/secrets.<destination>. This .kamal/secrets file is used
|
|
7
|
+
# only when no destination is selected.
|
|
4
8
|
|
|
5
9
|
# Option 1: Read secrets from the environment
|
|
6
10
|
# KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
|
data/lib/kamal/commander.rb
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
require "active_support/core_ext/enumerable"
|
|
2
2
|
require "active_support/core_ext/module/delegation"
|
|
3
3
|
require "active_support/core_ext/object/blank"
|
|
4
|
+
require "active_support/broadcast_logger"
|
|
5
|
+
require "active_support/notifications"
|
|
4
6
|
|
|
5
7
|
class Kamal::Commander
|
|
6
|
-
attr_accessor :verbosity, :holding_lock, :connected
|
|
8
|
+
attr_accessor :verbosity, :holding_lock, :connected, :logging, :lock_wait, :lock_wait_timeout, :lock_wait_interval
|
|
7
9
|
attr_reader :specific_roles, :specific_hosts
|
|
8
10
|
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :app_hosts, :proxy_hosts, :accessory_hosts, to: :specifics
|
|
9
11
|
|
|
@@ -15,8 +17,14 @@ class Kamal::Commander
|
|
|
15
17
|
self.verbosity = :info
|
|
16
18
|
self.holding_lock = ENV["KAMAL_LOCK"] == "true"
|
|
17
19
|
self.connected = false
|
|
20
|
+
self.logging = false
|
|
21
|
+
self.lock_wait = false
|
|
22
|
+
self.lock_wait_timeout = 900
|
|
23
|
+
self.lock_wait_interval = 15
|
|
24
|
+
@modify_depth = 0
|
|
18
25
|
@specifics = @specific_roles = @specific_hosts = nil
|
|
19
26
|
@config = @config_kwargs = nil
|
|
27
|
+
@output_logger = nil
|
|
20
28
|
@commands = {}
|
|
21
29
|
end
|
|
22
30
|
|
|
@@ -142,6 +150,22 @@ class Kamal::Commander
|
|
|
142
150
|
SSHKit.config.output_verbosity = old_level
|
|
143
151
|
end
|
|
144
152
|
|
|
153
|
+
def modify(command:, subcommand:)
|
|
154
|
+
@logging = true
|
|
155
|
+
if modify_started
|
|
156
|
+
ActiveSupport::Notifications.instrument("modify.kamal",
|
|
157
|
+
command: command, subcommand: subcommand, destination: config.destination, hosts: hosts) { yield }
|
|
158
|
+
else
|
|
159
|
+
yield
|
|
160
|
+
end
|
|
161
|
+
ensure
|
|
162
|
+
output_logger.close if modify_finished
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def log(line)
|
|
166
|
+
output_logger << "#{line}\n" if logging
|
|
167
|
+
end
|
|
168
|
+
|
|
145
169
|
def holding_lock?
|
|
146
170
|
self.holding_lock
|
|
147
171
|
end
|
|
@@ -151,6 +175,20 @@ class Kamal::Commander
|
|
|
151
175
|
end
|
|
152
176
|
|
|
153
177
|
private
|
|
178
|
+
def output_logger
|
|
179
|
+
@output_logger ||= ActiveSupport::BroadcastLogger.new
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def modify_started
|
|
183
|
+
@modify_depth += 1
|
|
184
|
+
@modify_depth == 1
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def modify_finished
|
|
188
|
+
@modify_depth -= 1
|
|
189
|
+
@modify_depth == 0
|
|
190
|
+
end
|
|
191
|
+
|
|
154
192
|
# Lazy setup of SSHKit
|
|
155
193
|
def configure_sshkit_with(config)
|
|
156
194
|
SSHKit::Backend::Netssh.pool.idle_timeout = config.sshkit.pool_idle_timeout
|
|
@@ -161,6 +199,21 @@ class Kamal::Commander
|
|
|
161
199
|
end
|
|
162
200
|
SSHKit.config.command_map[:docker] = "docker" # No need to use /usr/bin/env, just clogs up the logs
|
|
163
201
|
SSHKit.config.output_verbosity = verbosity
|
|
202
|
+
|
|
203
|
+
configure_output_with(config)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def configure_output_with(config)
|
|
207
|
+
return unless config.output.enabled?
|
|
208
|
+
|
|
209
|
+
config.output.loggers.each { |logger| output_logger.broadcast_to(logger) }
|
|
210
|
+
|
|
211
|
+
SSHKit.config.output = Kamal::Output::Formatter.new($stdout, output_logger)
|
|
212
|
+
|
|
213
|
+
at_exit { @output_logger&.close }
|
|
214
|
+
rescue => e
|
|
215
|
+
$stderr.puts "Output logger setup failed: #{e.class}: #{e.message}"
|
|
216
|
+
$stderr.puts e.backtrace.join("\n") if ENV["VERBOSE"]
|
|
164
217
|
end
|
|
165
218
|
|
|
166
219
|
def specifics
|
|
@@ -4,7 +4,7 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
|
4
4
|
attr_reader :accessory_config
|
|
5
5
|
delegate :service_name, :image, :hosts, :port, :files, :directories, :cmd,
|
|
6
6
|
:network_args, :publish_args, :env_args, :volume_args, :label_args, :option_args,
|
|
7
|
-
:secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?, :registry,
|
|
7
|
+
:restart_policy, :secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?, :registry,
|
|
8
8
|
to: :accessory_config
|
|
9
9
|
|
|
10
10
|
def initialize(config, name:)
|
|
@@ -16,7 +16,7 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
|
16
16
|
docker :run,
|
|
17
17
|
"--name", service_name,
|
|
18
18
|
"--detach",
|
|
19
|
-
"--restart",
|
|
19
|
+
"--restart", restart_policy,
|
|
20
20
|
*network_args,
|
|
21
21
|
*config.logging_args,
|
|
22
22
|
*publish_args,
|
|
@@ -21,7 +21,7 @@ module Kamal::Commands::App::Logging
|
|
|
21
21
|
def container_id_command(container_id)
|
|
22
22
|
case container_id
|
|
23
23
|
when Array then container_id
|
|
24
|
-
when String, Symbol then "echo #{container_id}"
|
|
24
|
+
when String, Symbol then shell([ "echo #{container_id}" ])
|
|
25
25
|
else current_running_container_id
|
|
26
26
|
end
|
|
27
27
|
end
|
data/lib/kamal/commands/app.rb
CHANGED
|
@@ -16,7 +16,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
|
16
16
|
def run(hostname: nil)
|
|
17
17
|
docker :run,
|
|
18
18
|
"--detach",
|
|
19
|
-
"--restart
|
|
19
|
+
"--restart", role.restart_policy,
|
|
20
20
|
"--name", container_name,
|
|
21
21
|
"--network", "kamal",
|
|
22
22
|
*([ "--hostname", hostname ] if hostname),
|
|
@@ -9,7 +9,8 @@ module Kamal::Commands::Builder::Clone
|
|
|
9
9
|
git(:fetch, :origin, path: escaped_build_directory),
|
|
10
10
|
git(:reset, "--hard", Kamal::Git.revision, path: escaped_build_directory),
|
|
11
11
|
git(:clean, "-fdx", path: escaped_build_directory),
|
|
12
|
-
git(:submodule, :update, "--init", path: escaped_build_directory)
|
|
12
|
+
git(:submodule, :update, "--init", path: escaped_build_directory),
|
|
13
|
+
git(:gc, "--auto", "--quiet", path: escaped_build_directory)
|
|
13
14
|
]
|
|
14
15
|
end
|
|
15
16
|
|
|
@@ -102,11 +102,11 @@ class Kamal::Configuration::Accessory
|
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
def option_args
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
optionize docker_options.reject { |key, _| key.to_s == "restart" }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def restart_policy
|
|
109
|
+
restart_policy_option || "unless-stopped"
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
def cmd
|
|
@@ -173,6 +173,14 @@ class Kamal::Configuration::Accessory
|
|
|
173
173
|
accessory_config["volumes"] || []
|
|
174
174
|
end
|
|
175
175
|
|
|
176
|
+
def docker_options
|
|
177
|
+
accessory_config["options"] || {}
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def restart_policy_option
|
|
181
|
+
docker_options.find { |key, _| key.to_s == "restart" }&.last
|
|
182
|
+
end
|
|
183
|
+
|
|
176
184
|
def path_volumes(paths)
|
|
177
185
|
paths.map do |local, config|
|
|
178
186
|
Kamal::Configuration::Volume.new \
|
|
@@ -99,7 +99,6 @@ hooks_path: /user_home/kamal/hooks
|
|
|
99
99
|
#
|
|
100
100
|
# Global setting for all hooks:
|
|
101
101
|
hooks_output: :verbose
|
|
102
|
-
|
|
103
102
|
# Or per-hook settings:
|
|
104
103
|
hooks_output:
|
|
105
104
|
pre-deploy: :verbose
|
|
@@ -108,13 +107,16 @@ hooks_output:
|
|
|
108
107
|
# Secrets path
|
|
109
108
|
#
|
|
110
109
|
# Path to secrets, defaults to `.kamal/secrets`.
|
|
111
|
-
# Kamal
|
|
110
|
+
# Kamal looks for `<secrets_path>-common` first and then `<secrets_path>`.
|
|
111
|
+
# When using destinations, it instead looks for `<secrets_path>-common` first and then
|
|
112
|
+
# `<secrets_path>.<destination>`. Later files override earlier ones.
|
|
112
113
|
secrets_path: /user_home/kamal/secrets
|
|
113
114
|
|
|
114
115
|
# Error pages
|
|
115
116
|
#
|
|
116
117
|
# A directory relative to the app root to find error pages for the proxy to serve.
|
|
117
|
-
#
|
|
118
|
+
# Name each page after the HTTP status code it serves, e.g. 404.html, 500.html,
|
|
119
|
+
# 502.html, 503.html, and 504.html.
|
|
118
120
|
error_pages_path: public
|
|
119
121
|
|
|
120
122
|
# Require destinations
|
|
@@ -159,6 +161,13 @@ deploy_timeout: 10
|
|
|
159
161
|
# How long to wait for a container to drain, default 30:
|
|
160
162
|
drain_timeout: 10
|
|
161
163
|
|
|
164
|
+
# Stop timeout
|
|
165
|
+
#
|
|
166
|
+
# How long to wait for a container to stop after SIGTERM, default is
|
|
167
|
+
# the drain_timeout for non-proxied roles and 10s (Docker default) for proxied roles.
|
|
168
|
+
# Can be overridden per role:
|
|
169
|
+
stop_timeout: 30
|
|
170
|
+
|
|
162
171
|
# Run directory
|
|
163
172
|
#
|
|
164
173
|
# Directory to store kamal runtime files in on the host, default `.kamal`:
|
|
@@ -206,6 +215,12 @@ boot:
|
|
|
206
215
|
logging:
|
|
207
216
|
...
|
|
208
217
|
|
|
218
|
+
# Output
|
|
219
|
+
#
|
|
220
|
+
# Configure output loggers (OTel, file), see kamal docs output:
|
|
221
|
+
output:
|
|
222
|
+
...
|
|
223
|
+
|
|
209
224
|
# Aliases
|
|
210
225
|
#
|
|
211
226
|
# Alias configuration, see kamal docs alias:
|
|
@@ -14,12 +14,14 @@ env:
|
|
|
14
14
|
|
|
15
15
|
# Secrets
|
|
16
16
|
#
|
|
17
|
-
# Kamal uses dotenv to automatically load environment variables
|
|
17
|
+
# Kamal uses dotenv to automatically load environment variables from the configured secrets files.
|
|
18
18
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
19
|
+
# Common secrets across all destinations can be set in `.kamal/secrets-common`. Kamal looks for
|
|
20
|
+
# `.kamal/secrets-common` first, then `.kamal/secrets`, with later values overriding earlier ones.
|
|
21
21
|
#
|
|
22
|
-
#
|
|
22
|
+
# If you are using destinations, Kamal looks for `.kamal/secrets-common` first, then
|
|
23
|
+
# `.kamal/secrets.<destination>`. The non-destination `.kamal/secrets` file is not read when a
|
|
24
|
+
# destination is selected.
|
|
23
25
|
#
|
|
24
26
|
# This file can be used to set variables like `KAMAL_REGISTRY_PASSWORD` or database passwords.
|
|
25
27
|
# You can use variable or command substitution in the secrets file.
|