kamal 1.5.1 → 1.6.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 +27 -22
- data/lib/kamal/cli/app/boot.rb +70 -18
- data/lib/kamal/cli/app/prepare_assets.rb +1 -1
- data/lib/kamal/cli/app.rb +57 -47
- data/lib/kamal/cli/base.rb +26 -28
- data/lib/kamal/cli/build/clone.rb +61 -0
- data/lib/kamal/cli/build.rb +58 -50
- data/lib/kamal/cli/env.rb +5 -5
- data/lib/kamal/cli/healthcheck/barrier.rb +31 -0
- data/lib/kamal/cli/healthcheck/error.rb +2 -0
- data/lib/kamal/cli/healthcheck/poller.rb +4 -5
- data/lib/kamal/cli/main.rb +36 -43
- data/lib/kamal/cli/prune.rb +3 -3
- data/lib/kamal/cli/server.rb +39 -15
- data/lib/kamal/cli/traefik.rb +8 -8
- data/lib/kamal/commander/specifics.rb +1 -1
- data/lib/kamal/commander.rb +6 -6
- data/lib/kamal/commands/app/containers.rb +8 -0
- data/lib/kamal/commands/app/execution.rb +3 -3
- data/lib/kamal/commands/app/logging.rb +2 -2
- data/lib/kamal/commands/app.rb +6 -5
- data/lib/kamal/commands/base.rb +2 -3
- data/lib/kamal/commands/builder/base.rb +6 -12
- data/lib/kamal/commands/builder/clone.rb +28 -0
- data/lib/kamal/commands/builder/multiarch.rb +9 -9
- data/lib/kamal/commands/builder/native/cached.rb +6 -7
- data/lib/kamal/commands/builder/native/remote.rb +9 -9
- data/lib/kamal/commands/builder/native.rb +6 -7
- data/lib/kamal/commands/builder.rb +2 -0
- data/lib/kamal/configuration/builder.rb +33 -2
- data/lib/kamal/configuration/env/tag.rb +12 -0
- data/lib/kamal/configuration/env.rb +1 -1
- data/lib/kamal/configuration/role.rb +29 -6
- data/lib/kamal/configuration.rb +14 -2
- data/lib/kamal/git.rb +4 -0
- data/lib/kamal/sshkit_with_ext.rb +36 -0
- data/lib/kamal/version.rb +1 -1
- metadata +18 -10
- data/lib/kamal/cli/healthcheck.rb +0 -21
- data/lib/kamal/commands/app.rb.orig +0 -127
- data/lib/kamal/commands/healthcheck.rb +0 -59
data/lib/kamal/cli/build.rb
CHANGED
@@ -5,39 +5,50 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
5
5
|
|
6
6
|
desc "deliver", "Build app and push app image to registry then pull image on servers"
|
7
7
|
def deliver
|
8
|
-
|
9
|
-
|
10
|
-
pull
|
11
|
-
end
|
8
|
+
push
|
9
|
+
pull
|
12
10
|
end
|
13
11
|
|
14
12
|
desc "push", "Build and push app image to registry"
|
15
13
|
def push
|
16
|
-
|
17
|
-
|
14
|
+
cli = self
|
15
|
+
|
16
|
+
verify_local_dependencies
|
17
|
+
run_hook "pre-build"
|
18
18
|
|
19
|
-
|
20
|
-
run_hook "pre-build"
|
19
|
+
uncommitted_changes = Kamal::Git.uncommitted_changes
|
21
20
|
|
22
|
-
|
23
|
-
|
21
|
+
if KAMAL.config.builder.git_clone?
|
22
|
+
if uncommitted_changes.present?
|
23
|
+
say "Building from a local git clone, so ignoring these uncommitted changes:\n #{uncommitted_changes}", :yellow
|
24
24
|
end
|
25
25
|
|
26
26
|
run_locally do
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
Clone.new(self).prepare
|
28
|
+
end
|
29
|
+
elsif uncommitted_changes.present?
|
30
|
+
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
34
|
+
push = KAMAL.builder.push
|
35
|
+
|
36
|
+
run_locally do
|
37
|
+
begin
|
38
|
+
KAMAL.with_verbosity(:debug) do
|
39
|
+
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
40
|
+
end
|
41
|
+
rescue SSHKit::Command::Failed => e
|
42
|
+
if e.message =~ /(no builder)|(no such file or directory)/
|
43
|
+
warn "Missing compatible builder, so creating a new one first"
|
34
44
|
|
35
|
-
|
36
|
-
|
45
|
+
if cli.create
|
46
|
+
KAMAL.with_verbosity(:debug) do
|
47
|
+
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
37
48
|
end
|
38
|
-
else
|
39
|
-
raise
|
40
49
|
end
|
50
|
+
else
|
51
|
+
raise
|
41
52
|
end
|
42
53
|
end
|
43
54
|
end
|
@@ -45,34 +56,30 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
45
56
|
|
46
57
|
desc "pull", "Pull app image from registry onto servers"
|
47
58
|
def pull
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
execute *KAMAL.builder.validate_image
|
54
|
-
end
|
59
|
+
on(KAMAL.hosts) do
|
60
|
+
execute *KAMAL.auditor.record("Pulled image with version #{KAMAL.config.version}"), verbosity: :debug
|
61
|
+
execute *KAMAL.builder.clean, raise_on_non_zero_exit: false
|
62
|
+
execute *KAMAL.builder.pull
|
63
|
+
execute *KAMAL.builder.validate_image
|
55
64
|
end
|
56
65
|
end
|
57
66
|
|
58
67
|
desc "create", "Create a build setup"
|
59
68
|
def create
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
69
|
+
if (remote_host = KAMAL.config.builder.remote_host)
|
70
|
+
connect_to_remote_host(remote_host)
|
71
|
+
end
|
64
72
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
73
|
+
run_locally do
|
74
|
+
begin
|
75
|
+
debug "Using builder: #{KAMAL.builder.name}"
|
76
|
+
execute *KAMAL.builder.create
|
77
|
+
rescue SSHKit::Command::Failed => e
|
78
|
+
if e.message =~ /stderr=(.*)/
|
79
|
+
error "Couldn't create remote builder: #{$1}"
|
80
|
+
false
|
81
|
+
else
|
82
|
+
raise
|
76
83
|
end
|
77
84
|
end
|
78
85
|
end
|
@@ -80,11 +87,9 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
80
87
|
|
81
88
|
desc "remove", "Remove build setup"
|
82
89
|
def remove
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
execute *KAMAL.builder.remove
|
87
|
-
end
|
90
|
+
run_locally do
|
91
|
+
debug "Using builder: #{KAMAL.builder.name}"
|
92
|
+
execute *KAMAL.builder.remove
|
88
93
|
end
|
89
94
|
end
|
90
95
|
|
@@ -114,8 +119,11 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
114
119
|
def connect_to_remote_host(remote_host)
|
115
120
|
remote_uri = URI.parse(remote_host)
|
116
121
|
if remote_uri.scheme == "ssh"
|
117
|
-
|
118
|
-
|
122
|
+
host = SSHKit::Host.new(
|
123
|
+
hostname: remote_uri.host,
|
124
|
+
ssh_options: { user: remote_uri.user, port: remote_uri.port }.compact
|
125
|
+
)
|
126
|
+
on(host, options) do
|
119
127
|
execute "true"
|
120
128
|
end
|
121
129
|
end
|
data/lib/kamal/cli/env.rb
CHANGED
@@ -3,13 +3,13 @@ require "tempfile"
|
|
3
3
|
class Kamal::Cli::Env < Kamal::Cli::Base
|
4
4
|
desc "push", "Push the env file to the remote hosts"
|
5
5
|
def push
|
6
|
-
|
6
|
+
with_lock do
|
7
7
|
on(KAMAL.hosts) do
|
8
8
|
execute *KAMAL.auditor.record("Pushed env files"), verbosity: :debug
|
9
9
|
|
10
10
|
KAMAL.roles_on(host).each do |role|
|
11
|
-
execute *KAMAL.app(role: role).make_env_directory
|
12
|
-
upload! role.env.secrets_io, role.env.secrets_file, mode: 400
|
11
|
+
execute *KAMAL.app(role: role, host: host).make_env_directory
|
12
|
+
upload! role.env(host).secrets_io, role.env(host).secrets_file, mode: 400
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -30,12 +30,12 @@ class Kamal::Cli::Env < Kamal::Cli::Base
|
|
30
30
|
|
31
31
|
desc "delete", "Delete the env file from the remote hosts"
|
32
32
|
def delete
|
33
|
-
|
33
|
+
with_lock do
|
34
34
|
on(KAMAL.hosts) do
|
35
35
|
execute *KAMAL.auditor.record("Deleted env files"), verbosity: :debug
|
36
36
|
|
37
37
|
KAMAL.roles_on(host).each do |role|
|
38
|
-
execute *KAMAL.app(role: role).remove_env_file
|
38
|
+
execute *KAMAL.app(role: role, host: host).remove_env_file
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Kamal::Cli::Healthcheck::Barrier
|
2
|
+
def initialize
|
3
|
+
@ivar = Concurrent::IVar.new
|
4
|
+
end
|
5
|
+
|
6
|
+
def close
|
7
|
+
set(false)
|
8
|
+
end
|
9
|
+
|
10
|
+
def open
|
11
|
+
set(true)
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait
|
15
|
+
unless opened?
|
16
|
+
raise Kamal::Cli::Healthcheck::Error.new("Halted at barrier")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def opened?
|
22
|
+
@ivar.value
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(value)
|
26
|
+
@ivar.set(value)
|
27
|
+
true
|
28
|
+
rescue Concurrent::MultipleAssignmentError
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
@@ -3,7 +3,6 @@ module Kamal::Cli::Healthcheck::Poller
|
|
3
3
|
|
4
4
|
TRAEFIK_UPDATE_DELAY = 5
|
5
5
|
|
6
|
-
class HealthcheckError < StandardError; end
|
7
6
|
|
8
7
|
def wait_for_healthy(pause_after_ready: false, &block)
|
9
8
|
attempt = 1
|
@@ -16,9 +15,9 @@ module Kamal::Cli::Healthcheck::Poller
|
|
16
15
|
when "running" # No health check configured
|
17
16
|
sleep KAMAL.config.readiness_delay if pause_after_ready
|
18
17
|
else
|
19
|
-
raise
|
18
|
+
raise Kamal::Cli::Healthcheck::Error, "container not ready (#{status})"
|
20
19
|
end
|
21
|
-
rescue
|
20
|
+
rescue Kamal::Cli::Healthcheck::Error => e
|
22
21
|
if attempt <= max_attempts
|
23
22
|
info "#{e.message}, retrying in #{attempt}s (attempt #{attempt}/#{max_attempts})..."
|
24
23
|
sleep attempt
|
@@ -41,9 +40,9 @@ module Kamal::Cli::Healthcheck::Poller
|
|
41
40
|
when "unhealthy"
|
42
41
|
sleep TRAEFIK_UPDATE_DELAY if pause_after_ready
|
43
42
|
else
|
44
|
-
raise
|
43
|
+
raise Kamal::Cli::Healthcheck::Error, "container not unhealthy (#{status})"
|
45
44
|
end
|
46
|
-
rescue
|
45
|
+
rescue Kamal::Cli::Healthcheck::Error => e
|
47
46
|
if attempt <= max_attempts
|
48
47
|
info "#{e.message}, retrying in #{attempt}s (attempt #{attempt}/#{max_attempts})..."
|
49
48
|
sleep attempt
|
data/lib/kamal/cli/main.rb
CHANGED
@@ -3,14 +3,14 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
3
3
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
4
4
|
def setup
|
5
5
|
print_runtime do
|
6
|
-
|
6
|
+
with_lock do
|
7
7
|
invoke_options = deploy_options
|
8
8
|
|
9
9
|
say "Ensure Docker is installed...", :magenta
|
10
10
|
invoke "kamal:cli:server:bootstrap", [], invoke_options
|
11
11
|
|
12
|
-
say "
|
13
|
-
invoke "kamal:cli:
|
12
|
+
say "Evaluate and push env files...", :magenta
|
13
|
+
invoke "kamal:cli:main:envify", [], invoke_options
|
14
14
|
|
15
15
|
invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options
|
16
16
|
deploy
|
@@ -22,30 +22,25 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
22
22
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
23
23
|
def deploy
|
24
24
|
runtime = print_runtime do
|
25
|
-
|
26
|
-
invoke_options = deploy_options
|
25
|
+
invoke_options = deploy_options
|
27
26
|
|
28
|
-
|
29
|
-
|
27
|
+
say "Log into image registry...", :magenta
|
28
|
+
invoke "kamal:cli:registry:login", [], invoke_options
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
if options[:skip_push]
|
31
|
+
say "Pull app image...", :magenta
|
32
|
+
invoke "kamal:cli:build:pull", [], invoke_options
|
33
|
+
else
|
34
|
+
say "Build and push app image...", :magenta
|
35
|
+
invoke "kamal:cli:build:deliver", [], invoke_options
|
36
|
+
end
|
38
37
|
|
38
|
+
with_lock do
|
39
39
|
run_hook "pre-deploy"
|
40
40
|
|
41
41
|
say "Ensure Traefik is running...", :magenta
|
42
42
|
invoke "kamal:cli:traefik:boot", [], invoke_options
|
43
43
|
|
44
|
-
if KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
|
45
|
-
say "Ensure app can pass healthcheck...", :magenta
|
46
|
-
invoke "kamal:cli:healthcheck:perform", [], invoke_options
|
47
|
-
end
|
48
|
-
|
49
44
|
say "Detect stale containers...", :magenta
|
50
45
|
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
51
46
|
|
@@ -63,22 +58,19 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
63
58
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
64
59
|
def redeploy
|
65
60
|
runtime = print_runtime do
|
66
|
-
|
67
|
-
invoke_options = deploy_options
|
61
|
+
invoke_options = deploy_options
|
68
62
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
63
|
+
if options[:skip_push]
|
64
|
+
say "Pull app image...", :magenta
|
65
|
+
invoke "kamal:cli:build:pull", [], invoke_options
|
66
|
+
else
|
67
|
+
say "Build and push app image...", :magenta
|
68
|
+
invoke "kamal:cli:build:deliver", [], invoke_options
|
69
|
+
end
|
76
70
|
|
71
|
+
with_lock do
|
77
72
|
run_hook "pre-deploy"
|
78
73
|
|
79
|
-
say "Ensure app can pass healthcheck...", :magenta
|
80
|
-
invoke "kamal:cli:healthcheck:perform", [], invoke_options
|
81
|
-
|
82
74
|
say "Detect stale containers...", :magenta
|
83
75
|
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
84
76
|
|
@@ -93,7 +85,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
93
85
|
def rollback(version)
|
94
86
|
rolled_back = false
|
95
87
|
runtime = print_runtime do
|
96
|
-
|
88
|
+
with_lock do
|
97
89
|
invoke_options = deploy_options
|
98
90
|
|
99
91
|
KAMAL.config.version = version
|
@@ -185,19 +177,23 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
185
177
|
env_path = ".env"
|
186
178
|
end
|
187
179
|
|
188
|
-
|
180
|
+
if Pathname.new(File.expand_path(env_template_path)).exist?
|
181
|
+
File.write(env_path, ERB.new(File.read(env_template_path), trim_mode: "-").result, perm: 0600)
|
189
182
|
|
190
|
-
|
191
|
-
|
192
|
-
|
183
|
+
unless options[:skip_push]
|
184
|
+
reload_envs
|
185
|
+
invoke "kamal:cli:env:push", options
|
186
|
+
end
|
187
|
+
else
|
188
|
+
puts "Skipping envify (no #{env_template_path} exist)"
|
193
189
|
end
|
194
190
|
end
|
195
191
|
|
196
192
|
desc "remove", "Remove Traefik, app, accessories, and registry session from servers"
|
197
193
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
198
194
|
def remove
|
199
|
-
|
200
|
-
|
195
|
+
confirming "This will remove all containers and images. Are you sure?" do
|
196
|
+
with_lock do
|
201
197
|
invoke "kamal:cli:traefik:remove", [], options.without(:confirmed)
|
202
198
|
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
203
199
|
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
@@ -223,9 +219,6 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
223
219
|
desc "env", "Manage environment files"
|
224
220
|
subcommand "env", Kamal::Cli::Env
|
225
221
|
|
226
|
-
desc "healthcheck", "Healthcheck application"
|
227
|
-
subcommand "healthcheck", Kamal::Cli::Healthcheck
|
228
|
-
|
229
222
|
desc "lock", "Manage the deploy lock"
|
230
223
|
subcommand "lock", Kamal::Cli::Lock
|
231
224
|
|
@@ -246,11 +239,11 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
246
239
|
begin
|
247
240
|
on(KAMAL.hosts) do
|
248
241
|
KAMAL.roles_on(host).each do |role|
|
249
|
-
container_id = capture_with_info(*KAMAL.app(role: role).container_id_for_version(version))
|
242
|
+
container_id = capture_with_info(*KAMAL.app(role: role, host: host).container_id_for_version(version))
|
250
243
|
raise "Container not found" unless container_id.present?
|
251
244
|
end
|
252
245
|
end
|
253
|
-
rescue SSHKit::Runner::ExecuteError => e
|
246
|
+
rescue SSHKit::Runner::ExecuteError, SSHKit::Runner::MultipleExecuteError => e
|
254
247
|
if e.message =~ /Container not found/
|
255
248
|
say "Error looking for container version #{version}: #{e.message}"
|
256
249
|
return false
|
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
|
+
with_lock 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
|
+
with_lock 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
|
+
with_lock 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,25 +1,49 @@
|
|
1
1
|
class Kamal::Cli::Server < Kamal::Cli::Base
|
2
|
+
desc "exec", "Run a custom command on the server (use --help to show options)"
|
3
|
+
option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)"
|
4
|
+
def exec(cmd)
|
5
|
+
hosts = KAMAL.hosts | KAMAL.accessory_hosts
|
6
|
+
|
7
|
+
case
|
8
|
+
when options[:interactive]
|
9
|
+
host = KAMAL.primary_host
|
10
|
+
|
11
|
+
say "Running '#{cmd}' on #{host} interactively...", :magenta
|
12
|
+
|
13
|
+
run_locally { exec KAMAL.server.run_over_ssh(cmd, host: host) }
|
14
|
+
else
|
15
|
+
say "Running '#{cmd}' on #{hosts.join(', ')}...", :magenta
|
16
|
+
|
17
|
+
on(hosts) do |host|
|
18
|
+
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on #{host}"), verbosity: :debug
|
19
|
+
puts_by_host host, capture_with_info(cmd)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
2
24
|
desc "bootstrap", "Set up Docker to run Kamal apps"
|
3
25
|
def bootstrap
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
26
|
+
with_lock do
|
27
|
+
missing = []
|
28
|
+
|
29
|
+
on(KAMAL.hosts | KAMAL.accessory_hosts) do |host|
|
30
|
+
unless execute(*KAMAL.docker.installed?, raise_on_non_zero_exit: false)
|
31
|
+
if execute(*KAMAL.docker.superuser?, raise_on_non_zero_exit: false)
|
32
|
+
info "Missing Docker on #{host}. Installing…"
|
33
|
+
execute *KAMAL.docker.install
|
34
|
+
else
|
35
|
+
missing << host
|
36
|
+
end
|
13
37
|
end
|
38
|
+
|
39
|
+
execute(*KAMAL.server.ensure_run_directory)
|
14
40
|
end
|
15
41
|
|
16
|
-
|
17
|
-
|
42
|
+
if missing.any?
|
43
|
+
raise "Docker is not installed on #{missing.join(", ")} and can't be automatically installed without having root access and either `wget` or `curl`. Install Docker manually: https://docs.docker.com/engine/install/"
|
44
|
+
end
|
18
45
|
|
19
|
-
|
20
|
-
raise "Docker is not installed on #{missing.join(", ")} and can't be automatically installed without having root access and either `wget` or `curl`. Install Docker manually: https://docs.docker.com/engine/install/"
|
46
|
+
run_hook "docker-setup"
|
21
47
|
end
|
22
|
-
|
23
|
-
run_hook "docker-setup"
|
24
48
|
end
|
25
49
|
end
|
data/lib/kamal/cli/traefik.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Kamal::Cli::Traefik < Kamal::Cli::Base
|
2
2
|
desc "boot", "Boot Traefik on servers"
|
3
3
|
def boot
|
4
|
-
|
4
|
+
with_lock do
|
5
5
|
on(KAMAL.traefik_hosts) do
|
6
6
|
execute *KAMAL.registry.login
|
7
7
|
execute *KAMAL.traefik.start_or_run
|
@@ -14,7 +14,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
14
14
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
15
15
|
def reboot
|
16
16
|
confirming "This will cause a brief outage on each host. Are you sure?" do
|
17
|
-
|
17
|
+
with_lock do
|
18
18
|
host_groups = options[:rolling] ? KAMAL.traefik_hosts : [ KAMAL.traefik_hosts ]
|
19
19
|
host_groups.each do |hosts|
|
20
20
|
host_list = Array(hosts).join(",")
|
@@ -34,7 +34,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
34
34
|
|
35
35
|
desc "start", "Start existing Traefik container on servers"
|
36
36
|
def start
|
37
|
-
|
37
|
+
with_lock do
|
38
38
|
on(KAMAL.traefik_hosts) do
|
39
39
|
execute *KAMAL.auditor.record("Started traefik"), verbosity: :debug
|
40
40
|
execute *KAMAL.traefik.start
|
@@ -44,7 +44,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
44
44
|
|
45
45
|
desc "stop", "Stop existing Traefik container on servers"
|
46
46
|
def stop
|
47
|
-
|
47
|
+
with_lock do
|
48
48
|
on(KAMAL.traefik_hosts) do
|
49
49
|
execute *KAMAL.auditor.record("Stopped traefik"), verbosity: :debug
|
50
50
|
execute *KAMAL.traefik.stop, raise_on_non_zero_exit: false
|
@@ -54,7 +54,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
54
54
|
|
55
55
|
desc "restart", "Restart existing Traefik container on servers"
|
56
56
|
def restart
|
57
|
-
|
57
|
+
with_lock do
|
58
58
|
stop
|
59
59
|
start
|
60
60
|
end
|
@@ -91,7 +91,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
91
91
|
|
92
92
|
desc "remove", "Remove Traefik container and image from servers"
|
93
93
|
def remove
|
94
|
-
|
94
|
+
with_lock do
|
95
95
|
stop
|
96
96
|
remove_container
|
97
97
|
remove_image
|
@@ -100,7 +100,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
100
100
|
|
101
101
|
desc "remove_container", "Remove Traefik container from servers", hide: true
|
102
102
|
def remove_container
|
103
|
-
|
103
|
+
with_lock do
|
104
104
|
on(KAMAL.traefik_hosts) do
|
105
105
|
execute *KAMAL.auditor.record("Removed traefik container"), verbosity: :debug
|
106
106
|
execute *KAMAL.traefik.remove_container
|
@@ -110,7 +110,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
110
110
|
|
111
111
|
desc "remove_image", "Remove Traefik image from servers", hide: true
|
112
112
|
def remove_image
|
113
|
-
|
113
|
+
with_lock do
|
114
114
|
on(KAMAL.traefik_hosts) do
|
115
115
|
execute *KAMAL.auditor.record("Removed traefik image"), verbosity: :debug
|
116
116
|
execute *KAMAL.traefik.remove_image
|
data/lib/kamal/commander.rb
CHANGED
@@ -2,13 +2,13 @@ require "active_support/core_ext/enumerable"
|
|
2
2
|
require "active_support/core_ext/module/delegation"
|
3
3
|
|
4
4
|
class Kamal::Commander
|
5
|
-
attr_accessor :verbosity, :holding_lock, :
|
5
|
+
attr_accessor :verbosity, :holding_lock, :connected
|
6
6
|
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :traefik_hosts, :accessory_hosts, to: :specifics
|
7
7
|
|
8
8
|
def initialize
|
9
9
|
self.verbosity = :info
|
10
10
|
self.holding_lock = false
|
11
|
-
self.
|
11
|
+
self.connected = false
|
12
12
|
@specifics = nil
|
13
13
|
end
|
14
14
|
|
@@ -65,8 +65,8 @@ class Kamal::Commander
|
|
65
65
|
end
|
66
66
|
|
67
67
|
|
68
|
-
def app(role: nil)
|
69
|
-
Kamal::Commands::App.new(config, role: role)
|
68
|
+
def app(role: nil, host: nil)
|
69
|
+
Kamal::Commands::App.new(config, role: role, host: host)
|
70
70
|
end
|
71
71
|
|
72
72
|
def accessory(name)
|
@@ -138,8 +138,8 @@ class Kamal::Commander
|
|
138
138
|
self.holding_lock
|
139
139
|
end
|
140
140
|
|
141
|
-
def
|
142
|
-
self.
|
141
|
+
def connected?
|
142
|
+
self.connected
|
143
143
|
end
|
144
144
|
|
145
145
|
private
|
@@ -1,4 +1,6 @@
|
|
1
1
|
module Kamal::Commands::App::Containers
|
2
|
+
DOCKER_HEALTH_LOG_FORMAT = "'{{json .State.Health}}'"
|
3
|
+
|
2
4
|
def list_containers
|
3
5
|
docker :container, :ls, "--all", *filter_args
|
4
6
|
end
|
@@ -20,4 +22,10 @@ module Kamal::Commands::App::Containers
|
|
20
22
|
def remove_containers
|
21
23
|
docker :container, :prune, "--force", *filter_args
|
22
24
|
end
|
25
|
+
|
26
|
+
def container_health_log(version:)
|
27
|
+
pipe \
|
28
|
+
container_id_for(container_name: container_name(version)),
|
29
|
+
xargs(docker(:inspect, "--format", DOCKER_HEALTH_LOG_FORMAT))
|
30
|
+
end
|
23
31
|
end
|
@@ -11,7 +11,7 @@ module Kamal::Commands::App::Execution
|
|
11
11
|
docker :run,
|
12
12
|
("-it" if interactive),
|
13
13
|
"--rm",
|
14
|
-
*role&.env_args,
|
14
|
+
*role&.env_args(host),
|
15
15
|
*argumentize("--env", env),
|
16
16
|
*config.volume_args,
|
17
17
|
*role&.option_args,
|
@@ -19,11 +19,11 @@ module Kamal::Commands::App::Execution
|
|
19
19
|
*command
|
20
20
|
end
|
21
21
|
|
22
|
-
def execute_in_existing_container_over_ssh(*command,
|
22
|
+
def execute_in_existing_container_over_ssh(*command, env:)
|
23
23
|
run_over_ssh execute_in_existing_container(*command, interactive: true, env: env), host: host
|
24
24
|
end
|
25
25
|
|
26
|
-
def execute_in_new_container_over_ssh(*command,
|
26
|
+
def execute_in_new_container_over_ssh(*command, env:)
|
27
27
|
run_over_ssh execute_in_new_container(*command, interactive: true, env: env), host: host
|
28
28
|
end
|
29
29
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Kamal::Commands::App::Logging
|
2
|
-
def logs(since: nil, lines: nil, grep: nil)
|
2
|
+
def logs(version: nil, since: nil, lines: nil, grep: nil)
|
3
3
|
pipe \
|
4
|
-
current_running_container_id,
|
4
|
+
version ? container_id_for_version(version) : current_running_container_id,
|
5
5
|
"xargs docker logs#{" --since #{since}" if since}#{" --tail #{lines}" if lines} 2>&1",
|
6
6
|
("grep '#{grep}'" if grep)
|
7
7
|
end
|