Allow for fully native builds too

Skipping multiarch if there's a platform match between dev and prod.
This commit is contained in:
David Heinemeier Hansson
2023-01-13 09:31:47 +01:00
parent 05f1ef5ee8
commit 6ccb3d2319
6 changed files with 129 additions and 56 deletions

View File

@@ -1,37 +1,39 @@
require "mrsk/commands/base" require "mrsk/commands/base"
class Mrsk::Commands::Builder < Mrsk::Commands::Base class Mrsk::Commands::Builder < Mrsk::Commands::Base
def create delegate :create, :remove, :push, :pull, to: :target
docker :buildx, :create, "--use", "--name", "mrsk" delegate :native?, :multiarch?, :remote?, to: :name
def name
target.class.to_s.demodulize.downcase.inquiry
end end
def remove def target
docker :buildx, :rm, "mrsk" case
when config.builder.nil?
multiarch
when config.builder["multiarch"] == false
native
when config.builder["local"] && config.builder["local"]
multiarch_remote
else
raise ArgumentError, "Builder configuration incorrect: #{config.builder.inspect}"
end
end end
def push def native
docker :buildx, :build, "--push", "--platform linux/amd64,linux/arm64", "-t", config.absolute_image, "." @native ||= Mrsk::Commands::Builder::Native.new(config)
end end
def pull def multiarch
docker :pull, config.absolute_image @multiarch ||= Mrsk::Commands::Builder::Multiarch.new(config)
end end
def multiarch_remote
def create_context(arch, host) @multiarch_remote ||= Mrsk::Commands::Builder::Multiarch::Remote.new(config)
docker :context, :create, "mrsk-#{arch}", "--description", "'MRSK #{arch} Native Host'", "--docker", "'host=#{host}'"
end
def remove_context(arch)
docker :context, :rm, "mrsk-#{arch}"
end
def create_with_context(arch)
docker :buildx, :create, "--use", "--name", "mrsk", "mrsk-#{arch}", "--platform", "linux/#{arch}"
end
def append_context(arch)
docker :buildx, :create, "--append", "--name", "mrsk", "mrsk-#{arch}", "--platform", "linux/#{arch}"
end end
end end
require "mrsk/commands/builder/native"
require "mrsk/commands/builder/multiarch"
require "mrsk/commands/builder/multiarch/remote"

View File

@@ -0,0 +1,19 @@
require "mrsk/commands/base"
class Mrsk::Commands::Builder::Multiarch < Mrsk::Commands::Base
def create
docker :buildx, :create, "--use", "--name", "mrsk"
end
def remove
docker :buildx, :rm, "mrsk"
end
def push
docker :buildx, :build, "--push", "--platform linux/amd64,linux/arm64", "-t", config.absolute_image, "."
end
def pull
docker :pull, config.absolute_image
end
end

View File

@@ -0,0 +1,19 @@
require "mrsk/commands/builder/multiarch"
class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Multiarch
def create(arch)
super + [ "mrsk-#{arch}", "--platform", "linux/#{arch}" ]
end
def append(arch)
docker :buildx, :create, "--append", "--name", "mrsk", "mrsk-#{arch}", "--platform", "linux/#{arch}"
end
def create_context(arch, host)
docker :context, :create, "mrsk-#{arch}", "--description", "'MRSK #{arch} Native Host'", "--docker", "'host=#{host}'"
end
def remove_context(arch)
docker :context, :rm, "mrsk-#{arch}"
end
end

View File

@@ -0,0 +1,19 @@
require "mrsk/commands/base"
class Mrsk::Commands::Builder::Native < Mrsk::Commands::Base
def create
# No op on native
end
def remove
# No op on native
end
def push
docker :build, "--push", "-t", config.absolute_image, "."
end
def pull
docker :pull, config.absolute_image
end
end

View File

