Combine multiarch and native/cache builders

Combine the two builders, as they are almost identical. The only
difference was whether the platforms were set.

The native cached builder wasn't using the context it created, so now
we do.

We'll set the driver to `docker-container` - it seems to be the default
but the Docker docs claim it is `docker`.
This commit is contained in:
Donal McBreen
2024-06-06 09:43:58 +01:00
parent f48987aa03
commit 2a4a8ac859
8 changed files with 76 additions and 82 deletions

View File

@@ -11,22 +11,17 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
end
def target
if config.builder.multiarch?
if config.builder.remote?
if config.builder.local?
multiarch_remote
else
native_remote
end
else
multiarch
end
else
if config.builder.cached?
native_cached
else
case
when !config.builder.multiarch? && !config.builder.cached?
native
end
when !config.builder.multiarch? && config.builder.cached?
local
when config.builder.local? && config.builder.remote?
multiarch_remote
when config.builder.remote?
native_remote
else
local
end
end
@@ -34,16 +29,12 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
@native ||= Kamal::Commands::Builder::Native.new(config)
end
def native_cached
@native ||= Kamal::Commands::Builder::Native::Cached.new(config)
end
def native_remote
@native ||= Kamal::Commands::Builder::Native::Remote.new(config)
end
def multiarch
@multiarch ||= Kamal::Commands::Builder::Multiarch.new(config)
def local
@local ||= Kamal::Commands::Builder::Local.new(config)
end
def multiarch_remote

View File

@@ -5,7 +5,10 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
ENDPOINT_DOCKER_HOST_INSPECT = "'{{.Endpoints.docker.Host}}'"
delegate :argumentize, to: Kamal::Utils
delegate :args, :secrets, :dockerfile, :target, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, to: :builder_config
delegate \
:args, :secrets, :dockerfile, :target, :local_arch, :local_host, :remote_arch, :remote_host,
:cache_from, :cache_to, :multiarch?, :ssh,
to: :builder_config
def clean
docker :image, :rm, "--force", config.absolute_image

View File

@@ -1,6 +1,6 @@
class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
class Kamal::Commands::Builder::Local < Kamal::Commands::Builder::Base
def create
docker :buildx, :create, "--use", "--name", builder_name
docker :buildx, :create, "--name", builder_name, "--driver=docker-container"
end
def remove
@@ -16,7 +16,7 @@ class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
def push
docker :buildx, :build,
"--push",
"--platform", platform_names,
*platform_options,
"--builder", builder_name,
*build_options,
build_context
@@ -28,14 +28,16 @@ class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
private
def builder_name
"kamal-#{config.service}-multiarch"
"kamal-local"
end
def platform_names
def platform_options
if multiarch?
if local_arch
"linux/#{local_arch}"
[ "--platform", "linux/#{local_arch}" ]
else
"linux/amd64,linux/arm64"
[ "--platform", "linux/amd64,linux/arm64" ]
end
end
end
end

View File

@@ -1,4 +1,4 @@
class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Multiarch
class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Base
def create
combine \
create_contexts,
@@ -12,6 +12,21 @@ class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Mu
super
end
def info
combine \
docker(:context, :ls),
docker(:buildx, :ls)
end
def push
docker :buildx, :build,
"--push",
*platform_options,
"--builder", builder_name,
*build_options,
build_context
end
def context_hosts
chain \
context_host(builder_name_with_arch(local_arch)),
@@ -24,7 +39,7 @@ class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Mu
private
def builder_name
super + "-remote"
"kamal-#{config.service}-multiarch-remote"
end
def builder_name_with_arch(arch)
@@ -58,4 +73,12 @@ class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Mu
def remove_context(arch)
docker :context, :rm, builder_name_with_arch(arch)
end
def platform_options
if local_arch
[ "--platform", "linux/#{local_arch}" ]
else
[ "--platform", "linux/amd64,linux/arm64" ]
end
end
end

View File

