kamal 1.5.2 → 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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kamal/cli/accessory.rb +25 -21
  3. data/lib/kamal/cli/app/boot.rb +70 -18
  4. data/lib/kamal/cli/app/prepare_assets.rb +1 -1
  5. data/lib/kamal/cli/app.rb +57 -47
  6. data/lib/kamal/cli/base.rb +26 -28
  7. data/lib/kamal/cli/build/clone.rb +61 -0
  8. data/lib/kamal/cli/build.rb +58 -50
  9. data/lib/kamal/cli/env.rb +5 -5
  10. data/lib/kamal/cli/healthcheck/barrier.rb +31 -0
  11. data/lib/kamal/cli/healthcheck/error.rb +2 -0
  12. data/lib/kamal/cli/healthcheck/poller.rb +4 -5
  13. data/lib/kamal/cli/main.rb +36 -43
  14. data/lib/kamal/cli/prune.rb +3 -3
  15. data/lib/kamal/cli/server.rb +39 -15
  16. data/lib/kamal/cli/traefik.rb +8 -8
  17. data/lib/kamal/commander.rb +6 -6
  18. data/lib/kamal/commands/app/containers.rb +8 -0
  19. data/lib/kamal/commands/app/execution.rb +3 -3
  20. data/lib/kamal/commands/app/logging.rb +2 -2
  21. data/lib/kamal/commands/app.rb +6 -5
  22. data/lib/kamal/commands/base.rb +2 -3
  23. data/lib/kamal/commands/builder/base.rb +6 -12
  24. data/lib/kamal/commands/builder/clone.rb +28 -0
  25. data/lib/kamal/commands/builder/multiarch.rb +9 -9
  26. data/lib/kamal/commands/builder/native/cached.rb +6 -7
  27. data/lib/kamal/commands/builder/native/remote.rb +9 -9
  28. data/lib/kamal/commands/builder/native.rb +6 -7
  29. data/lib/kamal/commands/builder.rb +2 -0
  30. data/lib/kamal/configuration/builder.rb +33 -2
  31. data/lib/kamal/configuration/env/tag.rb +12 -0
  32. data/lib/kamal/configuration/env.rb +1 -1
  33. data/lib/kamal/configuration/role.rb +29 -6
  34. data/lib/kamal/configuration.rb +14 -2
  35. data/lib/kamal/git.rb +4 -0
  36. data/lib/kamal/sshkit_with_ext.rb +36 -0
  37. data/lib/kamal/version.rb +1 -1
  38. metadata +18 -9
  39. data/lib/kamal/cli/healthcheck.rb +0 -21
  40. data/lib/kamal/commands/healthcheck.rb +0 -59
@@ -3,11 +3,12 @@ class Kamal::Commands::App < Kamal::Commands::Base
3
3
 
4
4
  ACTIVE_DOCKER_STATUSES = [ :running, :restarting ]
5
5
 
6
- attr_reader :role, :role
6
+ attr_reader :role, :host
7
7
 
8
- def initialize(config, role: nil)
8
+ def initialize(config, role: nil, host: nil)
9
9
  super(config)
10
10
  @role = role
11
+ @host = host
11
12
  end
12
13
 
13
14
  def run(hostname: nil)
@@ -18,7 +19,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
18
19
  *([ "--hostname", hostname ] if hostname),
19
20
  "-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
20
21
  "-e", "KAMAL_VERSION=\"#{config.version}\"",
21
- *role.env_args,
22
+ *role.env_args(host),
22
23
  *role.health_check_args,
23
24
  *role.logging_args,
24
25
  *config.volume_args,
@@ -70,11 +71,11 @@ class Kamal::Commands::App < Kamal::Commands::Base
70
71
 
71
72
 
72
73
  def make_env_directory
73
- make_directory role.env.secrets_directory
74
+ make_directory role.env(host).secrets_directory
74
75
  end
75
76
 
76
77
  def remove_env_file
77
- [ :rm, "-f", role.env.secrets_file ]
78
+ [ :rm, "-f", role.env(host).secrets_file ]
78
79
  end
79
80
 
80
81
 
@@ -3,7 +3,6 @@ module Kamal::Commands
3
3
  delegate :sensitive, :argumentize, to: Kamal::Utils
