diff --git a/README.md b/README.md index e133176e..3643425e 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/lib/mrsk/commands/builder.rb b/lib/mrsk/commands/builder.rb index ce18fc63..e24768d1 100644 --- a/lib/mrsk/commands/builder.rb +++ b/lib/mrsk/commands/builder.rb @@ -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" diff --git a/lib/mrsk/commands/builder/native/remote.rb b/lib/mrsk/commands/builder/native/remote.rb new file mode 100644 index 00000000..c7cecf89 --- /dev/null +++ b/lib/mrsk/commands/builder/native/remote.rb @@ -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 diff --git a/test/commands/builder_test.rb b/test/commands/builder_test.rb index 16c8f1ca..2a453080 100644 --- a/test/commands/builder_test.rb +++ b/test/commands/builder_test.rb @@ -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