kamal 1.8.3 → 2.7.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/README.md +1 -1
- data/lib/kamal/cli/accessory.rb +92 -38
- data/lib/kamal/cli/alias/command.rb +10 -0
- data/lib/kamal/cli/app/{prepare_assets.rb → assets.rb} +1 -1
- data/lib/kamal/cli/app/boot.rb +23 -16
- data/lib/kamal/cli/app/error_pages.rb +33 -0
- data/lib/kamal/cli/app/ssl_certificates.rb +28 -0
- data/lib/kamal/cli/app.rb +132 -30
- data/lib/kamal/cli/base.rb +57 -53
- data/lib/kamal/cli/build.rb +81 -38
- 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 +60 -59
- data/lib/kamal/cli/proxy.rb +290 -0
- data/lib/kamal/cli/prune.rb +0 -1
- data/lib/kamal/cli/registry.rb +2 -0
- data/lib/kamal/cli/secrets.rb +49 -0
- data/lib/kamal/cli/server.rb +6 -5
- data/lib/kamal/cli/templates/deploy.yml +53 -53
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +2 -12
- data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/post-deploy.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/pre-build.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-connect.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-deploy.sample +19 -6
- data/lib/kamal/cli/templates/sample_hooks/pre-proxy-reboot.sample +3 -0
- data/lib/kamal/cli/templates/secrets +17 -0
- data/lib/kamal/cli.rb +2 -0
- data/lib/kamal/commander/specifics.rb +19 -6
- data/lib/kamal/commander.rb +39 -32
- data/lib/kamal/commands/accessory/proxy.rb +16 -0
- data/lib/kamal/commands/accessory.rb +19 -19
- data/lib/kamal/commands/app/assets.rb +10 -10
- data/lib/kamal/commands/app/containers.rb +2 -2
- data/lib/kamal/commands/app/error_pages.rb +9 -0
- data/lib/kamal/commands/app/execution.rb +7 -4
- data/lib/kamal/commands/app/images.rb +1 -1
- data/lib/kamal/commands/app/logging.rb +16 -6
- data/lib/kamal/commands/app/proxy.rb +32 -0
- data/lib/kamal/commands/app.rb +25 -24
- data/lib/kamal/commands/auditor.rb +12 -3
- data/lib/kamal/commands/base.rb +54 -8
- data/lib/kamal/commands/builder/base.rb +46 -16
- data/lib/kamal/commands/builder/clone.rb +16 -14
- data/lib/kamal/commands/builder/cloud.rb +22 -0
- data/lib/kamal/commands/builder/hybrid.rb +21 -0
- data/lib/kamal/commands/builder/local.rb +14 -0
- data/lib/kamal/commands/builder/pack.rb +46 -0
- data/lib/kamal/commands/builder/remote.rb +63 -0
- data/lib/kamal/commands/builder.rb +21 -45
- data/lib/kamal/commands/docker.rb +4 -0
- data/lib/kamal/commands/hook.rb +8 -2
- data/lib/kamal/commands/lock.rb +2 -6
- data/lib/kamal/commands/proxy.rb +127 -0
- data/lib/kamal/commands/prune.rb +1 -9
- data/lib/kamal/commands/registry.rb +9 -7
- data/lib/kamal/commands/server.rb +11 -1
- data/lib/kamal/configuration/accessory.rb +89 -12
- data/lib/kamal/configuration/alias.rb +15 -0
- data/lib/kamal/configuration/builder.rb +73 -15
- data/lib/kamal/configuration/docs/accessory.yml +53 -15
- data/lib/kamal/configuration/docs/alias.yml +26 -0
- data/lib/kamal/configuration/docs/boot.yml +3 -3
- data/lib/kamal/configuration/docs/builder.yml +63 -38
- data/lib/kamal/configuration/docs/configuration.yml +62 -46
- data/lib/kamal/configuration/docs/env.yml +61 -17
- data/lib/kamal/configuration/docs/logging.yml +3 -3
- data/lib/kamal/configuration/docs/proxy.yml +168 -0
- data/lib/kamal/configuration/docs/registry.yml +20 -13
- data/lib/kamal/configuration/docs/role.yml +14 -13
- data/lib/kamal/configuration/docs/servers.yml +2 -2
- data/lib/kamal/configuration/docs/ssh.yml +23 -19
- data/lib/kamal/configuration/docs/sshkit.yml +4 -4
- data/lib/kamal/configuration/env/tag.rb +4 -3
- data/lib/kamal/configuration/env.rb +19 -17
- data/lib/kamal/configuration/proxy/boot.rb +129 -0
- data/lib/kamal/configuration/proxy.rb +124 -0
- data/lib/kamal/configuration/registry.rb +7 -6
- data/lib/kamal/configuration/role.rb +69 -98
- data/lib/kamal/configuration/servers.rb +8 -1
- data/lib/kamal/configuration/validator/accessory.rb +6 -2
- data/lib/kamal/configuration/validator/alias.rb +15 -0
- data/lib/kamal/configuration/validator/builder.rb +6 -0
- data/lib/kamal/configuration/validator/proxy.rb +25 -0
- data/lib/kamal/configuration/validator/role.rb +3 -1
- data/lib/kamal/configuration/validator/servers.rb +1 -1
- data/lib/kamal/configuration/validator.rb +62 -24
- data/lib/kamal/configuration.rb +96 -50
- data/lib/kamal/docker.rb +30 -0
- data/lib/kamal/env_file.rb +7 -1
- data/lib/kamal/git.rb +10 -0
- data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +51 -0
- data/lib/kamal/secrets/adapters/base.rb +33 -0
- data/lib/kamal/secrets/adapters/bitwarden.rb +81 -0
- data/lib/kamal/secrets/adapters/bitwarden_secrets_manager.rb +66 -0
- data/lib/kamal/secrets/adapters/doppler.rb +57 -0
- data/lib/kamal/secrets/adapters/enpass.rb +71 -0
- data/lib/kamal/secrets/adapters/gcp_secret_manager.rb +112 -0
- data/lib/kamal/secrets/adapters/last_pass.rb +40 -0
- data/lib/kamal/secrets/adapters/one_password.rb +104 -0
- data/lib/kamal/secrets/adapters/passbolt.rb +130 -0
- data/lib/kamal/secrets/adapters/test.rb +14 -0
- data/lib/kamal/secrets/adapters.rb +16 -0
- data/lib/kamal/secrets/dotenv/inline_command_substitution.rb +33 -0
- data/lib/kamal/secrets.rb +42 -0
- data/lib/kamal/sshkit_with_ext.rb +1 -0
- data/lib/kamal/utils.rb +30 -0
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +3 -1
- metadata +63 -36
- 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/sample_hooks/pre-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/build.rb
CHANGED
@@ -5,15 +5,22 @@ 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
|
-
push
|
9
|
-
pull
|
8
|
+
invoke :push
|
9
|
+
invoke :pull
|
10
10
|
end
|
11
11
|
|
12
12
|
desc "push", "Build and push app image to registry"
|
13
|
+
option :output, type: :string, default: "registry", banner: "export_type", desc: "Exported type for the build result, and may be any exported type supported by 'buildx --output'."
|
13
14
|
def push
|
14
15
|
cli = self
|
15
16
|
|
16
|
-
|
17
|
+
# Ensure pre-connect hooks run before the build, they may needed for a remote builder
|
18
|
+
# or the pre-build hooks.
|
19
|
+
pre_connect_if_required
|
20
|
+
|
21
|
+
ensure_docker_installed
|
22
|
+
login_to_registry_locally
|
23
|
+
|
17
24
|
run_hook "pre-build"
|
18
25
|
|
19
26
|
uncommitted_changes = Kamal::Git.uncommitted_changes
|
@@ -30,49 +37,52 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
30
37
|
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
|
31
38
|
end
|
32
39
|
|
33
|
-
|
34
|
-
|
40
|
+
with_env(KAMAL.config.builder.secrets) do
|
41
|
+
run_locally do
|
42
|
+
begin
|
43
|
+
execute *KAMAL.builder.inspect_builder
|
44
|
+
rescue SSHKit::Command::Failed => e
|
45
|
+
if e.message =~ /(context not found|no builder|no compatible builder|does not exist)/
|
46
|
+
warn "Missing compatible builder, so creating a new one first"
|
47
|
+
begin
|
48
|
+
cli.remove
|
49
|
+
rescue SSHKit::Command::Failed
|
50
|
+
raise unless e.message =~ /(context not found|no builder|does not exist)/
|
51
|
+
end
|
52
|
+
cli.create
|
53
|
+
else
|
54
|
+
raise
|
55
|
+
end
|
56
|
+
end
|
35
57
|
|
36
|
-
|
37
|
-
|
38
|
-
context_hosts = capture_with_info(*KAMAL.builder.context_hosts).split("\n")
|
58
|
+
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
59
|
+
push = KAMAL.builder.push(cli.options[:output])
|
39
60
|
|
40
|
-
|
41
|
-
|
42
|
-
cli.remove
|
43
|
-
cli.create
|
44
|
-
end
|
45
|
-
rescue SSHKit::Command::Failed => e
|
46
|
-
if e.message =~ /(context not found|no builder|does not exist)/
|
47
|
-
warn "Missing compatible builder, so creating a new one first"
|
48
|
-
cli.create
|
49
|
-
else
|
50
|
-
raise
|
61
|
+
KAMAL.with_verbosity(:debug) do
|
62
|
+
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
51
63
|
end
|
52
64
|
end
|
53
|
-
|
54
|
-
KAMAL.with_verbosity(:debug) do
|
55
|
-
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
56
|
-
end
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
60
68
|
desc "pull", "Pull app image from registry onto servers"
|
61
69
|
def pull
|
70
|
+
login_to_registry_remotely
|
71
|
+
|
62
72
|
if (first_hosts = mirror_hosts).any?
|
63
73
|
# Pull on a single host per mirror first to seed them
|
64
74
|
say "Pulling image on #{first_hosts.join(", ")} to seed the #{"mirror".pluralize(first_hosts.count)}...", :magenta
|
65
75
|
pull_on_hosts(first_hosts)
|
66
76
|
say "Pulling image on remaining hosts...", :magenta
|
67
|
-
pull_on_hosts(KAMAL.
|
77
|
+
pull_on_hosts(KAMAL.app_hosts - first_hosts)
|
68
78
|
else
|
69
|
-
pull_on_hosts(KAMAL.
|
79
|
+
pull_on_hosts(KAMAL.app_hosts)
|
70
80
|
end
|
71
81
|
end
|
72
82
|
|
73
83
|
desc "create", "Create a build setup"
|
74
84
|
def create
|
75
|
-
if (remote_host = KAMAL.config.builder.
|
85
|
+
if (remote_host = KAMAL.config.builder.remote)
|
76
86
|
connect_to_remote_host(remote_host)
|
77
87
|
end
|
78
88
|
|
@@ -107,21 +117,42 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
107
117
|
end
|
108
118
|
end
|
109
119
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
build_error = e.message =~ /command not found/ ?
|
117
|
-
"Docker is not installed locally" :
|
118
|
-
"Docker buildx plugin is not installed locally"
|
120
|
+
desc "dev", "Build using the working directory, tag it as dirty, and push to local image store."
|
121
|
+
option :output, type: :string, default: "docker", banner: "export_type", desc: "Exported type for the build result, and may be any exported type supported by 'buildx --output'."
|
122
|
+
def dev
|
123
|
+
cli = self
|
124
|
+
|
125
|
+
ensure_docker_installed
|
119
126
|
|
120
|
-
|
127
|
+
docker_included_files = Set.new(Kamal::Docker.included_files)
|
128
|
+
git_uncommitted_files = Set.new(Kamal::Git.uncommitted_files)
|
129
|
+
git_untracked_files = Set.new(Kamal::Git.untracked_files)
|
130
|
+
|
131
|
+
docker_uncommitted_files = docker_included_files & git_uncommitted_files
|
132
|
+
if docker_uncommitted_files.any?
|
133
|
+
say "WARNING: Files with uncommitted changes will be present in the dev container:", :yellow
|
134
|
+
docker_uncommitted_files.sort.each { |f| say " #{f}", :yellow }
|
135
|
+
say
|
136
|
+
end
|
137
|
+
|
138
|
+
docker_untracked_files = docker_included_files & git_untracked_files
|
139
|
+
if docker_untracked_files.any?
|
140
|
+
say "WARNING: Untracked files will be present in the dev container:", :yellow
|
141
|
+
docker_untracked_files.sort.each { |f| say " #{f}", :yellow }
|
142
|
+
say
|
143
|
+
end
|
144
|
+
|
145
|
+
with_env(KAMAL.config.builder.secrets) do
|
146
|
+
run_locally do
|
147
|
+
build = KAMAL.builder.push(cli.options[:output], tag_as_dirty: true)
|
148
|
+
KAMAL.with_verbosity(:debug) do
|
149
|
+
execute(*build)
|
121
150
|
end
|
122
151
|
end
|
123
152
|
end
|
153
|
+
end
|
124
154
|
|
155
|
+
private
|
125
156
|
def connect_to_remote_host(remote_host)
|
126
157
|
remote_uri = URI.parse(remote_host)
|
127
158
|
if remote_uri.scheme == "ssh"
|
@@ -136,9 +167,9 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
136
167
|
end
|
137
168
|
|
138
169
|
def mirror_hosts
|
139
|
-
if KAMAL.
|
170
|
+
if KAMAL.app_hosts.many?
|
140
171
|
mirror_hosts = Concurrent::Hash.new
|
141
|
-
on(KAMAL.
|
172
|
+
on(KAMAL.app_hosts) do |host|
|
142
173
|
first_mirror = capture_with_info(*KAMAL.builder.first_mirror).strip.presence
|
143
174
|
mirror_hosts[first_mirror] ||= host.to_s if first_mirror
|
144
175
|
rescue SSHKit::Command::Failed => e
|
@@ -158,4 +189,16 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
158
189
|
execute *KAMAL.builder.validate_image
|
159
190
|
end
|
160
191
|
end
|
192
|
+
|
193
|
+
def login_to_registry_locally
|
194
|
+
run_locally do
|
195
|
+
execute *KAMAL.registry.login
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def login_to_registry_remotely
|
200
|
+
on(KAMAL.app_hosts) do
|
201
|
+
execute *KAMAL.registry.login
|
202
|
+
end
|
203
|
+
end
|
161
204
|
end
|
@@ -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"
|
data/lib/kamal/cli/main.rb
CHANGED
@@ -9,25 +9,17 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
9
9
|
say "Ensure Docker is installed...", :magenta
|
10
10
|
invoke "kamal:cli:server:bootstrap", [], invoke_options
|
11
11
|
|
12
|
-
|
13
|
-
invoke "kamal:cli:main:envify", [], invoke_options
|
14
|
-
invoke "kamal:cli:env:push", [], invoke_options
|
15
|
-
|
16
|
-
invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options
|
17
|
-
deploy
|
12
|
+
deploy(boot_accessories: true)
|
18
13
|
end
|
19
14
|
end
|
20
15
|
end
|
21
16
|
|
22
17
|
desc "deploy", "Deploy app to servers"
|
23
18
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
24
|
-
def deploy
|
19
|
+
def deploy(boot_accessories: false)
|
25
20
|
runtime = print_runtime do
|
26
21
|
invoke_options = deploy_options
|
27
22
|
|
28
|
-
say "Log into image registry...", :magenta
|
29
|
-
invoke "kamal:cli:registry:login", [], invoke_options.merge(skip_local: options[:skip_push])
|
30
|
-
|
31
23
|
if options[:skip_push]
|
32
24
|
say "Pull app image...", :magenta
|
33
25
|
invoke "kamal:cli:build:pull", [], invoke_options
|
@@ -37,10 +29,12 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
37
29
|
end
|
38
30
|
|
39
31
|
with_lock do
|
40
|
-
run_hook "pre-deploy"
|
32
|
+
run_hook "pre-deploy", secrets: true
|
41
33
|
|
42
|
-
say "Ensure
|
43
|
-
invoke "kamal:cli:
|
34
|
+
say "Ensure kamal-proxy is running...", :magenta
|
35
|
+
invoke "kamal:cli:proxy:boot", [], invoke_options
|
36
|
+
|
37
|
+
invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options if boot_accessories
|
44
38
|
|
45
39
|
say "Detect stale containers...", :magenta
|
46
40
|
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
@@ -52,10 +46,10 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
52
46
|
end
|
53
47
|
end
|
54
48
|
|
55
|
-
run_hook "post-deploy", runtime: runtime.round
|
49
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
|
56
50
|
end
|
57
51
|
|
58
|
-
desc "redeploy", "Deploy app to servers without bootstrapping servers, starting
|
52
|
+
desc "redeploy", "Deploy app to servers without bootstrapping servers, starting kamal-proxy and pruning"
|
59
53
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
60
54
|
def redeploy
|
61
55
|
runtime = print_runtime do
|
@@ -70,7 +64,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
70
64
|
end
|
71
65
|
|
72
66
|
with_lock do
|
73
|
-
run_hook "pre-deploy"
|
67
|
+
run_hook "pre-deploy", secrets: true
|
74
68
|
|
75
69
|
say "Detect stale containers...", :magenta
|
76
70
|
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
@@ -79,7 +73,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
79
73
|
end
|
80
74
|
end
|
81
75
|
|
82
|
-
run_hook "post-deploy", runtime: runtime.round
|
76
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
|
83
77
|
end
|
84
78
|
|
85
79
|
desc "rollback [VERSION]", "Rollback app to VERSION"
|
@@ -93,7 +87,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
93
87
|
old_version = nil
|
94
88
|
|
95
89
|
if container_available?(version)
|
96
|
-
run_hook "pre-deploy"
|
90
|
+
run_hook "pre-deploy", secrets: true
|
97
91
|
|
98
92
|
invoke "kamal:cli:app:boot", [], invoke_options.merge(version: version)
|
99
93
|
rolled_back = true
|
@@ -103,12 +97,12 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
103
97
|
end
|
104
98
|
end
|
105
99
|
|
106
|
-
run_hook "post-deploy", runtime: runtime.round if rolled_back
|
100
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s if rolled_back
|
107
101
|
end
|
108
102
|
|
109
103
|
desc "details", "Show details about all containers"
|
110
104
|
def details
|
111
|
-
invoke "kamal:cli:
|
105
|
+
invoke "kamal:cli:proxy:details"
|
112
106
|
invoke "kamal:cli:app:details"
|
113
107
|
invoke "kamal:cli:accessory:details", [ "all" ]
|
114
108
|
end
|
@@ -127,7 +121,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
127
121
|
end
|
128
122
|
end
|
129
123
|
|
130
|
-
desc "docs", "Show Kamal
|
124
|
+
desc "docs [SECTION]", "Show Kamal configuration documentation"
|
131
125
|
def docs(section = nil)
|
132
126
|
case section
|
133
127
|
when NilClass
|
@@ -139,7 +133,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
139
133
|
puts "No documentation found for #{section}"
|
140
134
|
end
|
141
135
|
|
142
|
-
desc "init", "Create config stub in config/deploy.yml and
|
136
|
+
desc "init", "Create config stub in config/deploy.yml and secrets stub in .kamal"
|
143
137
|
option :bundle, type: :boolean, default: false, desc: "Add Kamal to the Gemfile and create a bin/kamal binstub"
|
144
138
|
def init
|
145
139
|
require "fileutils"
|
@@ -152,9 +146,10 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
152
146
|
puts "Created configuration file in config/deploy.yml"
|
153
147
|
end
|
154
148
|
|
155
|
-
unless (
|
156
|
-
FileUtils.
|
157
|
-
|
149
|
+
unless (secrets_file = Pathname.new(File.expand_path(".kamal/secrets"))).exist?
|
150
|
+
FileUtils.mkdir_p secrets_file.dirname
|
151
|
+
FileUtils.cp_r Pathname.new(File.expand_path("templates/secrets", __dir__)), secrets_file
|
152
|
+
puts "Created .kamal/secrets file"
|
158
153
|
end
|
159
154
|
|
160
155
|
unless (hooks_dir = Pathname.new(File.expand_path(".kamal/hooks"))).exist?
|
@@ -179,44 +174,50 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
179
174
|
end
|
180
175
|
end
|
181
176
|
|
182
|
-
desc "
|
183
|
-
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip .env file push"
|
184
|
-
def envify
|
185
|
-
if destination = options[:destination]
|
186
|
-
env_template_path = ".env.#{destination}.erb"
|
187
|
-
env_path = ".env.#{destination}"
|
188
|
-
else
|
189
|
-
env_template_path = ".env.erb"
|
190
|
-
env_path = ".env"
|
191
|
-
end
|
192
|
-
|
193
|
-
if Pathname.new(File.expand_path(env_template_path)).exist?
|
194
|
-
# Ensure existing env doesn't pollute template evaluation
|
195
|
-
content = with_original_env { ERB.new(File.read(env_template_path), trim_mode: "-").result }
|
196
|
-
File.write(env_path, content, perm: 0600)
|
197
|
-
|
198
|
-
unless options[:skip_push]
|
199
|
-
reload_env
|
200
|
-
invoke "kamal:cli:env:push", options
|
201
|
-
end
|
202
|
-
else
|
203
|
-
puts "Skipping envify (no #{env_template_path} exist)"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
desc "remove", "Remove Traefik, app, accessories, and registry session from servers"
|
177
|
+
desc "remove", "Remove kamal-proxy, app, accessories, and registry session from servers"
|
208
178
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
209
179
|
def remove
|
210
180
|
confirming "This will remove all containers and images. Are you sure?" do
|
211
181
|
with_lock do
|
212
|
-
invoke "kamal:cli:traefik:remove", [], options.without(:confirmed)
|
213
182
|
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
183
|
+
invoke "kamal:cli:proxy:remove", [], options.without(:confirmed)
|
214
184
|
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
215
185
|
invoke "kamal:cli:registry:logout", [], options.without(:confirmed).merge(skip_local: true)
|
216
186
|
end
|
217
187
|
end
|
218
188
|
end
|
219
189
|
|
190
|
+
desc "upgrade", "Upgrade from Kamal 1.x to 2.0"
|
191
|
+
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
192
|
+
option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time"
|
193
|
+
def upgrade
|
194
|
+
confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
|
195
|
+
with_lock do
|
196
|
+
if options[:rolling]
|
197
|
+
KAMAL.hosts.each do |host|
|
198
|
+
KAMAL.with_specific_hosts(host) do
|
199
|
+
say "Upgrading #{host}...", :magenta
|
200
|
+
if KAMAL.app_hosts.include?(host)
|
201
|
+
invoke "kamal:cli:proxy:upgrade", [], options.merge(confirmed: true, rolling: false)
|
202
|
+
reset_invocation(Kamal::Cli::Proxy)
|
203
|
+
end
|
204
|
+
if KAMAL.accessory_hosts.include?(host)
|
205
|
+
invoke "kamal:cli:accessory:upgrade", [ "all" ], options.merge(confirmed: true, rolling: false)
|
206
|
+
reset_invocation(Kamal::Cli::Accessory)
|
207
|
+
end
|
208
|
+
say "Upgraded #{host}", :magenta
|
209
|
+
end
|
210
|
+
end
|
211
|
+
else
|
212
|
+
say "Upgrading all hosts...", :magenta
|
213
|
+
invoke "kamal:cli:proxy:upgrade", [], options.merge(confirmed: true)
|
214
|
+
invoke "kamal:cli:accessory:upgrade", [ "all" ], options.merge(confirmed: true)
|
215
|
+
say "Upgraded all hosts", :magenta
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
220
221
|
desc "version", "Show Kamal version"
|
221
222
|
def version
|
222
223
|
puts Kamal::VERSION
|
@@ -231,28 +232,28 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
231
232
|
desc "build", "Build application image"
|
232
233
|
subcommand "build", Kamal::Cli::Build
|
233
234
|
|
234
|
-
desc "env", "Manage environment files"
|
235
|
-
subcommand "env", Kamal::Cli::Env
|
236
|
-
|
237
235
|
desc "lock", "Manage the deploy lock"
|
238
236
|
subcommand "lock", Kamal::Cli::Lock
|
239
237
|
|
238
|
+
desc "proxy", "Manage kamal-proxy"
|
239
|
+
subcommand "proxy", Kamal::Cli::Proxy
|
240
|
+
|
240
241
|
desc "prune", "Prune old application images and containers"
|
241
242
|
subcommand "prune", Kamal::Cli::Prune
|
242
243
|
|
243
244
|
desc "registry", "Login and -out of the image registry"
|
244
245
|
subcommand "registry", Kamal::Cli::Registry
|
245
246
|
|
247
|
+
desc "secrets", "Helpers for extracting secrets"
|
248
|
+
subcommand "secrets", Kamal::Cli::Secrets
|
249
|
+
|
246
250
|
desc "server", "Bootstrap servers with curl and Docker"
|
247
251
|
subcommand "server", Kamal::Cli::Server
|
248
252
|
|
249
|
-
desc "traefik", "Manage Traefik load balancer"
|
250
|
-
subcommand "traefik", Kamal::Cli::Traefik
|
251
|
-
|
252
253
|
private
|
253
254
|
def container_available?(version)
|
254
255
|
begin
|
255
|
-
on(KAMAL.
|
256
|
+
on(KAMAL.app_hosts) do
|
256
257
|
KAMAL.roles_on(host).each do |role|
|
257
258
|
container_id = capture_with_info(*KAMAL.app(role: role, host: host).container_id_for_version(version))
|
258
259
|
raise "Container not found" unless container_id.present?
|