Add option for remote building of single-arch

This commit is contained in:
David Heinemeier Hansson
2023-01-22 10:06:04 +01:00
parent 5c75404fe9
commit 287798ad57
4 changed files with 109 additions and 5 deletions

View File

@@ -164,6 +164,21 @@ Note: You must have Docker running on the remote host being used as a builder.
With that configuration in place, you can setup the local/remote configuration using `mrsk build create`. If you wish to remove the contexts and buildx instances again, you can run `mrsk build remove`. If you had already built using the standard emulation setup, run `mrsk build remove` before doing `mrsk build remote`.
### Configuring remote builder for single-arch
If you're developing on ARM64 (like Apple Silicon), want to deploy on AMD64 (x86 64-bit), but don't need to run the image locally (or on other ARM64 hosts), you can configure a remote builder that just targets AMD64. This is a bit faster than building with multi-arch, as there's nothing to build locally.
```yaml
builder:
remote:
arch: amd64
host: ssh://root@192.168.0.1
```
Note: You must have Docker running on the remote host being used as a builder.
With that configuration in place, you can setup the remote configuration using `mrsk build create`. If you wish to remove the contexts and buildx instances again, you can run `mrsk build remove`. If you had already built using the standard emulation setup, run `mrsk build remove` before doing `mrsk build remote`.
### Configuring native builder when multi-arch isn't needed
If you're developing on the same architecture as the one you're deploying on, you can speed up the build a lot by forgoing a multi-arch image. This can be done by configuring the builder like so:

View File

@@ -2,10 +2,9 @@ require "mrsk/commands/base"
class Mrsk::Commands::Builder < Mrsk::Commands::Base
delegate :create, :remove, :push, :pull, :info, to: :target
delegate :native?, :multiarch?, :remote?, to: :name
def name
target.class.to_s.demodulize.downcase.inquiry
target.class.to_s.remove("Mrsk::Commands::Builder::").underscore
end
def target
@@ -14,6 +13,8 @@ class Mrsk::Commands::Builder < Mrsk::Commands::Base
native
when config.builder && config.builder["local"] && config.builder["remote"]
multiarch_remote
when config.builder && config.builder["remote"]
native_remote
else
multiarch
end
@@ -23,6 +24,10 @@ class Mrsk::Commands::Builder < Mrsk::Commands::Base
@native ||= Mrsk::Commands::Builder::Native.new(config)
end
def native_remote
@native ||= Mrsk::Commands::Builder::Native::Remote.new(config)
end
def multiarch
@multiarch ||= Mrsk::Commands::Builder::Multiarch.new(config)
end
@@ -33,5 +38,6 @@ class Mrsk::Commands::Builder < Mrsk::Commands::Base
end
require "mrsk/commands/builder/native"
require "mrsk/commands/builder/native/remote"
require "mrsk/commands/builder/multiarch"
require "mrsk/commands/builder/multiarch/remote"

View File

@@ -0,0 +1,71 @@
require "mrsk/commands/builder/native"
class Mrsk::Commands::Builder::Native::Remote < Mrsk::Commands::Builder::Native
def create
combine \
create_context,
create_buildx
end
def remove
combine \
remove_context,
remove_buildx
end
def push
docker :buildx, :build,
"--push",
"--platform", platform,
"-t", config.absolute_image,
*build_args,
*build_secrets,
"."
end
def info
combine \
docker(:context, :ls),
docker(:buildx, :ls)
end
private
def arch
config.builder["remote"]["arch"]
end
def host
config.builder["remote"]["host"]
end
def builder_name
"mrsk-#{config.service}"
end
def builder_name_with_arch
"#{builder_name}-#{arch}"
end
def platform
"linux/#{arch}"
end
def create_context
docker :context, :create,
builder_name_with_arch, "--description", "'#{builder_name} #{arch} native host'", "--docker", "'host=#{host}'"
end
def remove_context
docker :context, :rm, builder_name_with_arch
end
def create_buildx
docker :buildx, :create,
"--use", "--name", builder_name, builder_name_with_arch, "--platform", platform
end
def remove_buildx
docker :buildx, :rm, builder_name
end
end

View File

@@ -8,15 +8,27 @@ class CommandsBuilderTest < ActiveSupport::TestCase
end
test "target multiarch by default" do
assert new_builder_command.multiarch?
builder = new_builder_command
assert_equal "multiarch", builder.name
assert_equal [:docker, :buildx, :build, "--push", "--platform linux/amd64,linux/arm64", "-t", "dhh/app:123", "."], builder.push
end
test "target native when multiarch is off" do
assert new_builder_command(builder: { "multiarch" => false }).native?
builder = new_builder_command(builder: { "multiarch" => false })
assert_equal "native", builder.name
assert_equal [:docker, :build, "-t", "dhh/app:123", ".", "&&", :docker, :push, "dhh/app:123"], builder.push
end
test "target multiarch remote when local and remote is set" do
assert new_builder_command(builder: { "local" => { }, "remote" => { } }).remote?
builder = new_builder_command(builder: { "local" => { }, "remote" => { } })
assert_equal "multiarch/remote", builder.name
assert_equal [:docker, :buildx, :build, "--push", "--platform linux/amd64,linux/arm64", "-t", "dhh/app:123", "."], builder.push
end
test "target native remote when only remote is set" do
builder = new_builder_command(builder: { "remote" => { "arch" => "amd64" } })
assert_equal "native/remote", builder.name
assert_equal [:docker, :buildx, :build, "--push", "--platform", "linux/amd64", "-t", "dhh/app:123", "."], builder.push
end
test "build args" do