Simplify the builders configuration
1. Add driver as an option, defaulting to `docker-container`. For a
"native" build you can set it to `docker`
2. Set arch as a array of architectures to build for, defaulting to
`[ "amd64", "arm64" ]` unless you are using the docker driver in
which case we default to not setting a platform
3. Remote is now just a connection string for the remote builder
4. If remote is set, we only use it for non-local arches, if we are
only building for the local arch, we'll ignore it.
Examples:
On arm64, build for arm64 locally, amd64 remotely or
On amd64, build for amd64 locally, arm64 remotely:
```yaml
builder:
remote: ssh://docker@docker-builder
```
On arm64, build amd64 on remote,
On amd64 build locally:
```yaml
builder:
arch:
- amd64
remote:
host: ssh://docker@docker-builder
```
Build amd64 on local:
```yaml
builder:
arch:
- amd64
```
Use docker driver, building for local arch:
```yaml
builder:
driver: docker
```
This commit is contained in:
committed by
Donal McBreen
parent
cffb6c3d7e
commit
56268d724d
@@ -66,7 +66,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
||||
|
||||
desc "create", "Create a build setup"
|
||||
def create
|
||||
if (remote_host = KAMAL.config.builder.remote_host)
|
||||
if (remote_host = KAMAL.config.builder.remote)
|
||||
connect_to_remote_host(remote_host)
|
||||
end
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ require "active_support/core_ext/string/filters"
|
||||
|
||||
class Kamal::Commands::Builder < Kamal::Commands::Base
|
||||
delegate :create, :remove, :push, :clean, :pull, :info, :buildx_inspect, :validate_image, :first_mirror, to: :target
|
||||
delegate :multiarch?, :local?, :remote?, to: "config.builder"
|
||||
delegate :local?, :remote?, to: "config.builder"
|
||||
|
||||
include Clone
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
||||
|
||||
delegate :argumentize, to: Kamal::Utils
|
||||
delegate \
|
||||
:args, :secrets, :dockerfile, :target, :local_arch, :remote_arch, :remote_host,
|
||||
:cache_from, :cache_to, :multiarch?, :ssh, :driver, :docker_driver?,
|
||||
:args, :secrets, :dockerfile, :target, :arches, :local_arches, :remote_arches, :remote,
|
||||
:cache_from, :cache_to, :ssh, :driver, :docker_driver?,
|
||||
to: :builder_config
|
||||
|
||||
def clean
|
||||
@@ -16,7 +16,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
||||
def push
|
||||
docker :build,
|
||||
"--push",
|
||||
*platform_options,
|
||||
*platform_options(arches),
|
||||
*([ "--builder", builder_name ] unless docker_driver?),
|
||||
*build_options,
|
||||
build_context
|
||||
@@ -33,7 +33,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
||||
end
|
||||
|
||||
def buildx_inspect
|
||||
docker :buildx, :inspect, builder_name
|
||||
docker :buildx, :inspect, builder_name unless docker_driver?
|
||||
end
|
||||
|
||||
def build_options
|
||||
@@ -104,4 +104,8 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
||||
def context_host(builder_name)
|
||||
docker :context, :inspect, builder_name, "--format", ENDPOINT_DOCKER_HOST_INSPECT
|
||||
end
|
||||
|
||||
def platform_options(arches)
|
||||
argumentize "--platform", arches.map { |arch| "linux/#{arch}" }.join(",") if arches.any?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,18 +8,14 @@ class Kamal::Commands::Builder::Hybrid < Kamal::Commands::Builder::Remote
|
||||
|
||||
private
|
||||
def builder_name
|
||||
"kamal-hybrid-#{driver}-#{local_arch}-#{remote_arch}-#{remote_host.gsub(/[^a-z0-9_-]/, "-")}"
|
||||
"kamal-hybrid-#{driver}-#{remote.gsub(/[^a-z0-9_-]/, "-")}"
|
||||
end
|
||||
|
||||
def create_local_buildx
|
||||
docker :buildx, :create, "--name", builder_name, "--platform", "linux/#{local_arch}", "--driver=#{driver}"
|
||||
docker :buildx, :create, *platform_options(local_arches), "--name", builder_name, "--driver=#{driver}"
|
||||
end
|
||||
|
||||
def append_remote_buildx
|
||||
docker :buildx, :create, "--append", "--name", builder_name, builder_name, "--platform", "linux/#{remote_arch}"
|
||||
end
|
||||
|
||||
def platform
|
||||
"linux/#{local_arch},linux/#{remote_arch}"
|
||||
docker :buildx, :create, *platform_options(remote_arches), "--append", "--name", builder_name, builder_name
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,14 +11,4 @@ class Kamal::Commands::Builder::Local < Kamal::Commands::Builder::Base
|
||||
def builder_name
|
||||
"kamal-local-#{driver}"
|
||||
end
|
||||
|
||||
def platform_options
|
||||
if multiarch?
|
||||
if local_arch
|
||||
[ "--platform", "linux/#{local_arch}" ]
|
||||
else
|
||||
[ "--platform", "linux/amd64,linux/arm64" ]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,22 +17,13 @@ class Kamal::Commands::Builder::Remote < Kamal::Commands::Builder::Base
|
||||
docker(:buildx, :ls)
|
||||
end
|
||||
|
||||
def push
|
||||
docker :build,
|
||||
"--push",
|
||||
*platform_options,
|
||||
"--builder", builder_name,
|
||||
*build_options,
|
||||
build_context
|
||||
end
|
||||
|
||||
private
|
||||
def builder_name
|
||||
"kamal-remote-#{driver}-#{remote_arch}-#{remote_host.gsub(/[^a-z0-9_-]/, "-")}"
|
||||
"kamal-remote-#{driver}-#{remote.gsub(/[^a-z0-9_-]/, "-")}"
|
||||
end
|
||||
|
||||
def create_remote_context
|
||||
docker :context, :create, builder_name, "--description", "'#{builder_name} host'", "--docker", "'host=#{remote_host}'"
|
||||
docker :context, :create, builder_name, "--description", "'#{builder_name} host'", "--docker", "'host=#{remote}'"
|
||||
end
|
||||
|
||||
def remove_remote_context
|
||||
@@ -40,18 +31,10 @@ class Kamal::Commands::Builder::Remote < Kamal::Commands::Builder::Base
|
||||
end
|
||||
|
||||
def create_buildx
|
||||
docker :buildx, :create, "--name", builder_name, builder_name, "--platform", platform
|
||||
docker :buildx, :create, "--name", builder_name, builder_name
|
||||
end
|
||||
|
||||
def remove_buildx
|
||||
docker :buildx, :rm, builder_name
|
||||
end
|
||||
|
||||
def platform_options
|
||||
[ "--platform", platform ]
|
||||
end
|
||||
|
||||
def platform
|
||||
"linux/#{remote_arch}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,16 +19,38 @@ class Kamal::Configuration::Builder
|
||||
builder_config
|
||||
end
|
||||
|
||||
def multiarch?
|
||||
builder_config["multiarch"] != false
|
||||
def remote
|
||||
builder_config["remote"]
|
||||
end
|
||||
|
||||
def local?
|
||||
!!builder_config["local"]
|
||||
def arches
|
||||
Array(builder_config.fetch("arch", default_arch))
|
||||
end
|
||||
|
||||
def local_arches
|
||||
@local_arches ||= if remote
|
||||
uname_m = `uname -m`.strip
|
||||
local_arch = uname_m == "x86_64" ? "amd64" : uname_m
|
||||
arches & [ local_arch ]
|
||||
else
|
||||
arches
|
||||
end
|
||||
end
|
||||
|
||||
def remote_arches
|
||||
@remote_arches ||= if remote
|
||||
arches - local_arches
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def remote?
|
||||
!!builder_config["remote"]
|
||||
remote_arches.any?
|
||||
end
|
||||
|
||||
def local?
|
||||
arches.empty? || local_arches.any?
|
||||
end
|
||||
|
||||
def cached?
|
||||
@@ -59,18 +81,6 @@ class Kamal::Configuration::Builder
|
||||
builder_config.fetch("driver", "docker-container")
|
||||
end
|
||||
|
||||
def local_arch
|
||||
builder_config["local"]["arch"] if local?
|
||||
end
|
||||
|
||||
def remote_arch
|
||||
builder_config["remote"]["arch"] if remote?
|
||||
end
|
||||
|
||||
def remote_host
|
||||
builder_config["remote"]["host"] if remote?
|
||||
end
|
||||
|
||||
def cache_from
|
||||
if cached?
|
||||
case builder_config["cache"]["type"]
|
||||
@@ -120,27 +130,14 @@ class Kamal::Configuration::Builder
|
||||
|
||||
private
|
||||
def valid?
|
||||
if multiarch?
|
||||
if local?
|
||||
raise ArgumentError, "Invalid builder configuration: local configuration, arch required" unless local_arch
|
||||
end
|
||||
|
||||
if remote?
|
||||
raise ArgumentError, "Invalid builder configuration: remote configuration, arch required" unless remote_arch
|
||||
raise ArgumentError, "Invalid builder configuration: remote configuration, arch required" unless remote_host
|
||||
end
|
||||
|
||||
if docker_driver?
|
||||
raise ArgumentError, "Invalid builder configuration: the docker driver does not support multiarch builds"
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Invalid builder configuration: multiarch must be enabled for local configuration" if local?
|
||||
raise ArgumentError, "Invalid builder configuration: multiarch must be enabled for remote configuration" if remote?
|
||||
if docker_driver?
|
||||
raise ArgumentError, "Invalid builder configuration: the `docker` driver does not not support remote builders" if remote
|
||||
raise ArgumentError, "Invalid builder configuration: the `docker` driver does not not support caching" if cached?
|
||||
raise ArgumentError, "Invalid builder configuration: the `docker` driver does not not support multiple arches" if arches.many?
|
||||
end
|
||||
|
||||
if @options["cache"] && @options["cache"]["type"]
|
||||
raise ArgumentError, "Invalid cache type: #{@options["cache"]["type"]}" unless [ "gha", "registry" ].include?(@options["cache"]["type"])
|
||||
raise ArgumentError, "The docker driver does not support caching" if docker_driver?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -179,4 +176,8 @@ class Kamal::Configuration::Builder
|
||||
def pwd_sha
|
||||
Digest::SHA256.hexdigest(Dir.pwd)[0..12]
|
||||
end
|
||||
|
||||
def default_arch
|
||||
docker_driver? ? [] : [ "amd64", "arm64" ]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# The builder configuration controls how the application is built with `docker build`
|
||||
#
|
||||
# If no configuration is specified, Kamal will:
|
||||
# 1. Create a buildx context called `kamal-<service>-multiarch`
|
||||
# 1. Create a buildx context called `kamal-local-docker-container`, using the docker-container driver
|
||||
# 2. Use `docker build` to build a multiarch image for linux/amd64,linux/arm64 with that context
|
||||
#
|
||||
# See https://kamal-deploy.org/docs/configuration/builder-examples/ for more information
|
||||
@@ -12,41 +12,29 @@
|
||||
#
|
||||
# Options go under the builder key in the root configuration.
|
||||
builder:
|
||||
|
||||
# Multiarch
|
||||
#
|
||||
# Enables multiarch builds, defaults to `true`
|
||||
multiarch: false
|
||||
|
||||
# Driver
|
||||
#
|
||||
# The build driver to use, defaults to `docker-container`
|
||||
driver: docker
|
||||
|
||||
# Local configuration
|
||||
# Arch
|
||||
#
|
||||
# The build configuration for local builds, only used if multiarch is enabled (the default)
|
||||
#
|
||||
# If there is no remote configuration, by default we build for amd64 and arm64.
|
||||
# If you only want to build for one architecture, you can specify it here.
|
||||
# The docker socket is optional and uses the default docker host socket when not specified
|
||||
local:
|
||||
arch: amd64
|
||||
host: /var/run/docker.sock
|
||||
# The architectures to build for, defaults to `[ amd64, arm64 ]`
|
||||
# Unless you are using the docker driver, when it defaults to the local architecture
|
||||
# You can set an array or just a single value
|
||||
arch:
|
||||
- amd64
|
||||
|
||||
# Remote configuration
|
||||
#
|
||||
# The build configuration for remote builds, also only used if multiarch is enabled.
|
||||
# The arch is required and can be either amd64 or arm64.
|
||||
remote:
|
||||
arch: arm64
|
||||
host: ssh://docker@docker-builder
|
||||
# If you have a remote builder, you can configure it here
|
||||
remote: ssh://docker@docker-builder
|
||||
|
||||
# Builder cache
|
||||
#
|
||||
# The type must be either 'gha' or 'registry'
|
||||
#
|
||||
# The image is only used for registry cache
|
||||
# The image is only used for registry cache. Not compatible with the docker driver
|
||||
cache:
|
||||
type: registry
|
||||
options: mode=max
|
||||
|
||||
@@ -28,7 +28,11 @@ class Kamal::Configuration::Validator
|
||||
elsif key == "hosts"
|
||||
validate_servers! value
|
||||
elsif example_value.is_a?(Array)
|
||||
validate_array_of! value, example_value.first.class
|
||||
if key == "arch"
|
||||
validate_array_of_or_type! value, example_value.first.class
|
||||
else
|
||||
validate_array_of! value, example_value.first.class
|
||||
end
|
||||
elsif example_value.is_a?(Hash)
|
||||
case key.to_s
|
||||
when "options", "args"
|
||||
@@ -71,6 +75,16 @@ class Kamal::Configuration::Validator
|
||||
value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
||||
end
|
||||
|
||||
def validate_array_of_or_type!(value, type)
|
||||
if value.is_a?(Array)
|
||||
validate_array_of! value, type
|
||||
else
|
||||
validate_type! value, type
|
||||
end
|
||||
rescue Kamal::ConfigurationError
|
||||
type_error(Array, type)
|
||||
end
|
||||
|
||||
def validate_array_of!(array, type)
|
||||
validate_type! array, Array
|
||||
|
||||
|
||||
Reference in New Issue
Block a user