@@ -1,25 +0,0 @@
class Kamal::Commands::Builder::Native::Cached < Kamal::Commands::Builder::Native
def create
docker :buildx, :create, "--name", builder_name, "--use", "--driver=docker-container"
end
def remove
docker :buildx, :rm, builder_name
end
def push
docker :buildx, :build,
"--push",
*build_options,
build_context
end
def context_hosts
docker :buildx, :inspect, builder_name, "> /dev/null"
end
private
def builder_name
"kamal-#{config.service}-native-cached"
end
end

View File

@@ -22,7 +22,7 @@ class CliBuildTest < CliTestCase
.returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-app-multiarch", "> /dev/null")
.with(:docker, :buildx, :inspect, "kamal-local", "> /dev/null")
.returns("")
run_command("push", "--verbose").tap do |output|
@@ -30,7 +30,7 @@ class CliBuildTest < CliTestCase
assert_match /Cloning repo into build directory/, output
assert_match /git -C #{Dir.tmpdir}\/kamal-clones\/app-#{pwd_sha} clone #{Dir.pwd}/, output
assert_match /docker --version && docker buildx version/, output
assert_match /docker buildx build --push --platform linux\/amd64,linux\/arm64 --builder kamal-app-multiarch -t dhh\/app:999 -t dhh\/app:latest --label service="app" --file Dockerfile \. as .*@localhost/, output
assert_match /docker buildx build --push --platform linux\/amd64,linux\/arm64 --builder kamal-local -t dhh\/app:999 -t dhh\/app:latest --label service="app" --file Dockerfile \. as .*@localhost/, output
end
end
end
@@ -52,7 +52,7 @@ class CliBuildTest < CliTestCase
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :clean, "-fdx")
SSHKit::Backend::Abstract.any_instance.expects(:execute)
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64,linux/arm64", "--builder", "kamal-app-multiarch", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64,linux/arm64", "--builder", "kamal-local", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:git, "-C", anything, :"rev-parse", :HEAD)
@@ -77,7 +77,7 @@ class CliBuildTest < CliTestCase
assert_no_match /Cloning repo into build directory/, output
assert_hook_ran "pre-build", output, **hook_variables
assert_match /docker --version && docker buildx version/, output
assert_match /docker buildx build --push --platform linux\/amd64,linux\/arm64 --builder kamal-app-multiarch -t dhh\/app:999 -t dhh\/app:latest --label service="app" --file Dockerfile . as .*@localhost/, output
assert_match /docker buildx build --push --platform linux\/amd64,linux\/arm64 --builder kamal-local -t dhh\/app:999 -t dhh\/app:latest --label service="app" --file Dockerfile . as .*@localhost/, output
end
end
@@ -123,10 +123,10 @@ class CliBuildTest < CliTestCase
.with(:docker, "--version", "&&", :docker, :buildx, "version")
SSHKit::Backend::Abstract.any_instance.expects(:execute)
.with(:docker, :buildx, :create, "--use", "--name", "kamal-app-multiarch")
.with(:docker, :buildx, :create, "--name", "kamal-local", "--driver=docker-container")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-app-multiarch", "> /dev/null")
.with(:docker, :buildx, :inspect, "kamal-local", "> /dev/null")
.raises(SSHKit::Command::Failed.new("no builder"))
SSHKit::Backend::Abstract.any_instance.expects(:execute).with { |*args| args.first.start_with?("git") }
@@ -140,7 +140,7 @@ class CliBuildTest < CliTestCase
.returns("")
SSHKit::Backend::Abstract.any_instance.expects(:execute)
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64,linux/arm64", "--builder", "kamal-app-multiarch", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64,linux/arm64", "--builder", "kamal-local", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
run_command("push").tap do |output|
assert_match /WARN Missing compatible builder, so creating a new one first/, output
@@ -206,7 +206,7 @@ class CliBuildTest < CliTestCase
test "create" do
run_command("create").tap do |output|
assert_match /docker buildx create --use --name kamal-app-multiarch/, output
assert_match /docker buildx create --name kamal-local --driver=docker-container/, output
end
end
@@ -239,7 +239,7 @@ class CliBuildTest < CliTestCase
test "remove" do
run_command("remove").tap do |output|
assert_match /docker buildx rm kamal-app-multiarch/, output
assert_match /docker buildx rm kamal-local/, output
end
end
@@ -249,7 +249,7 @@ class CliBuildTest < CliTestCase
.returns("docker builder info")
run_command("details").tap do |output|
assert_match /Builder: multiarch/, output
assert_match /Builder: local/, output
assert_match /docker builder info/, output
end
end