4
4
 
5
5
  DOCKER_HEALTH_STATUS_FORMAT = "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'"
6
- DOCKER_HEALTH_LOG_FORMAT = "'{{json .State.Health}}'"
7
6
 
8
7
  attr_accessor :config
9
8
 
@@ -78,8 +77,8 @@ module Kamal::Commands
78
77
  args.compact.unshift :docker
79
78
  end
80
79
 
81
- def git(*args)
82
- args.compact.unshift :git
80
+ def git(*args, path: nil)
81
+ [ :git, *([ "-C", path ] if path), *args.compact ]
83
82
  end
84
83
 
85
84
  def tags(**details)
@@ -3,7 +3,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
3
3
  class BuilderError < StandardError; end
4
4
 
5
5
  delegate :argumentize, to: Kamal::Utils
6
- delegate :args, :secrets, :dockerfile, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, :git_archive?, to: :builder_config
6
+ delegate :args, :secrets, :dockerfile, :target, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, to: :builder_config
7
7
 
8
8
  def clean
9
9
  docker :image, :rm, "--force", config.absolute_image
@@ -13,18 +13,8 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
13
13
  docker :pull, config.absolute_image
14
14
  end
15
15
 
16
- def push
17
- if git_archive?
18
- pipe \
19
- git(:archive, "--format=tar", :HEAD),
20
- build_and_push
21
- else
22
- build_and_push
23
- end
24
- end
25
-
26
16
  def build_options
27
- [ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_ssh ]
17
+ [ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh ]
28
18
  end
29
19
 
30
20
  def build_context
@@ -73,6 +63,10 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
73
63
  end
74
64
  end
75
65
 
66
+ def build_target
67
+ argumentize "--target", target if target.present?
68
+ end
69
+
76
70
  def build_ssh
77
71
  argumentize "--ssh", ssh if ssh.present?
78
72
  end
@@ -0,0 +1,28 @@
1
+ module Kamal::Commands::Builder::Clone
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ delegate :clone_directory, :build_directory, to: :"config.builder"
6
+ end
7
+
8
+ def clone
9
+ git :clone, Kamal::Git.root, path: clone_directory
10
+ end
11
+
12
+ def clone_reset_steps
13
+ [
14
+ git(:remote, "set-url", :origin, Kamal::Git.root, path: build_directory),
15
+ git(:fetch, :origin, path: build_directory),
16
+ git(:reset, "--hard", Kamal::Git.revision, path: build_directory),
17
+ git(:clean, "-fdx", path: build_directory)
18
+ ]
19
+ end
20
+
21
+ def clone_status
22
+ git :status, "--porcelain", path: build_directory
23
+ end
24
+
25
+ def clone_revision
26
+ git :"rev-parse", :HEAD, path: build_directory
27
+ end
28
+ end
@@ -13,6 +13,15 @@ class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
13
13
  docker(:buildx, :ls)
14
14
  end
15
15
 
16
+ def push
17
+ docker :buildx, :build,
18
+ "--push",
19
+ "--platform", platform_names,
20
+ "--builder", builder_name,
21
+ *build_options,
22
+ build_context
23
+ end
24
+
16
25
  private
17
26
  def builder_name
18
27
  "kamal-#{config.service}-multiarch"
@@ -25,13 +34,4 @@ class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
25
34
  "linux/amd64,linux/arm64"
26
35
  end
27
36
  end
28
-
29
- def build_and_push
30
- docker :buildx, :build,
31
- "--push",
32
- "--platform", platform_names,
33
- "--builder", builder_name,
34
- *build_options,
35
- build_context
36
- end
37
37
  end
@@ -7,11 +7,10 @@ class Kamal::Commands::Builder::Native::Cached < Kamal::Commands::Builder::Nativ
7
7
  docker :buildx, :rm, builder_name
8
8
  end
9
9
 
10
- private
11
- def build_and_push
12
- docker :buildx, :build,
13
- "--push",
14
- *build_options,
15
- build_context
16
- end
10
+ def push
11
+ docker :buildx, :build,
12
+ "--push",
13
+ *build_options,
14
+ build_context
15
+ end
17
16
  end
@@ -17,6 +17,15 @@ class Kamal::Commands::Builder::Native::Remote < Kamal::Commands::Builder::Nativ
17
17
  docker(:buildx, :ls)