@@ -13,7 +13,7 @@ namespace :mrsk do
execute *MRSK.builder.push execute *MRSK.builder.push
rescue SSHKit::Command::Failed => e rescue SSHKit::Command::Failed => e
error "Missing compatible buildx builder, so creating a new one first" error "Missing compatible buildx builder, so creating a new one first"
execute *MRSK.builder.create Rake::Task["mrsk:build:create"].invoke
execute *MRSK.builder.push execute *MRSK.builder.push
end end
end unless ENV["VERSION"] end unless ENV["VERSION"]
@@ -24,17 +24,25 @@ namespace :mrsk do
on(MRSK.config.hosts) { execute *MRSK.builder.pull } on(MRSK.config.hosts) { execute *MRSK.builder.pull }
end end
desc "Create a local buildx setup to produce multi-arch images" desc "Create a local build setup"
task :create do task :create do
run_locally do run_locally do
execute *MRSK.builder.create if MRSK.builder.remote?
Rake::Task["mrsk:build:remote:create"].invoke
else
execute *MRSK.builder.create
end
end end
end end
desc "Remove local buildx setup" desc "Remove local build setup"
task :remove do task :remove do
run_locally do run_locally do
execute *MRSK.builder.remove if MRSK.builder.remote?
Rake::Task["mrsk:build:remote:create"].invoke
else
execute *MRSK.builder.remove
end
end end
end end
@@ -44,28 +52,16 @@ namespace :mrsk do
namespace :create do namespace :create do
task :context do task :context do
if MRSK.config.builder && run_locally do
(local = MRSK.config.builder["local"]) && execute *MRSK.builder.create_context(local["arch"], local["host"])
(remote = MRSK.config.builder["remote"]) execute *MRSK.builder.create_context(remote["arch"], remote["host"])
run_locally do
execute *MRSK.builder.create_context(local["arch"], local["host"])
execute *MRSK.builder.create_context(remote["arch"], remote["host"])
end
else
error "Missing configuration of builder:local/remote in config"
end end
end end
task :buildx do task :buildx do
if MRSK.config.builder && run_locally do
(local = MRSK.config.builder["local"]) && execute *MRSK.builder.create_with_context(local["arch"])
(remote = MRSK.config.builder["remote"]) execute *MRSK.builder.append_context(remote["arch"])
run_locally do
execute *MRSK.builder.create_with_context(local["arch"])
execute *MRSK.builder.append_context(remote["arch"])
end
else
error "Missing configuration of builder:local/remote in config"
end end
end end
end end
@@ -76,15 +72,9 @@ namespace :mrsk do
namespace :remove do namespace :remove do
task :context do task :context do
if MRSK.config.builder && run_locally do
(local = MRSK.config.builder["local"]) && execute *MRSK.builder.remove_context(local["arch"])
(remote = MRSK.config.builder["remote"]) execute *MRSK.builder.remove_context(remote["arch"])
run_locally do
execute *MRSK.builder.remove_context(local["arch"])
execute *MRSK.builder.remove_context(remote["arch"])
end
else
error "Missing configuration of builder:local/remote in config"
end end
end end
end end

View File

@@ -0,0 +1,24 @@
require "test_helper"
require "mrsk/configuration"
require "mrsk/commands/builder"
class BuilderCommandTest < ActiveSupport::TestCase
setup do
@config = { service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ] }
end
test "target multiarch by default" do
builder = Mrsk::Commands::Builder.new(Mrsk::Configuration.new(@config))
assert builder.multiarch?
end
test "target native when multiarch is off" do
builder = Mrsk::Commands::Builder.new(Mrsk::Configuration.new(@config.merge({ builder: { "multiarch" => false } })))
assert builder.native?
end
test "target multiarch remote when local and remote is set" do
builder = Mrsk::Commands::Builder.new(Mrsk::Configuration.new(@config.merge({ builder: { "local" => { }, "remote" => { } } })))
assert builder.remote?
end
end