View File

@@ -122,7 +122,7 @@ class CliMainTest < CliTestCase
.returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-app-multiarch", "> /dev/null")
.with(:docker, :buildx, :inspect, "kamal-local", "> /dev/null")
.returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
@@ -160,7 +160,7 @@ class CliMainTest < CliTestCase
.returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-app-multiarch", "> /dev/null")
.with(:docker, :buildx, :inspect, "kamal-local", "> /dev/null")
.returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)

View File

@@ -7,9 +7,9 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "target multiarch by default" do
builder = new_builder_command(builder: { "cache" => { "type" => "gha" } })
assert_equal "multiarch", builder.name
assert_equal "local", builder.name
assert_equal \
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-app-multiarch -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-local -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
builder.push.join(" ")
end
@@ -23,9 +23,9 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "target native cached when multiarch is off and cache is set" do
builder = new_builder_command(builder: { "multiarch" => false, "cache" => { "type" => "gha" } })
assert_equal "native/cached", builder.name
assert_equal "local", builder.name
assert_equal \
"docker buildx build --push -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
"docker buildx build --push --builder kamal-local -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
builder.push.join(" ")
end
@@ -39,9 +39,9 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "target multiarch local when arch is set" do
builder = new_builder_command(builder: { "local" => { "arch" => "amd64" } })
assert_equal "multiarch", builder.name
assert_equal "local", builder.name
assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-app-multiarch -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile .",
"docker buildx build --push --platform linux/amd64 --builder kamal-local -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile .",
builder.push.join(" ")
end
@@ -93,7 +93,7 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "build context" do
builder = new_builder_command(builder: { "context" => ".." })
assert_equal \
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-app-multiarch -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile ..",
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-local -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile ..",
builder.push.join(" ")
end
@@ -107,7 +107,7 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "multiarch push with build args" do
builder = new_builder_command(builder: { "args" => { "a" => 1, "b" => 2 } })
assert_equal \
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-app-multiarch -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --build-arg a=\"1\" --build-arg b=\"2\" --file Dockerfile .",
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-local -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --build-arg a=\"1\" --build-arg b=\"2\" --file Dockerfile .",
builder.push.join(" ")
end
@@ -133,7 +133,7 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "multiarch context build" do
builder = new_builder_command(builder: { "context" => "./foo" })
assert_equal \
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-app-multiarch -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile ./foo",
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-local -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile ./foo",
builder.push.join(" ")
end
@@ -147,7 +147,7 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "cached context build" do
builder = new_builder_command(builder: { "multiarch" => false, "context" => "./foo", "cache" => { "type" => "gha" } })
assert_equal \
"docker buildx build --push -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile ./foo",
"docker buildx build --push --builder kamal-local -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile ./foo",
builder.push.join(" ")
end
@@ -160,7 +160,7 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "multiarch context hosts" do
command = new_builder_command
assert_equal "docker buildx inspect kamal-app-multiarch > /dev/null", command.context_hosts.join(" ")
assert_equal "docker buildx inspect kamal-local > /dev/null", command.context_hosts.join(" ")
assert_equal "", command.config_context_hosts.join(" ")
end
@@ -172,7 +172,7 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "native cached context hosts" do
command = new_builder_command(builder: { "multiarch" => false, "cache" => { "type" => "registry" } })
assert_equal "docker buildx inspect kamal-app-native-cached > /dev/null", command.context_hosts.join(" ")
assert_equal "docker buildx inspect kamal-local > /dev/null", command.context_hosts.join(" ")
assert_equal "", command.config_context_hosts.join(" ")
end