18
18
  end
19
19
 
20
+ def push
21
+ docker :buildx, :build,
22
+ "--push",
23
+ "--platform", platform,
24
+ "--builder", builder_name,
25
+ *build_options,
26
+ build_context
27
+ end
28
+
20
29
 
21
30
  private
22
31
  def builder_name
@@ -47,13 +56,4 @@ class Kamal::Commands::Builder::Native::Remote < Kamal::Commands::Builder::Nativ
47
56
  def remove_buildx
48
57
  docker :buildx, :rm, builder_name
49
58
  end
50
-
51
- def build_and_push
52
- docker :buildx, :build,
53
- "--push",
54
- "--platform", platform,
55
- "--builder", builder_name,
56
- *build_options,
57
- build_context
58
- end
59
59
  end
@@ -11,11 +11,10 @@ class Kamal::Commands::Builder::Native < Kamal::Commands::Builder::Base
11
11
  # No-op on native
12
12
  end
13
13
 
14
- private
15
- def build_and_push
16
- combine \
17
- docker(:build, *build_options, build_context),
18
- docker(:push, config.absolute_image),
19
- docker(:push, config.latest_image)
20
- end
14
+ def push
15
+ combine \
16
+ docker(:build, *build_options, build_context),
17
+ docker(:push, config.absolute_image),
18
+ docker(:push, config.latest_image)
19
+ end
21
20
  end
@@ -3,6 +3,8 @@ require "active_support/core_ext/string/filters"
3
3
  class Kamal::Commands::Builder < Kamal::Commands::Base
4
4
  delegate :create, :remove, :push, :clean, :pull, :info, :validate_image, to: :target
5
5
 
6
+ include Clone
7
+
6
8
  def name
7
9
  target.class.to_s.remove("Kamal::Commands::Builder::").underscore.inquiry
8
10
  end
@@ -3,6 +3,8 @@ class Kamal::Configuration::Builder
3
3
  @options = config.raw_config.builder || {}
4
4
  @image = config.image
5
5
  @server = config.registry["server"]
6
+ @service = config.service
7
+ @destination = config.destination
6
8
 
7
9
  valid?
8
10
  end
@@ -39,8 +41,12 @@ class Kamal::Configuration::Builder
39
41
  @options["dockerfile"] || "Dockerfile"
40
42
  end
41
43
 
44
+ def target
45
+ @options["target"]
46
+ end
47
+
42
48
  def context
43
- @options["context"] || (git_archive? ? "-" : ".")
49
+ @options["context"] || "."
44
50
  end
45
51
 
46
52
  def local_arch
@@ -85,10 +91,23 @@ class Kamal::Configuration::Builder
85
91
  @options["ssh"]
86
92
  end
87
93
 
88
- def git_archive?
94
+ def git_clone?
89
95
  Kamal::Git.used? && @options["context"].nil?
90
96
  end
91
97
 
98
+ def clone_directory
99
+ @clone_directory ||= File.join Dir.tmpdir, "kamal-clones", [ @service, pwd_sha ].compact.join("-")
100
+ end
101
+
102
+ def build_directory
103
+ @build_directory ||=
104
+ if git_clone?
105
+ File.join clone_directory, repo_basename, repo_relative_pwd
106
+ else
107
+ "."
108
+ end
109
+ end
110
+
92
111
  private
93
112
  def valid?
94
113
  if @options["cache"] && @options["cache"]["type"]
@@ -119,4 +138,16 @@ class Kamal::Configuration::Builder
119
138
  def cache_to_config_for_registry
120
139
  [ "type=registry", @options["cache"]&.fetch("options", nil), "ref=#{cache_image_ref}" ].compact.join(",")
121
140
  end
141
+
142
+ def repo_basename
143
+ File.basename(Kamal::Git.root)
144
+ end
145
+
146
+ def repo_relative_pwd
147
+ Dir.pwd.delete_prefix(Kamal::Git.root)
148
+ end
149
+
150
+ def pwd_sha
151
+ Digest::SHA256.hexdigest(Dir.pwd)[0..12]
152
+ end
122
153
  end
