kamal 2.8.1 → 2.8.2
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/build/clone.rb +0 -2
- data/lib/kamal/cli/build/port_forwarding.rb +66 -0
- data/lib/kamal/cli/build.rb +43 -26
- data/lib/kamal/cli/registry.rb +22 -0
- data/lib/kamal/commands/builder/base.rb +10 -0
- data/lib/kamal/commands/builder/hybrid.rb +3 -3
- data/lib/kamal/commands/builder/local.rb +2 -9
- data/lib/kamal/commands/builder/remote.rb +6 -2
- data/lib/kamal/configuration/docs/registry.yml +12 -4
- data/lib/kamal/configuration.rb +11 -0
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +1 -0
- metadata +2 -2
- data/lib/kamal/cli/port_forwarding.rb +0 -55
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ee017d64694e5a35507b9cfc9693e6a6c5fc876e0cfb731d58f0de7dba281f41
|
|
4
|
+
data.tar.gz: bcbc84a444f0aa5efb08fd0ab63ea87d5892821f04e9c6ac51d938d78e2547a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b285597e99a5d2d90a324e9be64332a71afd66269ac27c8550eebf692758cac14535a14164058fd246d0001fd3b371382ed0b4e4bc9a75e19f8d42e40b4d9365
|
|
7
|
+
data.tar.gz: fca4902b9da04bab86d087b0582ed956e2ee174259e47f1a491a4b68c928dc16a501cb0b137d443daeda25c00fd99bcf0f234ce54bf85da7b61002ce90402de0
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require "concurrent/atomic/count_down_latch"
|
|
2
|
+
|
|
3
|
+
class Kamal::Cli::Build::PortForwarding
|
|
4
|
+
attr_reader :hosts, :port, :ssh_options
|
|
5
|
+
|
|
6
|
+
def initialize(hosts, port, **ssh_options)
|
|
7
|
+
@hosts = hosts
|
|
8
|
+
@port = port
|
|
9
|
+
@ssh_options = ssh_options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def forward
|
|
13
|
+
@done = false
|
|
14
|
+
forward_ports
|
|
15
|
+
|
|
16
|
+
yield
|
|
17
|
+
ensure
|
|
18
|
+
stop
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
def stop
|
|
23
|
+
@done = true
|
|
24
|
+
@threads.to_a.each(&:join)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def forward_ports
|
|
28
|
+
ready = Concurrent::CountDownLatch.new(hosts.size)
|
|
29
|
+
|
|
30
|
+
@threads = hosts.map do |host|
|
|
31
|
+
Thread.new do
|
|
32
|
+
begin
|
|
33
|
+
Net::SSH.start(host, ssh_options[:user], **ssh_options.except(:user)) do |ssh|
|
|
34
|
+
ssh.forward.remote(port, "localhost", port, "127.0.0.1") do |remote_port, bind_address|
|
|
35
|
+
if remote_port == :error
|
|
36
|
+
raise "Failed to establish port forward on #{host}"
|
|
37
|
+
else
|
|
38
|
+
ready.count_down
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
ssh.loop(0.1) do
|
|
43
|
+
if @done
|
|
44
|
+
ssh.forward.cancel_remote(port, "127.0.0.1")
|
|
45
|
+
break
|
|
46
|
+
else
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
rescue Exception => e
|
|
52
|
+
error "Error setting up port forwarding to #{host}: #{e.class}: #{e.message}"
|
|
53
|
+
error e.backtrace.join("\n")
|
|
54
|
+
|
|
55
|
+
raise
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
raise "Timed out waiting for port forwarding to be established" unless ready.wait(30)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def error(message)
|
|
64
|
+
SSHKit.config.output.error(message)
|
|
65
|
+
end
|
|
66
|
+
end
|
data/lib/kamal/cli/build.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require "uri"
|
|
2
|
-
|
|
3
1
|
class Kamal::Cli::Build < Kamal::Cli::Base
|
|
4
2
|
class BuildError < StandardError; end
|
|
5
3
|
|
|
@@ -38,29 +36,31 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
|
38
36
|
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
|
|
39
37
|
end
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
forward_local_registry_port_for_remote_builder do
|
|
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
|
|
52
55
|
end
|
|
53
|
-
cli.create
|
|
54
|
-
else
|
|
55
|
-
raise
|
|
56
56
|
end
|
|
57
|
-
end
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
|
59
|
+
push = KAMAL.builder.push(cli.options[:output], no_cache: cli.options[:no_cache])
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
KAMAL.with_verbosity(:debug) do
|
|
62
|
+
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push, env: KAMAL.builder.push_env }
|
|
63
|
+
end
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
end
|
|
@@ -70,7 +70,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
|
70
70
|
def pull
|
|
71
71
|
login_to_registry_remotely unless KAMAL.registry.local?
|
|
72
72
|
|
|
73
|
-
forward_local_registry_port do
|
|
73
|
+
forward_local_registry_port(KAMAL.hosts, **KAMAL.config.ssh.options) do
|
|
74
74
|
if (first_hosts = mirror_hosts).any?
|
|
75
75
|
# Pull on a single host per mirror first to seed them
|
|
76
76
|
say "Pulling image on #{first_hosts.join(", ")} to seed the #{"mirror".pluralize(first_hosts.count)}...", :magenta
|
|
@@ -210,13 +210,30 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|
|
210
210
|
end
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
-
def
|
|
213
|
+
def forward_local_registry_port_for_remote_builder(&block)
|
|
214
|
+
if KAMAL.builder.remote?
|
|
215
|
+
remote_uri = URI(KAMAL.config.builder.remote)
|
|
216
|
+
forward_local_registry_port([ remote_uri.host ], **remote_builder_ssh_options(remote_uri), &block)
|
|
217
|
+
else
|
|
218
|
+
yield
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def forward_local_registry_port(hosts, **ssh_options, &block)
|
|
214
223
|
if KAMAL.config.registry.local?
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
forward(&block)
|
|
224
|
+
say "Setting up local registry port forwarding to #{hosts.join(', ')}..."
|
|
225
|
+
PortForwarding.new(hosts, KAMAL.config.registry.local_port, **ssh_options).forward(&block)
|
|
218
226
|
else
|
|
219
227
|
yield
|
|
220
228
|
end
|
|
221
229
|
end
|
|
230
|
+
|
|
231
|
+
def remote_builder_ssh_options(remote_uri)
|
|
232
|
+
{ user: remote_uri.user,
|
|
233
|
+
port: remote_uri.port,
|
|
234
|
+
keepalive: KAMAL.config.ssh.options[:keepalive],
|
|
235
|
+
keepalive_interval: KAMAL.config.ssh.options[:keepalive_interval],
|
|
236
|
+
logger: KAMAL.config.ssh.options[:logger]
|
|
237
|
+
}.compact
|
|
238
|
+
end
|
|
222
239
|
end
|
data/lib/kamal/cli/registry.rb
CHANGED
|
@@ -24,4 +24,26 @@ class Kamal::Cli::Registry < Kamal::Cli::Base
|
|
|
24
24
|
on(KAMAL.hosts) { execute *KAMAL.registry.logout } unless options[:skip_remote]
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
|
+
|
|
28
|
+
desc "login", "Log in to remote registry locally and remotely"
|
|
29
|
+
option :skip_local, aliases: "-L", type: :boolean, default: false, desc: "Skip local login"
|
|
30
|
+
option :skip_remote, aliases: "-R", type: :boolean, default: false, desc: "Skip remote login"
|
|
31
|
+
def login
|
|
32
|
+
if KAMAL.registry.local?
|
|
33
|
+
raise "Cannot use login command with a local registry. Use `kamal registry setup` instead."
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
setup
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
desc "logout", "Log out of remote registry locally and remotely"
|
|
40
|
+
option :skip_local, aliases: "-L", type: :boolean, default: false, desc: "Skip local login"
|
|
41
|
+
option :skip_remote, aliases: "-R", type: :boolean, default: false, desc: "Skip remote login"
|
|
42
|
+
def logout
|
|
43
|
+
if KAMAL.registry.local?
|
|
44
|
+
raise "Cannot use logout command with a local registry. Use `kamal registry remove` instead."
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
remove
|
|
48
|
+
end
|
|
27
49
|
end
|
|
@@ -127,6 +127,16 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
|
127
127
|
config.builder
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
+
def registry_config
|
|
131
|
+
config.registry
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def driver_options
|
|
135
|
+
if registry_config.local?
|
|
136
|
+
[ "--driver-opt", "network=host" ]
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
130
140
|
def platform_options(arches)
|
|
131
141
|
argumentize "--platform", arches.map { |arch| "linux/#{arch}" }.join(",") if arches.any?
|
|
132
142
|
end
|
|
@@ -8,14 +8,14 @@ class Kamal::Commands::Builder::Hybrid < Kamal::Commands::Builder::Remote
|
|
|
8
8
|
|
|
9
9
|
private
|
|
10
10
|
def builder_name
|
|
11
|
-
"kamal-hybrid-#{driver}-#{
|
|
11
|
+
"kamal-hybrid-#{driver}-#{remote_builder_name_suffix}"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def create_local_buildx
|
|
15
|
-
docker :buildx, :create, *platform_options(local_arches), "--name", builder_name, "--driver=#{driver}"
|
|
15
|
+
docker :buildx, :create, *platform_options(local_arches), "--name", builder_name, "--driver=#{driver}", *driver_options
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def append_remote_buildx
|
|
19
|
-
docker :buildx, :create, *platform_options(remote_arches), "--append", "--name", builder_name, remote_context_name
|
|
19
|
+
docker :buildx, :create, *platform_options(remote_arches), "--append", "--name", builder_name, *driver_options, remote_context_name
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -2,14 +2,7 @@ class Kamal::Commands::Builder::Local < Kamal::Commands::Builder::Base
|
|
|
2
2
|
def create
|
|
3
3
|
return if docker_driver?
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
if KAMAL.registry.local?
|
|
7
|
-
"--driver=#{driver} --driver-opt network=host"
|
|
8
|
-
else
|
|
9
|
-
"--driver=#{driver}"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
docker :buildx, :create, "--name", builder_name, options
|
|
5
|
+
docker :buildx, :create, "--name", builder_name, "--driver=#{driver}", *driver_options
|
|
13
6
|
end
|
|
14
7
|
|
|
15
8
|
def remove
|
|
@@ -18,7 +11,7 @@ class Kamal::Commands::Builder::Local < Kamal::Commands::Builder::Base
|
|
|
18
11
|
|
|
19
12
|
private
|
|
20
13
|
def builder_name
|
|
21
|
-
if
|
|
14
|
+
if registry_config.local?
|
|
22
15
|
"kamal-local-registry-#{driver}"
|
|
23
16
|
else
|
|
24
17
|
"kamal-local-#{driver}"
|
|
@@ -34,13 +34,17 @@ class Kamal::Commands::Builder::Remote < Kamal::Commands::Builder::Base
|
|
|
34
34
|
|
|
35
35
|
private
|
|
36
36
|
def builder_name
|
|
37
|
-
"kamal-remote-#{
|
|
37
|
+
"kamal-remote-#{remote_builder_name_suffix}"
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def remote_context_name
|
|
41
41
|
"#{builder_name}-context"
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def remote_builder_name_suffix
|
|
45
|
+
"#{remote.gsub(/[^a-z0-9_-]/, "-")}#{registry_config.local? ? "-local-registry" : "" }"
|
|
46
|
+
end
|
|
47
|
+
|
|
44
48
|
def inspect_buildx
|
|
45
49
|
pipe \
|
|
46
50
|
docker(:buildx, :inspect, builder_name),
|
|
@@ -62,7 +66,7 @@ class Kamal::Commands::Builder::Remote < Kamal::Commands::Builder::Base
|
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
def create_buildx
|
|
65
|
-
docker :buildx, :create, "--name", builder_name, remote_context_name
|
|
69
|
+
docker :buildx, :create, "--name", builder_name, *driver_options, remote_context_name
|
|
66
70
|
end
|
|
67
71
|
|
|
68
72
|
def remove_buildx
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
# Registry
|
|
2
2
|
#
|
|
3
3
|
# The default registry is Docker Hub, but you can change it using `registry/server`.
|
|
4
|
+
|
|
5
|
+
# Using a local container registry
|
|
6
|
+
#
|
|
7
|
+
# If the registry server starts with `localhost`, Kamal will start a local Docker registry
|
|
8
|
+
# on that port and push the app image to it.
|
|
9
|
+
registry:
|
|
10
|
+
server: localhost:5555
|
|
11
|
+
|
|
12
|
+
# Using Docker Hub as the container registry
|
|
4
13
|
#
|
|
5
14
|
# By default, Docker Hub creates public repositories. To avoid making your images public,
|
|
6
15
|
# set up a private repository before deploying, or change the default repository privacy
|
|
7
16
|
# settings to private in your [Docker Hub settings](https://hub.docker.com/repository-settings/default-privacy).
|
|
8
17
|
#
|
|
9
|
-
# A reference to a secret (in this case, `
|
|
18
|
+
# A reference to a secret (in this case, `KAMAL_REGISTRY_PASSWORD`) will look up the secret
|
|
10
19
|
# in the local environment:
|
|
11
20
|
registry:
|
|
12
|
-
server: registry.digitalocean.com
|
|
13
21
|
username:
|
|
14
|
-
-
|
|
22
|
+
- <your docker hub username>
|
|
15
23
|
password:
|
|
16
|
-
-
|
|
24
|
+
- KAMAL_REGISTRY_PASSWORD
|
|
17
25
|
|
|
18
26
|
# Using AWS ECR as the container registry
|
|
19
27
|
#
|
data/lib/kamal/configuration.rb
CHANGED
|
@@ -76,6 +76,7 @@ class Kamal::Configuration
|
|
|
76
76
|
ensure_no_traefik_reboot_hooks
|
|
77
77
|
ensure_one_host_for_ssl_roles
|
|
78
78
|
ensure_unique_hosts_for_ssl_roles
|
|
79
|
+
ensure_local_registry_remote_builder_has_ssh_url
|
|
79
80
|
end
|
|
80
81
|
|
|
81
82
|
def version=(version)
|
|
@@ -363,6 +364,16 @@ class Kamal::Configuration
|
|
|
363
364
|
true
|
|
364
365
|
end
|
|
365
366
|
|
|
367
|
+
def ensure_local_registry_remote_builder_has_ssh_url
|
|
368
|
+
if registry.local? && builder.remote?
|
|
369
|
+
unless URI(builder.remote).scheme == "ssh"
|
|
370
|
+
raise Kamal::ConfigurationError, "Local registry with remote builder requires an SSH URL (e.g., ssh://user@host)"
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
true
|
|
375
|
+
end
|
|
376
|
+
|
|
366
377
|
def role_names
|
|
367
378
|
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
|
|
368
379
|
end
|
data/lib/kamal/version.rb
CHANGED
data/lib/kamal.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kamal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.8.
|
|
4
|
+
version: 2.8.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Heinemeier Hansson
|
|
@@ -224,12 +224,12 @@ files:
|
|
|
224
224
|
- lib/kamal/cli/base.rb
|
|
225
225
|
- lib/kamal/cli/build.rb
|
|
226
226
|
- lib/kamal/cli/build/clone.rb
|
|
227
|
+
- lib/kamal/cli/build/port_forwarding.rb
|
|
227
228
|
- lib/kamal/cli/healthcheck/barrier.rb
|
|
228
229
|
- lib/kamal/cli/healthcheck/error.rb
|
|
229
230
|
- lib/kamal/cli/healthcheck/poller.rb
|
|
230
231
|
- lib/kamal/cli/lock.rb
|
|
231
232
|
- lib/kamal/cli/main.rb
|
|
232
|
-
- lib/kamal/cli/port_forwarding.rb
|
|
233
233
|
- lib/kamal/cli/proxy.rb
|
|
234
234
|
- lib/kamal/cli/prune.rb
|
|
235
235
|
- lib/kamal/cli/registry.rb
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
require "concurrent/atomic/count_down_latch"
|
|
2
|
-
|
|
3
|
-
class Kamal::Cli::PortForwarding
|
|
4
|
-
attr_reader :hosts, :port
|
|
5
|
-
|
|
6
|
-
def initialize(hosts, port)
|
|
7
|
-
@hosts = hosts
|
|
8
|
-
@port = port
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def forward
|
|
12
|
-
@done = false
|
|
13
|
-
forward_ports
|
|
14
|
-
|
|
15
|
-
yield
|
|
16
|
-
ensure
|
|
17
|
-
stop
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def stop
|
|
23
|
-
@done = true
|
|
24
|
-
@threads.to_a.each(&:join)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def forward_ports
|
|
28
|
-
ready = Concurrent::CountDownLatch.new(hosts.size)
|
|
29
|
-
|
|
30
|
-
@threads = hosts.map do |host|
|
|
31
|
-
Thread.new do
|
|
32
|
-
Net::SSH.start(host, KAMAL.config.ssh.user, **{ proxy: KAMAL.config.ssh.proxy }.compact) do |ssh|
|
|
33
|
-
ssh.forward.remote(port, "localhost", port, "127.0.0.1") do |remote_port, bind_address|
|
|
34
|
-
if remote_port == :error
|
|
35
|
-
raise "Failed to establish port forward on #{host}"
|
|
36
|
-
else
|
|
37
|
-
ready.count_down
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
ssh.loop(0.1) do
|
|
42
|
-
if @done
|
|
43
|
-
ssh.forward.cancel_remote(port, "127.0.0.1")
|
|
44
|
-
break
|
|
45
|
-
else
|
|
46
|
-
true
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
raise "Timed out waiting for port forwarding to be established" unless ready.wait(10)
|
|
54
|
-
end
|
|
55
|
-
end
|