kamal 1.8.3 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/kamal/cli/accessory.rb +44 -20
- data/lib/kamal/cli/alias/command.rb +9 -0
- data/lib/kamal/cli/app/boot.rb +22 -16
- data/lib/kamal/cli/app.rb +40 -5
- data/lib/kamal/cli/base.rb +19 -51
- data/lib/kamal/cli/build.rb +12 -13
- data/lib/kamal/cli/healthcheck/barrier.rb +2 -0
- data/lib/kamal/cli/healthcheck/poller.rb +18 -39
- data/lib/kamal/cli/lock.rb +2 -3
- data/lib/kamal/cli/main.rb +54 -51
- data/lib/kamal/cli/proxy.rb +224 -0
- data/lib/kamal/cli/prune.rb +0 -1
- data/lib/kamal/cli/secrets.rb +36 -0
- data/lib/kamal/cli/server.rb +2 -3
- data/lib/kamal/cli/templates/deploy.yml +4 -21
- data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +3 -0
- data/lib/kamal/cli/templates/secrets +16 -0
- data/lib/kamal/cli.rb +1 -0
- data/lib/kamal/commander/specifics.rb +3 -3
- data/lib/kamal/commander.rb +24 -8
- data/lib/kamal/commands/accessory.rb +7 -7
- data/lib/kamal/commands/app/assets.rb +8 -8
- data/lib/kamal/commands/app/proxy.rb +16 -0
- data/lib/kamal/commands/app.rb +7 -15
- data/lib/kamal/commands/auditor.rb +6 -3
- data/lib/kamal/commands/base.rb +8 -0
- data/lib/kamal/commands/builder/base.rb +26 -13
- data/lib/kamal/commands/builder/hybrid.rb +21 -0
- data/lib/kamal/commands/builder/local.rb +14 -0
- data/lib/kamal/commands/builder/remote.rb +63 -0
- data/lib/kamal/commands/builder.rb +13 -29
- data/lib/kamal/commands/docker.rb +4 -0
- data/lib/kamal/commands/hook.rb +5 -2
- data/lib/kamal/commands/lock.rb +2 -6
- data/lib/kamal/commands/proxy.rb +77 -0
- data/lib/kamal/commands/prune.rb +1 -9
- data/lib/kamal/commands/server.rb +11 -1
- data/lib/kamal/configuration/accessory.rb +14 -2
- data/lib/kamal/configuration/alias.rb +15 -0
- data/lib/kamal/configuration/builder.rb +52 -18
- data/lib/kamal/configuration/docs/alias.yml +26 -0
- data/lib/kamal/configuration/docs/builder.yml +26 -23
- data/lib/kamal/configuration/docs/configuration.yml +22 -16
- data/lib/kamal/configuration/docs/env.yml +10 -11
- data/lib/kamal/configuration/docs/proxy.yml +100 -0
- data/lib/kamal/configuration/docs/registry.yml +4 -2
- data/lib/kamal/configuration/docs/role.yml +3 -5
- data/lib/kamal/configuration/env/tag.rb +4 -3
- data/lib/kamal/configuration/env.rb +10 -17
- data/lib/kamal/configuration/proxy.rb +66 -0
- data/lib/kamal/configuration/registry.rb +3 -2
- data/lib/kamal/configuration/role.rb +63 -94
- data/lib/kamal/configuration/validator/alias.rb +15 -0
- data/lib/kamal/configuration/validator/builder.rb +4 -0
- data/lib/kamal/configuration/validator/proxy.rb +11 -0
- data/lib/kamal/configuration/validator.rb +42 -24
- data/lib/kamal/configuration.rb +91 -33
- data/lib/kamal/env_file.rb +4 -0
- data/lib/kamal/secrets/adapters/base.rb +18 -0
- data/lib/kamal/secrets/adapters/bitwarden.rb +64 -0
- data/lib/kamal/secrets/adapters/last_pass.rb +30 -0
- data/lib/kamal/secrets/adapters/one_password.rb +61 -0
- data/lib/kamal/secrets/adapters/test.rb +10 -0
- data/lib/kamal/secrets/adapters.rb +14 -0
- data/lib/kamal/secrets/dotenv/inline_command_substitution.rb +32 -0
- data/lib/kamal/secrets.rb +37 -0
- data/lib/kamal/sshkit_with_ext.rb +1 -0
- data/lib/kamal/utils.rb +28 -0
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +3 -1
- metadata +32 -23
- data/lib/kamal/cli/env.rb +0 -54
- data/lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample +0 -3
- data/lib/kamal/cli/templates/template.env +0 -2
- data/lib/kamal/cli/traefik.rb +0 -122
- data/lib/kamal/commands/app/cord.rb +0 -22
- data/lib/kamal/commands/builder/multiarch/remote.rb +0 -65
- data/lib/kamal/commands/builder/multiarch.rb +0 -41
- data/lib/kamal/commands/builder/native/cached.rb +0 -25
- data/lib/kamal/commands/builder/native/remote.rb +0 -67
- data/lib/kamal/commands/builder/native.rb +0 -20
- data/lib/kamal/commands/traefik.rb +0 -85
- data/lib/kamal/configuration/docs/healthcheck.yml +0 -59
- data/lib/kamal/configuration/docs/traefik.yml +0 -62
- data/lib/kamal/configuration/healthcheck.rb +0 -63
- data/lib/kamal/configuration/traefik.rb +0 -60
- /data/lib/kamal/cli/templates/sample_hooks/{pre-traefik-reboot.sample → pre-proxy-reboot.sample} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c08e90e760f2392afcd73847fa1d9f7e987c684d687f49f227b808fda6cc28d5
|
4
|
+
data.tar.gz: c0945022760eeca770901d2c163c58a4a46a11f917e29f2d516d95d4af51ef3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80ee86cd4b2ee5f5369cb6b1a7b81165a313cdedfd11352eb9215c5b6bf792be627927fad72c3bf25f69d12bcbf02a1fd088771ac495b45c0272145f16536f3f
|
7
|
+
data.tar.gz: df01ab908c65534003c0f089727c5ec6165be5ad72e72fab0f71c73c181ba0c8d7230a1887a2a3d7650c1f0ecfe2db349ebc2367ed64fbf052863d3bf37e4b57
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Kamal: Deploy web apps anywhere
|
2
2
|
|
3
|
-
From bare metal to cloud VMs, deploy web apps anywhere with zero downtime. Kamal
|
3
|
+
From bare metal to cloud VMs, deploy web apps anywhere with zero downtime. Kamal uses [kamal-proxy](https://github.com/basecamp/kamal-proxy) to seamlessly switch requests between containers. Works seamlessly across multiple servers, using SSHKit to execute commands. Originally built for Rails apps, Kamal will work with any type of web app that can be containerized with Docker.
|
4
4
|
|
5
5
|
➡️ See [kamal-deploy.org](https://kamal-deploy.org) for documentation on [installation](https://kamal-deploy.org/docs/installation), [configuration](https://kamal-deploy.org/docs/configuration), and [commands](https://kamal-deploy.org/docs/commands).
|
6
6
|
|
data/lib/kamal/cli/accessory.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
class Kamal::Cli::Accessory < Kamal::Cli::Base
|
2
2
|
desc "boot [NAME]", "Boot new accessory service on host (use NAME=all to boot all accessories)"
|
3
|
-
def boot(name,
|
3
|
+
def boot(name, prepare: true)
|
4
4
|
with_lock do
|
5
5
|
if name == "all"
|
6
6
|
KAMAL.accessory_names.each { |accessory_name| boot(accessory_name) }
|
7
7
|
else
|
8
|
+
prepare(name) if prepare
|
9
|
+
|
8
10
|
with_accessory(name) do |accessory, hosts|
|
9
11
|
directories(name)
|
10
12
|
upload(name)
|
11
13
|
|
12
14
|
on(hosts) do
|
13
|
-
execute *KAMAL.registry.login if login
|
14
15
|
execute *KAMAL.auditor.record("Booted #{name} accessory"), verbosity: :debug
|
16
|
+
execute *accessory.ensure_env_directory
|
17
|
+
upload! accessory.secrets_io, accessory.secrets_path, mode: "0600"
|
15
18
|
execute *accessory.run
|
16
19
|
end
|
17
20
|
end
|
@@ -55,15 +58,10 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|
55
58
|
if name == "all"
|
56
59
|
KAMAL.accessory_names.each { |accessory_name| reboot(accessory_name) }
|
57
60
|
else
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
stop(name)
|
64
|
-
remove_container(name)
|
65
|
-
boot(name, login: false)
|
66
|
-
end
|
61
|
+
prepare(name)
|
62
|
+
stop(name)
|
63
|
+
remove_container(name)
|
64
|
+
boot(name, prepare: false)
|
67
65
|
end
|
68
66
|
end
|
69
67
|
end
|
@@ -95,10 +93,8 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|
95
93
|
desc "restart [NAME]", "Restart existing accessory container on host"
|
96
94
|
def restart(name)
|
97
95
|
with_lock do
|
98
|
-
|
99
|
-
|
100
|
-
start(name)
|
101
|
-
end
|
96
|
+
stop(name)
|
97
|
+
start(name)
|
102
98
|
end
|
103
99
|
end
|
104
100
|
|
@@ -222,6 +218,25 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|
222
218
|
end
|
223
219
|
end
|
224
220
|
|
221
|
+
desc "upgrade", "Upgrade accessories from Kamal 1.x to 2.0 (restart them in 'kamal' network)"
|
222
|
+
option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time"
|
223
|
+
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
224
|
+
def upgrade(name)
|
225
|
+
confirming "This will restart all accessories" do
|
226
|
+
with_lock do
|
227
|
+
host_groups = options[:rolling] ? KAMAL.accessory_hosts : [ KAMAL.accessory_hosts ]
|
228
|
+
host_groups.each do |hosts|
|
229
|
+
host_list = Array(hosts).join(",")
|
230
|
+
KAMAL.with_specific_hosts(hosts) do
|
231
|
+
say "Upgrading #{name} accessories on #{host_list}...", :magenta
|
232
|
+
reboot name
|
233
|
+
say "Upgraded #{name} accessories on #{host_list}...", :magenta
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
225
240
|
private
|
226
241
|
def with_accessory(name)
|
227
242
|
if KAMAL.config.accessory(name)
|
@@ -249,11 +264,20 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|
249
264
|
end
|
250
265
|
|
251
266
|
def remove_accessory(name)
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
267
|
+
stop(name)
|
268
|
+
remove_container(name)
|
269
|
+
remove_image(name)
|
270
|
+
remove_service_directory(name)
|
271
|
+
end
|
272
|
+
|
273
|
+
def prepare(name)
|
274
|
+
with_accessory(name) do |accessory, hosts|
|
275
|
+
on(hosts) do
|
276
|
+
execute *KAMAL.registry.login
|
277
|
+
execute *KAMAL.docker.create_network
|
278
|
+
rescue SSHKit::Command::Failed => e
|
279
|
+
raise unless e.message.include?("already exists")
|
280
|
+
end
|
257
281
|
end
|
258
282
|
end
|
259
283
|
end
|
data/lib/kamal/cli/app/boot.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Kamal::Cli::App::Boot
|
2
2
|
attr_reader :host, :role, :version, :barrier, :sshkit
|
3
|
-
delegate :execute, :capture_with_info, :capture_with_pretty_json, :info, :error, to: :sshkit
|
4
|
-
delegate :
|
3
|
+
delegate :execute, :capture_with_info, :capture_with_pretty_json, :info, :error, :upload!, to: :sshkit
|
4
|
+
delegate :assets?, :running_proxy?, to: :role
|
5
5
|
|
6
6
|
def initialize(host, role, sshkit, version, barrier)
|
7
7
|
@host = host
|
@@ -45,11 +45,22 @@ class Kamal::Cli::App::Boot
|
|
45
45
|
|
46
46
|
def start_new_version
|
47
47
|
audit "Booted app version #{version}"
|
48
|
-
|
49
|
-
execute *app.tie_cord(role.cord_host_file) if uses_cord?
|
50
48
|
hostname = "#{host.to_s[0...51].gsub(/\.+$/, '')}-#{SecureRandom.hex(6)}"
|
49
|
+
|
50
|
+
execute *app.ensure_env_directory
|
51
|
+
upload! role.secrets_io(host), role.secrets_path, mode: "0600"
|
52
|
+
|
51
53
|
execute *app.run(hostname: hostname)
|
52
|
-
|
54
|
+
if running_proxy?
|
55
|
+
endpoint = capture_with_info(*app.container_id_for_version(version)).strip
|
56
|
+
raise Kamal::Cli::BootError, "Failed to get endpoint for #{role} on #{host}, did the container boot?" if endpoint.empty?
|
57
|
+
execute *app.deploy(target: endpoint)
|
58
|
+
else
|
59
|
+
Kamal::Cli::Healthcheck::Poller.wait_for_healthy(pause_after_ready: true) { capture_with_info(*app.status(version: version)) }
|
60
|
+
end
|
61
|
+
rescue => e
|
62
|
+
error "Failed to boot #{role} on #{host}"
|
63
|
+
raise e
|
53
64
|
end
|
54
65
|
|
55
66
|
def stop_new_version
|
@@ -57,16 +68,7 @@ class Kamal::Cli::App::Boot
|
|
57
68
|
end
|
58
69
|
|
59
70
|
def stop_old_version(version)
|
60
|
-
if uses_cord?
|
61
|
-
cord = capture_with_info(*app.cord(version: version), raise_on_non_zero_exit: false).strip
|
62
|
-
if cord.present?
|
63
|
-
execute *app.cut_cord(cord)
|
64
|
-
Kamal::Cli::Healthcheck::Poller.wait_for_unhealthy(pause_after_ready: true) { capture_with_info(*app.status(version: version)) }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
71
|
execute *app.stop(version: version), raise_on_non_zero_exit: false
|
69
|
-
|
70
72
|
execute *app.clean_up_assets if assets?
|
71
73
|
end
|
72
74
|
|
@@ -88,8 +90,12 @@ class Kamal::Cli::App::Boot
|
|
88
90
|
def close_barrier
|
89
91
|
if barrier.close
|
90
92
|
info "First #{KAMAL.primary_role} container is unhealthy on #{host}, not booting any other roles"
|
91
|
-
|
92
|
-
|
93
|
+
begin
|
94
|
+
error capture_with_info(*app.logs(version: version))
|
95
|
+
error capture_with_info(*app.container_health_log(version: version))
|
96
|
+
rescue SSHKit::Command::Failed
|
97
|
+
error "Could not fetch logs for #{version}"
|
98
|
+
end
|
93
99
|
end
|
94
100
|
end
|
95
101
|
|
data/lib/kamal/cli/app.rb
CHANGED
@@ -4,7 +4,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
4
4
|
with_lock do
|
5
5
|
say "Get most recent version available as an image...", :magenta unless options[:version]
|
6
6
|
using_version(version_or_latest) do |version|
|
7
|
-
say "Start container with version #{version}
|
7
|
+
say "Start container with version #{version} (or reboot if already running)...", :magenta
|
8
8
|
|
9
9
|
# Assets are prepared in a separate step to ensure they are on all hosts before booting
|
10
10
|
on(KAMAL.hosts) do
|
@@ -38,8 +38,17 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
38
38
|
roles = KAMAL.roles_on(host)
|
39
39
|
|
40
40
|
roles.each do |role|
|
41
|
+
app = KAMAL.app(role: role, host: host)
|
41
42
|
execute *KAMAL.auditor.record("Started app version #{KAMAL.config.version}"), verbosity: :debug
|
42
|
-
execute *
|
43
|
+
execute *app.start, raise_on_non_zero_exit: false
|
44
|
+
|
45
|
+
if role.running_proxy?
|
46
|
+
version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
|
47
|
+
endpoint = capture_with_info(*app.container_id_for_version(version)).strip
|
48
|
+
raise Kamal::Cli::BootError, "Failed to get endpoint for #{role} on #{host}, did the container boot?" if endpoint.empty?
|
49
|
+
|
50
|
+
execute *app.deploy(target: endpoint)
|
51
|
+
end
|
43
52
|
end
|
44
53
|
end
|
45
54
|
end
|
@@ -52,8 +61,18 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
52
61
|
roles = KAMAL.roles_on(host)
|
53
62
|
|
54
63
|
roles.each do |role|
|
64
|
+
app = KAMAL.app(role: role, host: host)
|
55
65
|
execute *KAMAL.auditor.record("Stopped app", role: role), verbosity: :debug
|
56
|
-
|
66
|
+
|
67
|
+
if role.running_proxy?
|
68
|
+
version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
|
69
|
+
endpoint = capture_with_info(*app.container_id_for_version(version)).strip
|
70
|
+
if endpoint.present?
|
71
|
+
execute *app.remove(target: endpoint), raise_on_non_zero_exit: false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
execute *app.stop, raise_on_non_zero_exit: false
|
57
76
|
end
|
58
77
|
end
|
59
78
|
end
|
@@ -71,11 +90,12 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
71
90
|
end
|
72
91
|
end
|
73
92
|
|
74
|
-
desc "exec [CMD]", "Execute a custom command on servers within the app container (use --help to show options)"
|
93
|
+
desc "exec [CMD...]", "Execute a custom command on servers within the app container (use --help to show options)"
|
75
94
|
option :interactive, aliases: "-i", type: :boolean, default: false, desc: "Execute command over ssh for an interactive shell (use for console/bash)"
|
76
95
|
option :reuse, type: :boolean, default: false, desc: "Reuse currently running container instead of starting a new one"
|
77
96
|
option :env, aliases: "-e", type: :hash, desc: "Set environment variables for the command"
|
78
|
-
def exec(cmd)
|
97
|
+
def exec(*cmd)
|
98
|
+
cmd = Kamal::Utils.join_commands(cmd)
|
79
99
|
env = options[:env]
|
80
100
|
case
|
81
101
|
when options[:interactive] && options[:reuse]
|
@@ -211,6 +231,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
211
231
|
stop
|
212
232
|
remove_containers
|
213
233
|
remove_images
|
234
|
+
remove_app_directory
|
214
235
|
end
|
215
236
|
end
|
216
237
|
|
@@ -252,6 +273,20 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
252
273
|
end
|
253
274
|
end
|
254
275
|
|
276
|
+
desc "remove_app_directory", "Remove the service directory from servers", hide: true
|
277
|
+
def remove_app_directory
|
278
|
+
with_lock do
|
279
|
+
on(KAMAL.hosts) do |host|
|
280
|
+
roles = KAMAL.roles_on(host)
|
281
|
+
|
282
|
+
roles.each do |role|
|
283
|
+
execute *KAMAL.auditor.record("Removed #{KAMAL.config.app_directory} on all servers", role: role), verbosity: :debug
|
284
|
+
execute *KAMAL.server.remove_app_directory, raise_on_non_zero_exit: false
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
255
290
|
desc "version", "Show app version currently running on servers"
|
256
291
|
def version
|
257
292
|
on(KAMAL.hosts) do |host|
|
data/lib/kamal/cli/base.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require "thor"
|
2
|
-
require "dotenv"
|
3
2
|
require "kamal/sshkit_with_ext"
|
4
3
|
|
5
4
|
module Kamal::Cli
|
6
5
|
class Base < Thor
|
7
6
|
include SSHKit::DSL
|
8
7
|
|
9
|
-
def self.exit_on_failure?()
|
8
|
+
def self.exit_on_failure?() false end
|
9
|
+
def self.dynamic_command_class() Kamal::Cli::Alias::Command end
|
10
10
|
|
11
11
|
class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging"
|
12
12
|
class_option :quiet, type: :boolean, aliases: "-q", desc: "Minimal logging"
|
@@ -22,55 +22,23 @@ module Kamal::Cli
|
|
22
22
|
|
23
23
|
class_option :skip_hooks, aliases: "-H", type: :boolean, default: false, desc: "Don't run hooks"
|
24
24
|
|
25
|
-
def initialize(
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
def initialize(args = [], local_options = {}, config = {})
|
26
|
+
if config[:current_command].is_a?(Kamal::Cli::Alias::Command)
|
27
|
+
# When Thor generates a dynamic command, it doesn't attempt to parse the arguments.
|
28
|
+
# For our purposes, it means the arguments are passed in args rather than local_options.
|
29
|
+
super([], args, config)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
initialize_commander unless KAMAL.configured?
|
30
34
|
end
|
31
35
|
|
32
36
|
private
|
33
|
-
def reload_env
|
34
|
-
reset_env
|
35
|
-
load_env
|
36
|
-
end
|
37
|
-
|
38
|
-
def load_env
|
39
|
-
if destination = options[:destination]
|
40
|
-
Dotenv.load(".env.#{destination}", ".env")
|
41
|
-
else
|
42
|
-
Dotenv.load(".env")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def reset_env
|
47
|
-
replace_env @original_env
|
48
|
-
end
|
49
|
-
|
50
|
-
def replace_env(env)
|
51
|
-
ENV.clear
|
52
|
-
ENV.update(env)
|
53
|
-
end
|
54
|
-
|
55
|
-
def with_original_env
|
56
|
-
keeping_current_env do
|
57
|
-
reset_env
|
58
|
-
yield
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def keeping_current_env
|
63
|
-
current_env = ENV.to_h.dup
|
64
|
-
yield
|
65
|
-
ensure
|
66
|
-
replace_env(current_env)
|
67
|
-
end
|
68
|
-
|
69
37
|
def options_with_subcommand_class_options
|
70
38
|
options.merge(@_initializer.last[:class_options] || {})
|
71
39
|
end
|
72
40
|
|
73
|
-
def initialize_commander
|
41
|
+
def initialize_commander
|
74
42
|
KAMAL.tap do |commander|
|
75
43
|
if options[:verbose]
|
76
44
|
ENV["VERBOSE"] = "1" # For backtraces via cli/start
|
@@ -105,8 +73,6 @@ module Kamal::Cli
|
|
105
73
|
if KAMAL.holding_lock?
|
106
74
|
yield
|
107
75
|
else
|
108
|
-
ensure_run_and_locks_directory
|
109
|
-
|
110
76
|
acquire_lock
|
111
77
|
|
112
78
|
begin
|
@@ -135,6 +101,8 @@ module Kamal::Cli
|
|
135
101
|
end
|
136
102
|
|
137
103
|
def acquire_lock
|
104
|
+
ensure_run_directory
|
105
|
+
|
138
106
|
raise_if_locked do
|
139
107
|
say "Acquiring the deploy lock...", :magenta
|
140
108
|
on(KAMAL.primary_host) { execute *KAMAL.lock.acquire("Automatic deploy lock", KAMAL.config.version), verbosity: :debug }
|
@@ -206,14 +174,14 @@ module Kamal::Cli
|
|
206
174
|
instance_variable_get("@_invocations").first
|
207
175
|
end
|
208
176
|
|
209
|
-
def
|
177
|
+
def reset_invocation(cli_class)
|
178
|
+
instance_variable_get("@_invocations")[cli_class].pop
|
179
|
+
end
|
180
|
+
|
181
|
+
def ensure_run_directory
|
210
182
|
on(KAMAL.hosts) do
|
211
183
|
execute(*KAMAL.server.ensure_run_directory)
|
212
184
|
end
|
213
|
-
|
214
|
-
on(KAMAL.primary_host) do
|
215
|
-
execute(*KAMAL.lock.ensure_locks_directory)
|
216
|
-
end
|
217
185
|
end
|
218
186
|
end
|
219
187
|
end
|
data/lib/kamal/cli/build.rb
CHANGED
@@ -30,29 +30,28 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
30
30
|
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
|
31
31
|
end
|
32
32
|
|
33
|
-
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
34
|
-
push = KAMAL.builder.push
|
35
|
-
|
36
33
|
run_locally do
|
37
34
|
begin
|
38
|
-
|
39
|
-
|
40
|
-
if context_hosts != KAMAL.builder.config_context_hosts
|
41
|
-
warn "Context hosts have changed, so re-creating builder, was: #{context_hosts.join(", ")}], now: #{KAMAL.builder.config_context_hosts.join(", ")}"
|
42
|
-
cli.remove
|
43
|
-
cli.create
|
44
|
-
end
|
35
|
+
execute *KAMAL.builder.inspect_builder
|
45
36
|
rescue SSHKit::Command::Failed => e
|
46
|
-
if e.message =~ /(context not found|no builder|does not exist)/
|
37
|
+
if e.message =~ /(context not found|no builder|no compatible builder|does not exist)/
|
47
38
|
warn "Missing compatible builder, so creating a new one first"
|
39
|
+
begin
|
40
|
+
cli.remove
|
41
|
+
rescue SSHKit::Command::Failed
|
42
|
+
raise unless e.message =~ /(context not found|no builder|does not exist)/
|
43
|
+
end
|
48
44
|
cli.create
|
49
45
|
else
|
50
46
|
raise
|
51
47
|
end
|
52
48
|
end
|
53
49
|
|
50
|
+
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
51
|
+
push = KAMAL.builder.push
|
52
|
+
|
54
53
|
KAMAL.with_verbosity(:debug) do
|
55
|
-
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
54
|
+
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push, env: KAMAL.config.builder.secrets }
|
56
55
|
end
|
57
56
|
end
|
58
57
|
end
|
@@ -72,7 +71,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
72
71
|
|
73
72
|
desc "create", "Create a build setup"
|
74
73
|
def create
|
75
|
-
if (remote_host = KAMAL.config.builder.
|
74
|
+
if (remote_host = KAMAL.config.builder.remote)
|
76
75
|
connect_to_remote_host(remote_host)
|
77
76
|
end
|
78
77
|
|
@@ -1,51 +1,30 @@
|
|
1
1
|
module Kamal::Cli::Healthcheck::Poller
|
2
2
|
extend self
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def wait_for_healthy(pause_after_ready: false, &block)
|
4
|
+
def wait_for_healthy(role, &block)
|
8
5
|
attempt = 1
|
9
|
-
|
6
|
+
timeout_at = Time.now + KAMAL.config.deploy_timeout
|
7
|
+
readiness_delay = KAMAL.config.readiness_delay
|
10
8
|
|
11
9
|
begin
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
if attempt <= max_attempts
|
22
|
-
info "#{e.message}, retrying in #{attempt}s (attempt #{attempt}/#{max_attempts})..."
|
23
|
-
sleep attempt
|
24
|
-
attempt += 1
|
25
|
-
retry
|
26
|
-
else
|
27
|
-
raise
|
10
|
+
status = block.call
|
11
|
+
|
12
|
+
if status == "running"
|
13
|
+
# Wait for the readiness delay and confirm it is still running
|
14
|
+
if readiness_delay > 0
|
15
|
+
info "Container is running, waiting for readiness delay of #{readiness_delay} seconds"
|
16
|
+
sleep readiness_delay
|
17
|
+
status = block.call
|
18
|
+
end
|
28
19
|
end
|
29
|
-
end
|
30
20
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def wait_for_unhealthy(pause_after_ready: false, &block)
|
35
|
-
attempt = 1
|
36
|
-
max_attempts = KAMAL.config.healthcheck.max_attempts
|
37
|
-
|
38
|
-
begin
|
39
|
-
case status = block.call
|
40
|
-
when "unhealthy"
|
41
|
-
sleep TRAEFIK_UPDATE_DELAY if pause_after_ready
|
42
|
-
else
|
43
|
-
raise Kamal::Cli::Healthcheck::Error, "container not unhealthy (#{status})"
|
21
|
+
unless %w[ running healthy ].include?(status)
|
22
|
+
raise Kamal::Cli::Healthcheck::Error, "container not ready after #{KAMAL.config.deploy_timeout} seconds (#{status})"
|
44
23
|
end
|
45
24
|
rescue Kamal::Cli::Healthcheck::Error => e
|
46
|
-
|
47
|
-
|
48
|
-
sleep attempt
|
25
|
+
time_left = timeout_at - Time.now
|
26
|
+
if time_left > 0
|
27
|
+
sleep [ attempt, time_left ].min
|
49
28
|
attempt += 1
|
50
29
|
retry
|
51
30
|
else
|
@@ -53,7 +32,7 @@ module Kamal::Cli::Healthcheck::Poller
|
|
53
32
|
end
|
54
33
|
end
|
55
34
|
|
56
|
-
info "Container is
|
35
|
+
info "Container is healthy!"
|
57
36
|
end
|
58
37
|
|
59
38
|
private
|
data/lib/kamal/cli/lock.rb
CHANGED
@@ -3,7 +3,6 @@ class Kamal::Cli::Lock < Kamal::Cli::Base
|
|
3
3
|
def status
|
4
4
|
handle_missing_lock do
|
5
5
|
on(KAMAL.primary_host) do
|
6
|
-
execute *KAMAL.server.ensure_run_directory
|
7
6
|
puts capture_with_debug(*KAMAL.lock.status)
|
8
7
|
end
|
9
8
|
end
|
@@ -13,9 +12,10 @@ class Kamal::Cli::Lock < Kamal::Cli::Base
|
|
13
12
|
option :message, aliases: "-m", type: :string, desc: "A lock message", required: true
|
14
13
|
def acquire
|
15
14
|
message = options[:message]
|
15
|
+
ensure_run_directory
|
16
|
+
|
16
17
|
raise_if_locked do
|
17
18
|
on(KAMAL.primary_host) do
|
18
|
-
execute *KAMAL.server.ensure_run_directory
|
19
19
|
execute *KAMAL.lock.acquire(message, KAMAL.config.version), verbosity: :debug
|
20
20
|
end
|
21
21
|
say "Acquired the deploy lock"
|
@@ -26,7 +26,6 @@ class Kamal::Cli::Lock < Kamal::Cli::Base
|
|
26
26
|
def release
|
27
27
|
handle_missing_lock do
|
28
28
|
on(KAMAL.primary_host) do
|
29
|
-
execute *KAMAL.server.ensure_run_directory
|
30
29
|
execute *KAMAL.lock.release, verbosity: :debug
|
31
30
|
end
|
32
31
|
say "Released the deploy lock"
|