@@ -0,0 +1,12 @@
1
+ class Kamal::Configuration::Env::Tag
2
+ attr_reader :name, :config
3
+
4
+ def initialize(name, config:)
5
+ @name = name
6
+ @config = config
7
+ end
8
+
9
+ def env
10
+ Kamal::Configuration::Env.from_config(config: config)
11
+ end
12
+ end
@@ -4,7 +4,7 @@ class Kamal::Configuration::Env
4
4
 
5
5
  def self.from_config(config:, secrets_file: nil)
6
6
  secrets_keys = config.fetch("secret", [])
7
- clear = config.fetch("clear", config.key?("secret") ? {} : config)
7
+ clear = config.fetch("clear", config.key?("secret") || config.key?("tags") ? {} : config)
8
8
 
9
9
  new clear: clear, secrets_keys: secrets_keys, secrets_file: secrets_file
10
10
  end
@@ -7,6 +7,7 @@ class Kamal::Configuration::Role
7
7
 
8
8
  def initialize(name, config:)
9
9
  @name, @config = name.inquiry, config
10
+ @tagged_hosts ||= extract_tagged_hosts_from_config
10
11
  end
11
12
 
12
13
  def primary_host
@@ -14,7 +15,11 @@ class Kamal::Configuration::Role
14
15
  end
15
16
 
16
17
  def hosts
17
- @hosts ||= extract_hosts_from_config
18
+ tagged_hosts.keys
19
+ end
20
+
21
+ def env_tags(host)
22
+ tagged_hosts.fetch(host).collect { |tag| config.env_tag(tag) }
18
23
  end
19
24
 
20
25
  def cmd
@@ -50,12 +55,13 @@ class Kamal::Configuration::Role
50
55
  end
51
56
 
52
57
 
53
- def env
54
- @env ||= base_env.merge(specialized_env)
58
+ def env(host)
59
+ @envs ||= {}
60
+ @envs[host] ||= [ base_env, specialized_env, *env_tags(host).map(&:env) ].reduce(:merge)
55
61
  end
56
62
 
57
- def env_args
58
- env.args
63
+ def env_args(host)
64
+ env(host).args
59
65
  end
60
66
 
61
67
  def asset_volume_args
@@ -164,7 +170,24 @@ class Kamal::Configuration::Role
164
170
  end
165
171
 
166
172
  private
167
- attr_accessor :config
173
+ attr_accessor :config, :tagged_hosts
174
+
175
+ def extract_tagged_hosts_from_config
176
+ {}.tap do |tagged_hosts|
177
+ extract_hosts_from_config.map do |host_config|
178
+ if host_config.is_a?(Hash)
179
+ raise ArgumentError, "Multiple hosts found: #{host_config.inspect}" unless host_config.size == 1
180
+
181
+ host, tags = host_config.first
182
+ tagged_hosts[host] = Array(tags)
183
+ elsif host_config.is_a?(String) || host_config.is_a?(Symbol)
184
+ tagged_hosts[host_config] = []
185
+ else
186
+ raise ArgumentError, "Invalid host config: #{host_config.inspect}"
187
+ end
188
+ end
189
+ end
190
+ end
168
191
 
169
192
  def extract_hosts_from_config
170
193
  if config.servers.is_a?(Array)
@@ -188,7 +188,7 @@ class Kamal::Configuration
188
188
 
189
189
 
190
190
  def healthcheck
191
- { "path" => "/up", "port" => 3000, "max_attempts" => 7, "exposed_port" => 3999, "cord" => "/tmp/kamal-cord", "log_lines" => 50 }.merge(raw_config.healthcheck || {})
191
+ { "path" => "/up", "port" => 3000, "max_attempts" => 7, "cord" => "/tmp/kamal-cord", "log_lines" => 50 }.merge(raw_config.healthcheck || {})
192
192
  end
193
193
 
194
194
  def healthcheck_service
@@ -233,6 +233,18 @@ class Kamal::Configuration
233
233
  raw_config.env || {}
234
234
  end
235
235
 
236
+ def env_tags
237
+ @env_tags ||= if (tags = raw_config.env["tags"])
238
+ tags.collect { |name, config| Kamal::Configuration::Env::Tag.new(name, config: config) }
239
+ else
240
+ []
241
+ end
242
+ end
243
+
244
+ def env_tag(name)
245
+ env_tags.detect { |t| t.name == name.to_s }
246
+ end
247
+
236
248
 
