Docker login if exec might pull image

The `app exec` and `accessory exec` commands will run `docker run` if
they are not set to reuse existing containers. This might need to pull
an image so let's make sure we are logged in before running the command.

Fixes: https://github.com/basecamp/kamal/issues/1163
This commit is contained in:
Donal McBreen
2025-04-18 14:44:43 +01:00
parent cd9d01b016
commit 7a63cacb09
4 changed files with 8 additions and 0 deletions

View File

@@ -152,6 +152,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
when options[:interactive] when options[:interactive]
say "Launching interactive command via SSH from new container...", :magenta say "Launching interactive command via SSH from new container...", :magenta
on(accessory.hosts.first) { execute *KAMAL.registry.login }
run_locally { exec accessory.execute_in_new_container_over_ssh(cmd) } run_locally { exec accessory.execute_in_new_container_over_ssh(cmd) }
when options[:reuse] when options[:reuse]
@@ -164,6 +165,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
else else
say "Launching command from new container...", :magenta say "Launching command from new container...", :magenta
on(hosts) do |host| on(hosts) do |host|
execute *KAMAL.registry.login
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on #{name} accessory"), verbosity: :debug execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on #{name} accessory"), verbosity: :debug
puts_by_host host, capture_with_info(*accessory.execute_in_new_container(cmd)) puts_by_host host, capture_with_info(*accessory.execute_in_new_container(cmd))
end end

View File

@@ -127,6 +127,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
say "Get most recent version available as an image...", :magenta unless options[:version] say "Get most recent version available as an image...", :magenta unless options[:version]
using_version(version_or_latest) do |version| using_version(version_or_latest) do |version|
say "Launching interactive command with version #{version} via SSH from new container on #{KAMAL.primary_host}...", :magenta say "Launching interactive command with version #{version} via SSH from new container on #{KAMAL.primary_host}...", :magenta
on(KAMAL.primary_host) { execute *KAMAL.registry.login }
run_locally do run_locally do
exec KAMAL.app(role: KAMAL.primary_role, host: KAMAL.primary_host).execute_in_new_container_over_ssh(cmd, env: env) exec KAMAL.app(role: KAMAL.primary_role, host: KAMAL.primary_host).execute_in_new_container_over_ssh(cmd, env: env)
end end
@@ -152,6 +153,8 @@ class Kamal::Cli::App < Kamal::Cli::Base
using_version(version_or_latest) do |version| using_version(version_or_latest) do |version|
say "Launching command with version #{version} from new container...", :magenta say "Launching command with version #{version} from new container...", :magenta
on(KAMAL.app_hosts) do |host| on(KAMAL.app_hosts) do |host|
execute *KAMAL.registry.login
roles = KAMAL.roles_on(host) roles = KAMAL.roles_on(host)
roles.each do |role| roles.each do |role|

View File

@@ -115,6 +115,7 @@ class CliAccessoryTest < CliTestCase
test "exec" do test "exec" do
run_command("exec", "mysql", "mysql -v").tap do |output| run_command("exec", "mysql", "mysql -v").tap do |output|
assert_match "docker login private.registry -u [REDACTED] -p [REDACTED]", output
assert_match "Launching command from new container", output assert_match "Launching command from new container", output
assert_match "mysql -v", output assert_match "mysql -v", output
end end

View File

@@ -307,6 +307,7 @@ class CliAppTest < CliTestCase
test "exec" do test "exec" do
run_command("exec", "ruby -v").tap do |output| run_command("exec", "ruby -v").tap do |output|
assert_match "docker login -u [REDACTED] -p [REDACTED]", output
assert_match "docker run --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size=\"10m\" dhh/app:latest ruby -v", output assert_match "docker run --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size=\"10m\" dhh/app:latest ruby -v", output
end end
end end
@@ -355,6 +356,7 @@ class CliAppTest < CliTestCase
run_command("exec", "-i", "ruby -v").tap do |output| run_command("exec", "-i", "ruby -v").tap do |output|
assert_hook_ran "pre-connect", output assert_hook_ran "pre-connect", output
assert_match "docker login -u [REDACTED] -p [REDACTED]", output
assert_match "Get most recent version available as an image...", output assert_match "Get most recent version available as an image...", output
assert_match "Launching interactive command with version latest via SSH from new container on 1.1.1.1...", output assert_match "Launching interactive command with version latest via SSH from new container on 1.1.1.1...", output
end end