Skip to content

Commit 10e40a7

Browse files
committed
Improve port forwarding setup
- Include keepalive options when forwarding port for remote builder - Log port forwarding errors.
1 parent 0055338 commit 10e40a7

File tree

3 files changed

+60
-36
lines changed

3 files changed

+60
-36
lines changed

lib/kamal/cli/build.rb

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def push
7070
def pull
7171
login_to_registry_remotely unless KAMAL.registry.local?
7272

73-
forward_local_registry_port(KAMAL.hosts) do
73+
forward_local_registry_port(KAMAL.hosts, **KAMAL.config.ssh.options) do
7474
if (first_hosts = mirror_hosts).any?
7575
#  Pull on a single host per mirror first to seed them
7676
say "Pulling image on #{first_hosts.join(", ")} to seed the #{"mirror".pluralize(first_hosts.count)}...", :magenta
@@ -213,17 +213,27 @@ def login_to_registry_remotely
213213
def forward_local_registry_port_for_remote_builder(&block)
214214
if KAMAL.builder.remote?
215215
remote_uri = URI(KAMAL.config.builder.remote)
216-
forward_local_registry_port([ remote_uri.host ], user: remote_uri.user, proxy: nil, ssh_port: remote_uri.port, &block)
216+
forward_local_registry_port([ remote_uri.host ], **remote_builder_ssh_options(remote_uri), &block)
217217
else
218218
yield
219219
end
220220
end
221221

222-
def forward_local_registry_port(hosts, user: KAMAL.config.ssh.user, proxy: KAMAL.config.ssh.proxy, ssh_port: nil, &block)
222+
def forward_local_registry_port(hosts, **ssh_options, &block)
223223
if KAMAL.config.registry.local?
224-
PortForwarding.new(hosts, KAMAL.config.registry.local_port, user: user, proxy: proxy, ssh_port: ssh_port).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)
225226
else
226227
yield
227228
end
228229
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
229239
end
Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
require "concurrent/atomic/count_down_latch"
22

33
class Kamal::Cli::Build::PortForwarding
4-
attr_reader :hosts, :port, :user, :proxy, :ssh_port
4+
attr_reader :hosts, :port, :ssh_options
55

6-
def initialize(hosts, port, user: nil, proxy: nil, ssh_port: nil)
6+
def initialize(hosts, port, **ssh_options)
77
@hosts = hosts
88
@port = port
9-
@user = user
10-
@proxy = proxy
11-
@ssh_port = ssh_port
9+
@ssh_options = ssh_options
1210
end
1311

1412
def forward
@@ -21,38 +19,48 @@ def forward
2119
end
2220

2321
private
22+
def stop
23+
@done = true
24+
@threads.to_a.each(&:join)
25+
end
2426

25-
def stop
26-
@done = true
27-
@threads.to_a.each(&:join)
28-
end
27+
def forward_ports
28+
ready = Concurrent::CountDownLatch.new(hosts.size)
2929

30-
def forward_ports
31-
ready = Concurrent::CountDownLatch.new(hosts.size)
32-
33-
@threads = hosts.map do |host|
34-
Thread.new do
35-
Net::SSH.start(host, user, **{ port: ssh_port, proxy: proxy }.compact) do |ssh|
36-
ssh.forward.remote(port, "localhost", port, "127.0.0.1") do |remote_port, bind_address|
37-
if remote_port == :error
38-
raise "Failed to establish port forward on #{host}"
39-
else
40-
ready.count_down
41-
end
42-
end
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
4341

44-
ssh.loop(0.1) do
45-
if @done
46-
ssh.forward.cancel_remote(port, "127.0.0.1")
47-
break
48-
else
49-
true
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
5050
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
5156
end
5257
end
5358
end
59+
60+
raise "Timed out waiting for port forwarding to be established" unless ready.wait(30)
5461
end
5562

56-
raise "Timed out waiting for port forwarding to be established" unless ready.wait(30)
57-
end
63+
def error(message)
64+
SSHKit.config.output.error(message)
65+
end
5866
end

test/cli/build_test.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,14 @@ class CliBuildTest < CliTestCase
428428
port_forwarding_mock = mock("port_forwarding")
429429
port_forwarding_mock.expects(:forward).yields
430430
Kamal::Cli::Build::PortForwarding.expects(:new)
431-
.with([ "1.1.1.1", "1.1.1.2" ], 5000, user: "root", proxy: nil, ssh_port: nil)
432-
.returns(port_forwarding_mock)
431+
.with([ "1.1.1.1", "1.1.1.2" ], 5000, has_entries(
432+
user: "root",
433+
port: 22,
434+
logger: instance_of(Logger),
435+
keepalive: true,
436+
keepalive_interval: 30
437+
)
438+
).returns(port_forwarding_mock)
433439

434440
run_command("pull", fixture: :with_local_registry).tap do |output|
435441
assert_match /docker pull localhost:5000\/dhh\/app:999/, output

0 commit comments

Comments
 (0)