237
249
  def valid?
238
250
  ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version && ensure_retain_containers_valid && ensure_valid_service_name
@@ -328,7 +340,7 @@ class Kamal::Configuration
328
340
  def git_version
329
341
  @git_version ||=
330
342
  if Kamal::Git.used?
331
- if Kamal::Git.uncommitted_changes.present? && !builder.git_archive?
343
+ if Kamal::Git.uncommitted_changes.present? && !builder.git_clone?
332
344
  uncommitted_suffix = "_uncommitted_#{SecureRandom.hex(8)}"
333
345
  end
334
346
  [ Kamal::Git.revision, uncommitted_suffix ].compact.join
data/lib/kamal/git.rb CHANGED
@@ -16,4 +16,8 @@ module Kamal::Git
16
16
  def uncommitted_changes
17
17
  `git status --porcelain`.strip
18
18
  end
19
+
20
+ def root
21
+ `git rev-parse --show-toplevel`.strip
22
+ end
19
23
  end
@@ -103,3 +103,39 @@ class SSHKit::Backend::Netssh
103
103
 
104
104
  prepend LimitConcurrentStartsInstance
105
105
  end
106
+
107
+ class SSHKit::Runner::Parallel
108
+ # SSHKit joins the threads in sequence and fails on the first error it encounters, which means that we wait threads
109
+ # before the first failure to complete but not for ones after.
110
+ #
111
+ # We'll patch it to wait for them all to complete, and to record all the threads that errored so we can see when a
112
+ # problem occurs on multiple hosts.
113
+ module CompleteAll
114
+ def execute
115
+ threads = hosts.map do |host|
116
+ Thread.new(host) do |h|
117
+ backend(h, &block).run
118
+ rescue ::StandardError => e
119
+ e2 = SSHKit::Runner::ExecuteError.new e
120
+ raise e2, "Exception while executing #{host.user ? "as #{host.user}@" : "on host "}#{host}: #{e.message}"
121
+ end
122
+ end
123
+
124
+ exceptions = []
125
+ threads.each do |t|
126
+ begin
127
+ t.join
128
+ rescue SSHKit::Runner::ExecuteError => e
129
+ exceptions << e
130
+ end
131
+ end
132
+ if exceptions.one?
133
+ raise exceptions.first
134
+ elsif exceptions.many?
135
+ raise exceptions.first, [ "Exceptions on #{exceptions.count} hosts:", exceptions.map(&:message) ].join("\n")
136
+ end
137
+ end
138
+ end
139
+
140
+ prepend CompleteAll
141
+ end
data/lib/kamal/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kamal
2
- VERSION = "1.5.2"
2
+ VERSION = "1.6.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kamal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-07 00:00:00.000000000 Z
11
+ date: 2024-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -28,16 +28,22 @@ dependencies:
28
28
  name: sshkit
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.22.2
34
+ - - "<"
32
35
  - !ruby/object:Gem::Version
33
- version: '1.21'
36
+ version: '2.0'
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - "~>"
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.22.2
44
+ - - "<"
39
45
  - !ruby/object:Gem::Version
40
- version: '1.21'
46
+ version: '2.0'
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: net-ssh
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -210,8 +216,10 @@ files:
210
216
  - lib/kamal/cli/app/prepare_assets.rb
211
217
  - lib/kamal/cli/base.rb
212
218
  - lib/kamal/cli/build.rb
219
+ - lib/kamal/cli/build/clone.rb
213
220
  - lib/kamal/cli/env.rb
214
- - lib/kamal/cli/healthcheck.rb
221
+ - lib/kamal/cli/healthcheck/barrier.rb
222
+ - lib/kamal/cli/healthcheck/error.rb
215
223
  - lib/kamal/cli/healthcheck/poller.rb
216
224
  - lib/kamal/cli/lock.rb
217
225
  - lib/kamal/cli/main.rb
@@ -243,13 +251,13 @@ files:
243
251
  - lib/kamal/commands/base.rb
244
252
  - lib/kamal/commands/builder.rb
245
253
  - lib/kamal/commands/builder/base.rb
254
+ - lib/kamal/commands/builder/clone.rb
246
255
  - lib/kamal/commands/builder/multiarch.rb
247
256
  - lib/kamal/commands/builder/multiarch/remote.rb
248
257
  - lib/kamal/commands/builder/native.rb
249
258
  - lib/kamal/commands/builder/native/cached.rb
250
259
  - lib/kamal/commands/builder/native/remote.rb
251
260
  - lib/kamal/commands/docker.rb
252
- - lib/kamal/commands/healthcheck.rb
253
261
  - lib/kamal/commands/hook.rb
254
262
  - lib/kamal/commands/lock.rb
255
263
  - lib/kamal/commands/prune.rb
@@ -261,6 +269,7 @@ files:
261
269
  - lib/kamal/configuration/boot.rb
262
270
  - lib/kamal/configuration/builder.rb
263
271
  - lib/kamal/configuration/env.rb
272
+ - lib/kamal/configuration/env/tag.rb
264
273
  - lib/kamal/configuration/role.rb
265
274
  - lib/kamal/configuration/ssh.rb
266
275
  - lib/kamal/configuration/sshkit.rb
@@ -291,7 +300,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
291
300
  - !ruby/object:Gem::Version
292
301
  version: '0'
293
302
  requirements: []
294
- rubygems_version: 3.5.6
303
+ rubygems_version: 3.5.10
295
304
  signing_key:
296
305
  specification_version: 4
297
306
  summary: Deploy web apps in containers to servers running Docker with zero downtime.
@@ -1,21 +0,0 @@
1
- class Kamal::Cli::Healthcheck < Kamal::Cli::Base
2
- default_command :perform
3
-
4
- desc "perform", "Health check current app version"
5
- def perform
6
- raise "The primary host is not configured to run Traefik" unless KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
7
- on(KAMAL.primary_host) do
8
- begin
9
- execute *KAMAL.healthcheck.run
10
- Poller.wait_for_healthy { capture_with_info(*KAMAL.healthcheck.status) }
11
- rescue Poller::HealthcheckError => e
12
- error capture_with_info(*KAMAL.healthcheck.logs)
13
- error capture_with_pretty_json(*KAMAL.healthcheck.container_health_log)
14
- raise
15
- ensure
16
- execute *KAMAL.healthcheck.stop, raise_on_non_zero_exit: false
17
- execute *KAMAL.healthcheck.remove, raise_on_non_zero_exit: false
18
- end
19
- end
20
- end
21
- end
@@ -1,59 +0,0 @@
1
- class Kamal::Commands::Healthcheck < Kamal::Commands::Base
2
- def run
3
- primary = config.role(config.primary_role)
4
-
5
- docker :run,
6
- "--detach",
7
- "--name", container_name_with_version,
8
- "--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
9
- "--label", "service=#{config.healthcheck_service}",
10
- "-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
11
- *primary.env_args,
12
- *primary.health_check_args(cord: false),
13
- *config.volume_args,
14
- *primary.option_args,
15
- config.absolute_image,
16
- primary.cmd
17
- end
18
-
19
- def status
20
- pipe container_id, xargs(docker(:inspect, "--format", DOCKER_HEALTH_STATUS_FORMAT))
21
- end
22
-
23
- def container_health_log
24
- pipe container_id, xargs(docker(:inspect, "--format", DOCKER_HEALTH_LOG_FORMAT))
25
- end
26
-
27
- def logs
28
- pipe container_id, xargs(docker(:logs, "--tail", log_lines, "2>&1"))
29
- end
30
-
31
- def stop
32
- pipe container_id, xargs(docker(:stop))
33
- end
34
-
35
- def remove
36
- pipe container_id, xargs(docker(:container, :rm))
37
- end
38
-
39
- private
40
- def container_name_with_version
41
- "#{config.healthcheck_service}-#{config.version}"
42
- end
43
-
44
- def container_id
45
- container_id_for(container_name: container_name_with_version)
46
- end
47
-
48
- def health_url
49
- "http://localhost:#{exposed_port}#{config.healthcheck["path"]}"
50
- end
51
-
52
- def exposed_port
53
- config.healthcheck["exposed_port"]
54
- end
55
-
56
- def log_lines
57
- config.healthcheck["log_lines"]
58
- end
59
- end