Compare commits

...

1 Commits

Author SHA1 Message Date
Donal McBreen
459ba95bbf Revert "Simplify builders config" 2024-08-29 20:16:34 +01:00
64 changed files with 538 additions and 388 deletions

View File

@@ -30,9 +30,18 @@ class Kamal::Cli::Build < Kamal::Cli::Base
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
end end
# Get the command here to ensure the Dir.chdir doesn't interfere with it
push = KAMAL.builder.push
run_locally do run_locally do
begin begin
execute *KAMAL.builder.buildx_inspect context_hosts = capture_with_info(*KAMAL.builder.context_hosts).split("\n")
if context_hosts != KAMAL.builder.config_context_hosts
warn "Context hosts have changed, so re-creating builder, was: #{context_hosts.join(", ")}], now: #{KAMAL.builder.config_context_hosts.join(", ")}"
cli.remove
cli.create
end
rescue SSHKit::Command::Failed => e rescue SSHKit::Command::Failed => e
if e.message =~ /(context not found|no builder|does not exist)/ if e.message =~ /(context not found|no builder|does not exist)/
warn "Missing compatible builder, so creating a new one first" warn "Missing compatible builder, so creating a new one first"
@@ -42,9 +51,6 @@ class Kamal::Cli::Build < Kamal::Cli::Base
end end
end end
# Get the command here to ensure the Dir.chdir doesn't interfere with it
push = KAMAL.builder.push
KAMAL.with_verbosity(:debug) do KAMAL.with_verbosity(:debug) do
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push } Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
end end
@@ -66,7 +72,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
desc "create", "Create a build setup" desc "create", "Create a build setup"
def create def create
if (remote_host = KAMAL.config.builder.remote) if (remote_host = KAMAL.config.builder.remote_host)
connect_to_remote_host(remote_host) connect_to_remote_host(remote_host)
end end

View File

@@ -18,10 +18,6 @@ registry:
password: password:
- KAMAL_REGISTRY_PASSWORD - KAMAL_REGISTRY_PASSWORD
# Configure builder setup.
builder:
arch: amd64
# Inject ENV variables into containers (secrets come from .env). # Inject ENV variables into containers (secrets come from .env).
# Remember to run `kamal env push` after making changes! # Remember to run `kamal env push` after making changes!
# env: # env:
@@ -34,6 +30,16 @@ builder:
# ssh: # ssh:
# user: app # user: app
# Configure builder setup.
# builder:
# args:
# RUBY_VERSION: 3.2.0
# secrets:
# - GITHUB_TOKEN
# remote:
# arch: amd64
# host: ssh://app@192.168.0.1
# Use accessory services (secrets come from .env). # Use accessory services (secrets come from .env).
# accessories: # accessories:
# db: # db:

View File

@@ -1,8 +1,8 @@
require "active_support/core_ext/string/filters" require "active_support/core_ext/string/filters"
class Kamal::Commands::Builder < Kamal::Commands::Base class Kamal::Commands::Builder < Kamal::Commands::Base
delegate :create, :remove, :push, :clean, :pull, :info, :buildx_inspect, :validate_image, :first_mirror, to: :target delegate :create, :remove, :push, :clean, :pull, :info, :context_hosts, :config_context_hosts, :validate_image,
delegate :local?, :remote?, to: "config.builder" :first_mirror, to: :target
include Clone include Clone
@@ -11,27 +11,43 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
end end
def target def target
if remote? if config.builder.multiarch?
if local? if config.builder.remote?
hybrid if config.builder.local?
multiarch_remote
else
native_remote
end
else else
remote multiarch
end end
else else
local if config.builder.cached?
native_cached
else
native
end
end end
end end
def remote def native
@remote ||= Kamal::Commands::Builder::Remote.new(config) @native ||= Kamal::Commands::Builder::Native.new(config)
end end
def local def native_cached
@local ||= Kamal::Commands::Builder::Local.new(config) @native ||= Kamal::Commands::Builder::Native::Cached.new(config)
end end
def hybrid def native_remote
@hybrid ||= Kamal::Commands::Builder::Hybrid.new(config) @native ||= Kamal::Commands::Builder::Native::Remote.new(config)
end
def multiarch
@multiarch ||= Kamal::Commands::Builder::Multiarch.new(config)
end
def multiarch_remote
@multiarch_remote ||= Kamal::Commands::Builder::Multiarch::Remote.new(config)
end end

View File

@@ -1,41 +1,20 @@
class Kamal::Commands::Builder::Base < Kamal::Commands::Base class Kamal::Commands::Builder::Base < Kamal::Commands::Base
class BuilderError < StandardError; end class BuilderError < StandardError; end
ENDPOINT_DOCKER_HOST_INSPECT = "'{{.Endpoints.docker.Host}}'" ENDPOINT_DOCKER_HOST_INSPECT = "'{{.Endpoints.docker.Host}}'"
delegate :argumentize, to: Kamal::Utils delegate :argumentize, to: Kamal::Utils
delegate \ delegate :args, :secrets, :dockerfile, :target, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, to: :builder_config
:args, :secrets, :dockerfile, :target, :arches, :local_arches, :remote_arches, :remote,
:cache_from, :cache_to, :ssh, :driver, :docker_driver?,
to: :builder_config
def clean def clean
docker :image, :rm, "--force", config.absolute_image docker :image, :rm, "--force", config.absolute_image
end end
def push
docker :buildx, :build,
"--push",
*platform_options(arches),
*([ "--builder", builder_name ] unless docker_driver?),
*build_options,
build_context
end
def pull def pull
docker :pull, config.absolute_image docker :pull, config.absolute_image
end end
def info
combine \
docker(:context, :ls),
docker(:buildx, :ls)
end
def buildx_inspect
docker :buildx, :inspect, builder_name unless docker_driver?
end
def build_options def build_options
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh ] [ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh ]
end end
@@ -53,6 +32,14 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
) )
end end
def context_hosts
:true
end
def config_context_hosts
[]
end
def first_mirror def first_mirror
docker(:info, "--format '{{index .RegistryConfig.Mirrors 0}}'") docker(:info, "--format '{{index .RegistryConfig.Mirrors 0}}'")
end end
@@ -104,8 +91,4 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
def context_host(builder_name) def context_host(builder_name)
docker :context, :inspect, builder_name, "--format", ENDPOINT_DOCKER_HOST_INSPECT docker :context, :inspect, builder_name, "--format", ENDPOINT_DOCKER_HOST_INSPECT
end end
def platform_options(arches)
argumentize "--platform", arches.map { |arch| "linux/#{arch}" }.join(",") if arches.any?
end
end end

View File

@@ -1,21 +0,0 @@
class Kamal::Commands::Builder::Hybrid < Kamal::Commands::Builder::Remote
def create
combine \
create_local_buildx,
create_remote_context,
append_remote_buildx
end
private
def builder_name
"kamal-hybrid-#{driver}-#{remote.gsub(/[^a-z0-9_-]/, "-")}"
end
def create_local_buildx
docker :buildx, :create, *platform_options(local_arches), "--name", builder_name, "--driver=#{driver}"
end
def append_remote_buildx
docker :buildx, :create, *platform_options(remote_arches), "--append", "--name", builder_name, builder_name
end
end

View File

@@ -1,14 +0,0 @@
class Kamal::Commands::Builder::Local < Kamal::Commands::Builder::Base
def create
docker :buildx, :create, "--name", builder_name, "--driver=#{driver}" unless docker_driver?
end
def remove
docker :buildx, :rm, builder_name unless docker_driver?
end
private
def builder_name
"kamal-local-#{driver}"
end
end

View File

@@ -0,0 +1,41 @@
class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
def create
docker :buildx, :create, "--use", "--name", builder_name
end
def remove
docker :buildx, :rm, builder_name
end
def info
combine \
docker(:context, :ls),
docker(:buildx, :ls)
end
def push
docker :buildx, :build,
"--push",
"--platform", platform_names,
"--builder", builder_name,
*build_options,
build_context
end
def context_hosts
docker :buildx, :inspect, builder_name, "> /dev/null"
end
private
def builder_name
"kamal-#{config.service}-multiarch"
end
def platform_names
if local_arch
"linux/#{local_arch}"
else
"linux/amd64,linux/arm64"
end
end
end

View File

@@ -0,0 +1,61 @@
class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Multiarch
def create
combine \
create_contexts,
create_local_buildx,
append_remote_buildx
end
def remove
combine \
remove_contexts,
super
end
def context_hosts
chain \
context_host(builder_name_with_arch(local_arch)),
context_host(builder_name_with_arch(remote_arch))
end
def config_context_hosts
[ local_host, remote_host ].compact
end
private
def builder_name
super + "-remote"
end
def builder_name_with_arch(arch)
"#{builder_name}-#{arch}"
end
def create_local_buildx
docker :buildx, :create, "--name", builder_name, builder_name_with_arch(local_arch), "--platform", "linux/#{local_arch}"
end
def append_remote_buildx
docker :buildx, :create, "--append", "--name", builder_name, builder_name_with_arch(remote_arch), "--platform", "linux/#{remote_arch}"
end
def create_contexts
combine \
create_context(local_arch, local_host),
create_context(remote_arch, remote_host)
end
def create_context(arch, host)
docker :context, :create, builder_name_with_arch(arch), "--description", "'#{builder_name} #{arch} native host'", "--docker", "'host=#{host}'"
end
def remove_contexts
combine \
remove_context(local_arch),
remove_context(remote_arch)
end
def remove_context(arch)
docker :context, :rm, builder_name_with_arch(arch)
end
end

View File

@@ -0,0 +1,20 @@
class Kamal::Commands::Builder::Native < Kamal::Commands::Builder::Base
def create
# No-op on native without cache
end
def remove
# No-op on native without cache
end
def info
# No-op on native
end
def push
combine \
docker(:build, *build_options, build_context),
docker(:push, config.absolute_image),
docker(:push, config.latest_image)
end
end

View File

@@ -0,0 +1,25 @@
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

@@ -0,0 +1,67 @@
class Kamal::Commands::Builder::Native::Remote < Kamal::Commands::Builder::Native
def create
chain \
create_context,
create_buildx
end
def remove
chain \
remove_context,
remove_buildx
end
def info
chain \
docker(:context, :ls),
docker(:buildx, :ls)
end
def push
docker :buildx, :build,
"--push",
"--platform", platform,
"--builder", builder_name,
*build_options,
build_context
end
def context_hosts
context_host(builder_name_with_arch)
end
def config_context_hosts
[ remote_host ]
end
private
def builder_name
"kamal-#{config.service}-native-remote"
end
def builder_name_with_arch
"#{builder_name}-#{remote_arch}"
end
def platform
"linux/#{remote_arch}"
end
def create_context
docker :context, :create,
builder_name_with_arch, "--description", "'#{builder_name} #{remote_arch} native host'", "--docker", "'host=#{remote_host}'"
end
def remove_context
docker :context, :rm, builder_name_with_arch
end
def create_buildx
docker :buildx, :create, "--name", builder_name, builder_name_with_arch, "--platform", platform
end
def remove_buildx
docker :buildx, :rm, builder_name
end
end

View File

@@ -1,40 +0,0 @@
class Kamal::Commands::Builder::Remote < Kamal::Commands::Builder::Base
def create
chain \
create_remote_context,
create_buildx
end
def remove
chain \
remove_remote_context,
remove_buildx
end
def info
chain \
docker(:context, :ls),
docker(:buildx, :ls)
end
private
def builder_name
"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}'"
end
def remove_remote_context
docker :context, :rm, builder_name
end
def create_buildx
docker :buildx, :create, "--name", builder_name, builder_name
end
def remove_buildx
docker :buildx, :rm, builder_name
end
end

View File

@@ -19,36 +19,16 @@ class Kamal::Configuration::Builder
builder_config builder_config
end end
def remote def multiarch?
builder_config["remote"] builder_config["multiarch"] != false
end
def arches
Array(builder_config.fetch("arch", default_arch))
end
def local_arches
@local_arches ||= if remote
arches & [ Kamal::Utils.docker_arch ]
else
arches
end
end
def remote_arches
@remote_arches ||= if remote
arches - local_arches
else
[]
end
end
def remote?
remote_arches.any?
end end
def local? def local?
arches.empty? || local_arches.any? !!builder_config["local"]
end
def remote?
!!builder_config["remote"]
end end
def cached? def cached?
@@ -75,8 +55,20 @@ class Kamal::Configuration::Builder
builder_config["context"] || "." builder_config["context"] || "."
end end
def driver def local_arch
builder_config.fetch("driver", "docker-container") builder_config["local"]["arch"] if local?
end
def local_host
builder_config["local"]["host"] if local?
end
def remote_arch
builder_config["remote"]["arch"] if remote?
end
def remote_host
builder_config["remote"]["host"] if remote?
end end
def cache_from def cache_from
@@ -122,23 +114,7 @@ class Kamal::Configuration::Builder
end end
end end
def docker_driver?
driver == "docker"
end
private private
def valid?
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"])
end
end
def cache_image def cache_image
builder_config["cache"]&.fetch("image", nil) || "#{image}-build-cache" builder_config["cache"]&.fetch("image", nil) || "#{image}-build-cache"
end end
@@ -174,8 +150,4 @@ class Kamal::Configuration::Builder
def pwd_sha def pwd_sha
Digest::SHA256.hexdigest(Dir.pwd)[0..12] Digest::SHA256.hexdigest(Dir.pwd)[0..12]
end end
def default_arch
docker_driver? ? [] : [ "amd64", "arm64" ]
end
end end

View File

@@ -1,10 +1,10 @@
# Builder # Builder
# #
# The builder configuration controls how the application is built with `docker build` # The builder configuration controls how the application is built with `docker build` or `docker buildx build`
# #
# If no configuration is specified, Kamal will: # If no configuration is specified, Kamal will:
# 1. Create a buildx context called `kamal-local-docker-container`, using the docker-container driver # 1. Create a buildx context called `kamal-<service>-multiarch`
# 2. Use `docker build` to build a multiarch image for linux/amd64,linux/arm64 with that context # 2. Use `docker buildx 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 # See https://kamal-deploy.org/docs/configuration/builder-examples/ for more information
@@ -12,29 +12,36 @@
# #
# Options go under the builder key in the root configuration. # Options go under the builder key in the root configuration.
builder: builder:
# Driver
#
# The build driver to use, defaults to `docker-container`
driver: docker
# Arch # Multiarch
# #
# The architectures to build for, defaults to `[ amd64, arm64 ]` # Enables multiarch builds, defaults to `true`
# Unless you are using the docker driver, when it defaults to the local architecture multiarch: false
# You can set an array or just a single value
arch: # Local configuration
- amd64 #
# 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
# Remote configuration # Remote configuration
# #
# If you have a remote builder, you can configure it here # The build configuration for remote builds, also only used if multiarch is enabled.
remote: ssh://docker@docker-builder # The arch is required and can be either amd64 or arm64.
remote:
arch: arm64
host: ssh://docker@docker-builder
# Builder cache # Builder cache
# #
# The type must be either 'gha' or 'registry' # The type must be either 'gha' or 'registry'
# #
# The image is only used for registry cache. Not compatible with the docker driver # The image is only used for registry cache
cache: cache:
type: registry type: registry
options: mode=max options: mode=max

View File

@@ -28,11 +28,7 @@ class Kamal::Configuration::Validator
elsif key == "hosts" elsif key == "hosts"
validate_servers! value validate_servers! value
elsif example_value.is_a?(Array) elsif example_value.is_a?(Array)
if key == "arch" validate_array_of! value, example_value.first.class
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) elsif example_value.is_a?(Hash)
case key.to_s case key.to_s
when "options", "args" when "options", "args"
@@ -75,16 +71,6 @@ class Kamal::Configuration::Validator
value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass) value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
end 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) def validate_array_of!(array, type)
validate_type! array, Array validate_type! array, Array

View File

@@ -5,7 +5,5 @@ class Kamal::Configuration::Validator::Builder < Kamal::Configuration::Validator
if config["cache"] && config["cache"]["type"] if config["cache"] && config["cache"]["type"]
error "Invalid cache type: #{config["cache"]["type"]}" unless [ "gha", "registry" ].include?(config["cache"]["type"]) error "Invalid cache type: #{config["cache"]["type"]}" unless [ "gha", "registry" ].include?(config["cache"]["type"])
end end
error "Builder arch not set" unless config["arch"].present?
end end
end end

View File

@@ -81,16 +81,4 @@ module Kamal::Utils
def join_commands(commands) def join_commands(commands)
commands.map(&:strip).join(" ") commands.map(&:strip).join(" ")
end end
def docker_arch
arch = `docker info --format '{{.Architecture}}'`.strip
case arch
when /aarch64/
"arm64"
when /x86_64/
"amd64"
else
arch
end
end
end end

View File

@@ -21,12 +21,16 @@ class CliBuildTest < CliTestCase
.with(:git, "-C", anything, :status, "--porcelain") .with(:git, "-C", anything, :status, "--porcelain")
.returns("") .returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-app-multiarch", "> /dev/null")
.returns("")
run_command("push", "--verbose").tap do |output| run_command("push", "--verbose").tap do |output|
assert_hook_ran "pre-build", output, **hook_variables assert_hook_ran "pre-build", output, **hook_variables
assert_match /Cloning repo into build directory/, output 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 /git -C #{Dir.tmpdir}\/kamal-clones\/app-#{pwd_sha} clone #{Dir.pwd}/, output
assert_match /docker --version && docker buildx version/, output assert_match /docker --version && docker buildx version/, output
assert_match /docker buildx build --push --platform linux\/amd64 --builder kamal-local-docker-container -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-app-multiarch -t dhh\/app:999 -t dhh\/app:latest --label service="app" --file Dockerfile \. as .*@localhost/, output
end end
end end
end end
@@ -49,7 +53,7 @@ class CliBuildTest < CliTestCase
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :submodule, :update, "--init") SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :submodule, :update, "--init")
SSHKit::Backend::Abstract.any_instance.expects(:execute) SSHKit::Backend::Abstract.any_instance.expects(:execute)
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64", "--builder", "kamal-local-docker-container", "-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-app-multiarch", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:git, "-C", anything, :"rev-parse", :HEAD) .with(:git, "-C", anything, :"rev-parse", :HEAD)
@@ -74,7 +78,7 @@ class CliBuildTest < CliTestCase
assert_no_match /Cloning repo into build directory/, output assert_no_match /Cloning repo into build directory/, output
assert_hook_ran "pre-build", output, **hook_variables assert_hook_ran "pre-build", output, **hook_variables
assert_match /docker --version && docker buildx version/, output assert_match /docker --version && docker buildx version/, output
assert_match /docker buildx build --push --platform linux\/amd64 --builder kamal-local-docker-container -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-app-multiarch -t dhh\/app:999 -t dhh\/app:latest --label service="app" --file Dockerfile . as .*@localhost/, output
end end
end end
@@ -120,10 +124,10 @@ class CliBuildTest < CliTestCase
.with(:docker, "--version", "&&", :docker, :buildx, "version") .with(:docker, "--version", "&&", :docker, :buildx, "version")
SSHKit::Backend::Abstract.any_instance.expects(:execute) SSHKit::Backend::Abstract.any_instance.expects(:execute)
.with(:docker, :buildx, :create, "--name", "kamal-local-docker-container", "--driver=docker-container") .with(:docker, :buildx, :create, "--use", "--name", "kamal-app-multiarch")
SSHKit::Backend::Abstract.any_instance.expects(:execute) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-local-docker-container") .with(:docker, :buildx, :inspect, "kamal-app-multiarch", "> /dev/null")
.raises(SSHKit::Command::Failed.new("no builder")) .raises(SSHKit::Command::Failed.new("no builder"))
SSHKit::Backend::Abstract.any_instance.expects(:execute).with { |*args| args.first.start_with?("git") } SSHKit::Backend::Abstract.any_instance.expects(:execute).with { |*args| args.first.start_with?("git") }
@@ -137,7 +141,7 @@ class CliBuildTest < CliTestCase
.returns("") .returns("")
SSHKit::Backend::Abstract.any_instance.expects(:execute) SSHKit::Backend::Abstract.any_instance.expects(:execute)
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64", "--builder", "kamal-local-docker-container", "-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-app-multiarch", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
run_command("push").tap do |output| run_command("push").tap do |output|
assert_match /WARN Missing compatible builder, so creating a new one first/, output assert_match /WARN Missing compatible builder, so creating a new one first/, output
@@ -161,7 +165,7 @@ class CliBuildTest < CliTestCase
error = assert_raises(Kamal::Cli::HookError) { run_command("push") } error = assert_raises(Kamal::Cli::HookError) { run_command("push") }
assert_equal "Hook `pre-build` failed:\nfailed", error.message assert_equal "Hook `pre-build` failed:\nfailed", error.message
assert @executions.none? { |args| args[0..2] == [ :docker, :build ] } assert @executions.none? { |args| args[0..2] == [ :docker, :buildx, :build ] }
end end
test "pull" do test "pull" do
@@ -203,23 +207,23 @@ class CliBuildTest < CliTestCase
test "create" do test "create" do
run_command("create").tap do |output| run_command("create").tap do |output|
assert_match /docker buildx create --name kamal-local-docker-container --driver=docker-container/, output assert_match /docker buildx create --use --name kamal-app-multiarch/, output
end end
end end
test "create remote" do test "create remote" do
run_command("create", fixture: :with_remote_builder).tap do |output| run_command("create", fixture: :with_remote_builder).tap do |output|
assert_match "Running /usr/bin/env true on 1.1.1.5", output assert_match "Running /usr/bin/env true on 1.1.1.5", output
assert_match "docker context create kamal-remote-docker-container-ssh---app-1-1-1-5 --description 'kamal-remote-docker-container-ssh---app-1-1-1-5 host' --docker 'host=ssh://app@1.1.1.5'", output assert_match "docker context create kamal-app-native-remote-amd64 --description 'kamal-app-native-remote amd64 native host' --docker 'host=ssh://app@1.1.1.5'", output
assert_match "docker buildx create --name kamal-remote-docker-container-ssh---app-1-1-1-5 kamal-remote-docker-container-ssh---app-1-1-1-5", output assert_match "docker buildx create --name kamal-app-native-remote kamal-app-native-remote-amd64 --platform linux/amd64", output
end end
end end
test "create remote with custom ports" do test "create remote with custom ports" do
run_command("create", fixture: :with_remote_builder_and_custom_ports).tap do |output| run_command("create", fixture: :with_remote_builder_and_custom_ports).tap do |output|
assert_match "Running /usr/bin/env true on 1.1.1.5", output assert_match "Running /usr/bin/env true on 1.1.1.5", output
assert_match "docker context create kamal-remote-docker-container-ssh---app-1-1-1-5-2122 --description 'kamal-remote-docker-container-ssh---app-1-1-1-5-2122 host' --docker 'host=ssh://app@1.1.1.5:2122'", output assert_match "docker context create kamal-app-native-remote-amd64 --description 'kamal-app-native-remote amd64 native host' --docker 'host=ssh://app@1.1.1.5:2122'", output
assert_match "docker buildx create --name kamal-remote-docker-container-ssh---app-1-1-1-5-2122 kamal-remote-docker-container-ssh---app-1-1-1-5-2122", output assert_match "docker buildx create --name kamal-app-native-remote kamal-app-native-remote-amd64 --platform linux/amd64", output
end end
end end
@@ -236,7 +240,7 @@ class CliBuildTest < CliTestCase
test "remove" do test "remove" do
run_command("remove").tap do |output| run_command("remove").tap do |output|
assert_match /docker buildx rm kamal-local/, output assert_match /docker buildx rm kamal-app-multiarch/, output
end end
end end
@@ -246,7 +250,7 @@ class CliBuildTest < CliTestCase
.returns("docker builder info") .returns("docker builder info")
run_command("details").tap do |output| run_command("details").tap do |output|
assert_match /Builder: local/, output assert_match /Builder: multiarch/, output
assert_match /docker builder info/, output assert_match /docker builder info/, output
end end
end end

View File

@@ -36,8 +36,9 @@ class CliTestCase < ActiveSupport::TestCase
.with { |arg1, arg2| arg1 == :mkdir && arg2 == ".kamal/locks/app" } .with { |arg1, arg2| arg1 == :mkdir && arg2 == ".kamal/locks/app" }
SSHKit::Backend::Abstract.any_instance.stubs(:execute) SSHKit::Backend::Abstract.any_instance.stubs(:execute)
.with { |arg1, arg2| arg1 == :rm && arg2 == ".kamal/locks/app/details" } .with { |arg1, arg2| arg1 == :rm && arg2 == ".kamal/locks/app/details" }
SSHKit::Backend::Abstract.any_instance.stubs(:execute) SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-local-docker-container") .with { |*args| args[0..2] == [ :docker, :buildx, :inspect ] }
.returns("")
end end
def assert_hook_ran(hook, output, version:, service_version:, hosts:, command:, subcommand: nil, runtime: false) def assert_hook_ran(hook, output, version:, service_version:, hosts:, command:, subcommand: nil, runtime: false)

View File

@@ -121,6 +121,10 @@ class CliMainTest < CliTestCase
.with(:git, "-C", anything, :status, "--porcelain") .with(:git, "-C", anything, :status, "--porcelain")
.returns("") .returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-app-multiarch", "> /dev/null")
.returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :info, "--format '{{index .RegistryConfig.Mirrors 0}}'") .with(:docker, :info, "--format '{{index .RegistryConfig.Mirrors 0}}'")
.returns("") .returns("")
@@ -155,6 +159,10 @@ class CliMainTest < CliTestCase
.with(:git, "-C", anything, :status, "--porcelain") .with(:git, "-C", anything, :status, "--porcelain")
.returns("") .returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :buildx, :inspect, "kamal-app-multiarch", "> /dev/null")
.returns("")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :info, "--format '{{index .RegistryConfig.Mirrors 0}}'") .with(:docker, :info, "--format '{{index .RegistryConfig.Mirrors 0}}'")
.returns("") .returns("")

View File

@@ -5,7 +5,6 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
@config = { @config = {
service: "app", image: "dhh/app", registry: { "server" => "private.registry", "username" => "dhh", "password" => "secret" }, service: "app", image: "dhh/app", registry: { "server" => "private.registry", "username" => "dhh", "password" => "secret" },
servers: [ "1.1.1.1" ], servers: [ "1.1.1.1" ],
builder: { "arch" => "amd64" },
accessories: { accessories: {
"mysql" => { "mysql" => {
"image" => "private.registry/mysql:8.0", "image" => "private.registry/mysql:8.0",

View File

@@ -5,7 +5,7 @@ class CommandsAppTest < ActiveSupport::TestCase
ENV["RAILS_MASTER_KEY"] = "456" ENV["RAILS_MASTER_KEY"] = "456"
Kamal::Configuration.any_instance.stubs(:run_id).returns("12345678901234567890123456789012") Kamal::Configuration.any_instance.stubs(:run_id).returns("12345678901234567890123456789012")
@config = { service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], env: { "secret" => [ "RAILS_MASTER_KEY" ] }, builder: { "arch" => "amd64" } } @config = { service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], env: { "secret" => [ "RAILS_MASTER_KEY" ] } }
end end
teardown do teardown do

View File

@@ -8,7 +8,7 @@ class CommandsAuditorTest < ActiveSupport::TestCase
freeze_time freeze_time
@config = { @config = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, builder: { "arch" => "amd64" }, servers: [ "1.1.1.1" ] service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ]
} }
@auditor = new_command @auditor = new_command

View File

@@ -2,54 +2,54 @@ require "test_helper"
class CommandsBuilderTest < ActiveSupport::TestCase class CommandsBuilderTest < ActiveSupport::TestCase
setup do setup do
@config = { service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], builder: { "arch" => "amd64" } } @config = { service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ] }
end end
test "target linux/amd64 locally by default" do test "target multiarch by default" do
builder = new_builder_command(builder: { "cache" => { "type" => "gha" } }) builder = new_builder_command(builder: { "cache" => { "type" => "gha" } })
assert_equal "local", builder.name assert_equal "multiarch", builder.name
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-local-docker-container -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-app-multiarch -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
builder.push.join(" ") builder.push.join(" ")
end end
test "target specified arch locally by default" do test "target native when multiarch is off" do
builder = new_builder_command(builder: { "arch" => [ "amd64" ] }) builder = new_builder_command(builder: { "multiarch" => false })
assert_equal "local", builder.name assert_equal "native", builder.name
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-local-docker-container -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile .", "docker build -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile . && docker push dhh/app:123 && docker push dhh/app:latest",
builder.push.join(" ") builder.push.join(" ")
end end
test "build with caching" do test "target native cached when multiarch is off and cache is set" do
builder = new_builder_command(builder: { "cache" => { "type" => "gha" } }) builder = new_builder_command(builder: { "multiarch" => false, "cache" => { "type" => "gha" } })
assert_equal "local", builder.name assert_equal "native/cached", builder.name
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-local-docker-container -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 -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
builder.push.join(" ") builder.push.join(" ")
end end
test "hybrid build if remote is set and building multiarch" do test "target multiarch remote when local and remote is set" do
builder = new_builder_command(builder: { "arch" => [ "amd64", "arm64" ], "remote" => "ssh://app@127.0.0.1", "cache" => { "type" => "gha" } }) builder = new_builder_command(builder: { "local" => {}, "remote" => {}, "cache" => { "type" => "gha" } })
assert_equal "hybrid", builder.name assert_equal "multiarch/remote", builder.name
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-hybrid-docker-container-ssh---app-127-0-0-1 -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-app-multiarch-remote -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
builder.push.join(" ") builder.push.join(" ")
end end
test "target remote when remote set and arch is non local" do test "target multiarch local when arch is set" do
builder = new_builder_command(builder: { "arch" => [ "#{remote_arch}" ], "remote" => "ssh://app@host", "cache" => { "type" => "gha" } }) builder = new_builder_command(builder: { "local" => { "arch" => "amd64" } })
assert_equal "remote", builder.name assert_equal "multiarch", builder.name
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/#{remote_arch} --builder kamal-remote-docker-container-ssh---app-host -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 --builder kamal-app-multiarch -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile .",
builder.push.join(" ") builder.push.join(" ")
end end
test "target local when remote set and arch is local" do test "target native remote when only remote is set" do
builder = new_builder_command(builder: { "arch" => [ "#{local_arch}" ], "remote" => "ssh://app@host", "cache" => { "type" => "gha" } }) builder = new_builder_command(builder: { "remote" => { "arch" => "amd64" }, "cache" => { "type" => "gha" } })
assert_equal "local", builder.name assert_equal "native/remote", builder.name
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/#{local_arch} --builder kamal-local-docker-container -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 --builder kamal-app-native-remote -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
builder.push.join(" ") builder.push.join(" ")
end end
@@ -93,21 +93,28 @@ class CommandsBuilderTest < ActiveSupport::TestCase
test "build context" do test "build context" do
builder = new_builder_command(builder: { "context" => ".." }) builder = new_builder_command(builder: { "context" => ".." })
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-local-docker-container -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile ..", "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 ..",
builder.push.join(" ") builder.push.join(" ")
end end
test "push with build args" do test "native push with build args" do
builder = new_builder_command(builder: { "multiarch" => false, "args" => { "a" => 1, "b" => 2 } })
assert_equal \
"docker build -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --build-arg a=\"1\" --build-arg b=\"2\" --file Dockerfile . && docker push dhh/app:123 && docker push dhh/app:latest",
builder.push.join(" ")
end
test "multiarch push with build args" do
builder = new_builder_command(builder: { "args" => { "a" => 1, "b" => 2 } }) builder = new_builder_command(builder: { "args" => { "a" => 1, "b" => 2 } })
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-local-docker-container -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-app-multiarch -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --build-arg a=\"1\" --build-arg b=\"2\" --file Dockerfile .",
builder.push.join(" ") builder.push.join(" ")
end end
test "push with build secrets" do test "native push with build secrets" do
builder = new_builder_command(builder: { "secrets" => [ "a", "b" ] }) builder = new_builder_command(builder: { "multiarch" => false, "secrets" => [ "a", "b" ] })
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-local-docker-container -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --secret id=\"a\" --secret id=\"b\" --file Dockerfile .", "docker build -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --secret id=\"a\" --secret id=\"b\" --file Dockerfile . && docker push dhh/app:123 && docker push dhh/app:latest",
builder.push.join(" ") builder.push.join(" ")
end end
@@ -123,13 +130,76 @@ class CommandsBuilderTest < ActiveSupport::TestCase
assert_equal "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:123 | grep -x app || (echo \"Image dhh/app:123 is missing the 'service' label\" && exit 1)", new_builder_command.validate_image.join(" ") assert_equal "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:123 | grep -x app || (echo \"Image dhh/app:123 is missing the 'service' label\" && exit 1)", new_builder_command.validate_image.join(" ")
end end
test "context build" do test "multiarch context build" do
builder = new_builder_command(builder: { "context" => "./foo" }) builder = new_builder_command(builder: { "context" => "./foo" })
assert_equal \ assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-local-docker-container -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-app-multiarch -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile ./foo",
builder.push.join(" ") builder.push.join(" ")
end end
test "native context build" do
builder = new_builder_command(builder: { "multiarch" => false, "context" => "./foo" })
assert_equal \
"docker build -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile ./foo && docker push dhh/app:123 && docker push dhh/app:latest",
builder.push.join(" ")
end
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",
builder.push.join(" ")
end
test "remote context build" do
builder = new_builder_command(builder: { "remote" => { "arch" => "amd64" }, "context" => "./foo" })
assert_equal \
"docker buildx build --push --platform linux/amd64 --builder kamal-app-native-remote -t dhh/app:123 -t dhh/app:latest --label service=\"app\" --file Dockerfile ./foo",
builder.push.join(" ")
end
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 "", command.config_context_hosts.join(" ")
end
test "native context hosts" do
command = new_builder_command(builder: { "multiarch" => false })
assert_equal :true, command.context_hosts
assert_equal "", command.config_context_hosts.join(" ")
end
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 "", command.config_context_hosts.join(" ")
end
test "native remote context hosts" do
command = new_builder_command(builder: { "remote" => { "arch" => "amd64", "host" => "ssh://host" } })
assert_equal "docker context inspect kamal-app-native-remote-amd64 --format '{{.Endpoints.docker.Host}}'", command.context_hosts.join(" ")
assert_equal [ "ssh://host" ], command.config_context_hosts
end
test "multiarch remote context hosts" do
command = new_builder_command(builder: {
"remote" => { "arch" => "amd64", "host" => "ssh://host" },
"local" => { "arch" => "arm64" }
})
assert_equal "docker context inspect kamal-app-multiarch-remote-arm64 --format '{{.Endpoints.docker.Host}}' ; docker context inspect kamal-app-multiarch-remote-amd64 --format '{{.Endpoints.docker.Host}}'", command.context_hosts.join(" ")
assert_equal [ "ssh://host" ], command.config_context_hosts
end
test "multiarch remote context hosts with local host" do
command = new_builder_command(builder: {
"remote" => { "arch" => "amd64", "host" => "ssh://host" },
"local" => { "arch" => "arm64", "host" => "unix:///var/run/docker.sock" }
})
assert_equal "docker context inspect kamal-app-multiarch-remote-arm64 --format '{{.Endpoints.docker.Host}}' ; docker context inspect kamal-app-multiarch-remote-amd64 --format '{{.Endpoints.docker.Host}}'", command.context_hosts.join(" ")
assert_equal [ "unix:///var/run/docker.sock", "ssh://host" ], command.config_context_hosts
end
test "mirror count" do test "mirror count" do
command = new_builder_command command = new_builder_command
assert_equal "docker info --format '{{index .RegistryConfig.Mirrors 0}}'", command.first_mirror.join(" ") assert_equal "docker info --format '{{index .RegistryConfig.Mirrors 0}}'", command.first_mirror.join(" ")
@@ -137,18 +207,10 @@ class CommandsBuilderTest < ActiveSupport::TestCase
private private
def new_builder_command(additional_config = {}) def new_builder_command(additional_config = {})
Kamal::Commands::Builder.new(Kamal::Configuration.new(@config.deep_merge(additional_config), version: "123")) Kamal::Commands::Builder.new(Kamal::Configuration.new(@config.merge(additional_config), version: "123"))
end end
def build_directory def build_directory
"#{Dir.tmpdir}/kamal-clones/app/kamal/" "#{Dir.tmpdir}/kamal-clones/app/kamal/"
end end
def local_arch
Kamal::Utils.docker_arch
end
def remote_arch
Kamal::Utils.docker_arch == "arm64" ? "amd64" : "arm64"
end
end end

View File

@@ -3,7 +3,7 @@ require "test_helper"
class CommandsDockerTest < ActiveSupport::TestCase class CommandsDockerTest < ActiveSupport::TestCase
setup do setup do
@config = { @config = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], builder: { "arch" => "amd64" } service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ]
} }
@docker = Kamal::Commands::Docker.new(Kamal::Configuration.new(@config)) @docker = Kamal::Commands::Docker.new(Kamal::Configuration.new(@config))
end end

View File

@@ -8,7 +8,7 @@ class CommandsHookTest < ActiveSupport::TestCase
@config = { @config = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ],
builder: { "arch" => "amd64" }, traefik: { "args" => { "accesslog.format" => "json", "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } } traefik: { "args" => { "accesslog.format" => "json", "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } }
} }
@performer = Kamal::Git.email.presence || `whoami`.chomp @performer = Kamal::Git.email.presence || `whoami`.chomp

View File

@@ -4,7 +4,7 @@ class CommandsLockTest < ActiveSupport::TestCase
setup do setup do
@config = { @config = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ],
builder: { "arch" => "amd64" }, traefik: { "args" => { "accesslog.format" => "json", "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } } traefik: { "args" => { "accesslog.format" => "json", "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } }
} }
end end

View File

@@ -4,7 +4,7 @@ class CommandsPruneTest < ActiveSupport::TestCase
setup do setup do
@config = { @config = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ],
builder: { "arch" => "amd64" }, traefik: { "args" => { "accesslog.format" => "json", "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } } traefik: { "args" => { "accesslog.format" => "json", "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } }
} }
end end

View File

@@ -8,7 +8,6 @@ class CommandsRegistryTest < ActiveSupport::TestCase
"password" => "secret", "password" => "secret",
"server" => "hub.docker.com" "server" => "hub.docker.com"
}, },
builder: { "arch" => "amd64" },
servers: [ "1.1.1.1" ] servers: [ "1.1.1.1" ]
} }
@registry = Kamal::Commands::Registry.new Kamal::Configuration.new(@config) @registry = Kamal::Commands::Registry.new Kamal::Configuration.new(@config)

View File

@@ -4,7 +4,7 @@ class CommandsServerTest < ActiveSupport::TestCase
setup do setup do
@config = { @config = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ],
builder: { "arch" => "amd64" }, traefik: { "args" => { "accesslog.format" => "json", "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } } traefik: { "args" => { "accesslog.format" => "json", "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } }
} }
end end

View File

@@ -5,7 +5,7 @@ class CommandsTraefikTest < ActiveSupport::TestCase
@image = "traefik:test" @image = "traefik:test"
@config = { @config = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], builder: { "arch" => "amd64" }, service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ],
traefik: { "image" => @image, "args" => { "accesslog.format" => "json", "api.insecure" => true, "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } } traefik: { "image" => @image, "args" => { "accesslog.format" => "json", "api.insecure" => true, "metrics.prometheus.buckets" => "0.1,0.3,1.2,5.0" } }
} }

View File

@@ -8,7 +8,6 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
"web" => [ "1.1.1.1", "1.1.1.2" ], "web" => [ "1.1.1.1", "1.1.1.2" ],
"workers" => [ "1.1.1.3", "1.1.1.4" ] "workers" => [ "1.1.1.3", "1.1.1.4" ]
}, },
builder: { "arch" => "amd64" },
env: { "REDIS_URL" => "redis://x/y" }, env: { "REDIS_URL" => "redis://x/y" },
accessories: { accessories: {
"mysql" => { "mysql" => {

View File

@@ -4,33 +4,56 @@ class ConfigurationBuilderTest < ActiveSupport::TestCase
setup do setup do
@deploy = { @deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
builder: { "arch" => "amd64" }, servers: [ "1.1.1.1" ] servers: [ "1.1.1.1" ]
}
@deploy_with_builder_option = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ "1.1.1.1" ],
builder: {}
} }
end end
test "multiarch?" do
assert_equal true, config.builder.multiarch?
end
test "setting multiarch to false" do
@deploy_with_builder_option[:builder] = { "multiarch" => false }
assert_equal false, config_with_builder_option.builder.multiarch?
end
test "local?" do test "local?" do
assert_equal true, config.builder.local? assert_equal false, config.builder.local?
end end
test "remote?" do test "remote?" do
assert_equal false, config.builder.remote? assert_equal false, config.builder.remote?
end end
test "remote" do test "remote_arch" do
assert_nil config.builder.remote assert_nil config.builder.remote_arch
end
test "remote_host" do
assert_nil config.builder.remote_host
end end
test "setting both local and remote configs" do test "setting both local and remote configs" do
@deploy[:builder] = { @deploy_with_builder_option[:builder] = {
"arch" => [ "amd64", "arm64" ], "local" => { "arch" => "arm64", "host" => "unix:///Users/<%= `whoami`.strip %>/.docker/run/docker.sock" },
"remote" => "ssh://root@192.168.0.1" "remote" => { "arch" => "amd64", "host" => "ssh://root@192.168.0.1" }
} }
assert_equal true, config.builder.local? assert_equal true, config_with_builder_option.builder.local?
assert_equal true, config.builder.remote? assert_equal true, config_with_builder_option.builder.remote?
assert_equal [ "amd64", "arm64" ], config.builder.arches assert_equal "amd64", config_with_builder_option.builder.remote_arch
assert_equal "ssh://root@192.168.0.1", config.builder.remote assert_equal "ssh://root@192.168.0.1", config_with_builder_option.builder.remote_host
assert_equal "arm64", config_with_builder_option.builder.local_arch
assert_equal "unix:///Users/<%= `whoami`.strip %>/.docker/run/docker.sock", config_with_builder_option.builder.local_host
end end
test "cached?" do test "cached?" do
@@ -38,10 +61,10 @@ class ConfigurationBuilderTest < ActiveSupport::TestCase
end end
test "invalid cache type specified" do test "invalid cache type specified" do
@deploy[:builder]["cache"] = { "type" => "invalid" } @deploy_with_builder_option[:builder] = { "cache" => { "type" => "invalid" } }
assert_raises(Kamal::ConfigurationError) do assert_raises(Kamal::ConfigurationError) do
config.builder config_with_builder_option.builder
end end
end end
@@ -54,32 +77,32 @@ class ConfigurationBuilderTest < ActiveSupport::TestCase
end end
test "setting gha cache" do test "setting gha cache" do
@deploy[:builder] = { "arch" => "amd64", "cache" => { "type" => "gha", "options" => "mode=max" } } @deploy_with_builder_option[:builder] = { "cache" => { "type" => "gha", "options" => "mode=max" } }
assert_equal "type=gha", config.builder.cache_from assert_equal "type=gha", config_with_builder_option.builder.cache_from
assert_equal "type=gha,mode=max", config.builder.cache_to assert_equal "type=gha,mode=max", config_with_builder_option.builder.cache_to
end end
test "setting registry cache" do test "setting registry cache" do
@deploy[:builder] = { "arch" => "amd64", "cache" => { "type" => "registry", "options" => "mode=max,image-manifest=true,oci-mediatypes=true" } } @deploy_with_builder_option[:builder] = { "cache" => { "type" => "registry", "options" => "mode=max,image-manifest=true,oci-mediatypes=true" } }
assert_equal "type=registry,ref=dhh/app-build-cache", config.builder.cache_from assert_equal "type=registry,ref=dhh/app-build-cache", config_with_builder_option.builder.cache_from
assert_equal "type=registry,mode=max,image-manifest=true,oci-mediatypes=true,ref=dhh/app-build-cache", config.builder.cache_to assert_equal "type=registry,mode=max,image-manifest=true,oci-mediatypes=true,ref=dhh/app-build-cache", config_with_builder_option.builder.cache_to
end end
test "setting registry cache when using a custom registry" do test "setting registry cache when using a custom registry" do
@deploy[:registry]["server"] = "registry.example.com" @deploy_with_builder_option[:registry]["server"] = "registry.example.com"
@deploy[:builder] = { "arch" => "amd64", "cache" => { "type" => "registry", "options" => "mode=max,image-manifest=true,oci-mediatypes=true" } } @deploy_with_builder_option[:builder] = { "cache" => { "type" => "registry", "options" => "mode=max,image-manifest=true,oci-mediatypes=true" } }
assert_equal "type=registry,ref=registry.example.com/dhh/app-build-cache", config.builder.cache_from assert_equal "type=registry,ref=registry.example.com/dhh/app-build-cache", config_with_builder_option.builder.cache_from
assert_equal "type=registry,mode=max,image-manifest=true,oci-mediatypes=true,ref=registry.example.com/dhh/app-build-cache", config.builder.cache_to assert_equal "type=registry,mode=max,image-manifest=true,oci-mediatypes=true,ref=registry.example.com/dhh/app-build-cache", config_with_builder_option.builder.cache_to
end end
test "setting registry cache with image" do test "setting registry cache with image" do
@deploy[:builder] = { "arch" => "amd64", "cache" => { "type" => "registry", "image" => "kamal", "options" => "mode=max" } } @deploy_with_builder_option[:builder] = { "cache" => { "type" => "registry", "image" => "kamal", "options" => "mode=max" } }
assert_equal "type=registry,ref=kamal", config.builder.cache_from assert_equal "type=registry,ref=kamal", config_with_builder_option.builder.cache_from
assert_equal "type=registry,mode=max,ref=kamal", config.builder.cache_to assert_equal "type=registry,mode=max,ref=kamal", config_with_builder_option.builder.cache_to
end end
test "args" do test "args" do
@@ -87,9 +110,9 @@ class ConfigurationBuilderTest < ActiveSupport::TestCase
end end
test "setting args" do test "setting args" do
@deploy[:builder]["args"] = { "key" => "value" } @deploy_with_builder_option[:builder] = { "args" => { "key" => "value" } }
assert_equal({ "key" => "value" }, config.builder.args) assert_equal({ "key" => "value" }, config_with_builder_option.builder.args)
end end
test "secrets" do test "secrets" do
@@ -97,9 +120,9 @@ class ConfigurationBuilderTest < ActiveSupport::TestCase
end end
test "setting secrets" do test "setting secrets" do
@deploy[:builder]["secrets"] = [ "GITHUB_TOKEN" ] @deploy_with_builder_option[:builder] = { "secrets" => [ "GITHUB_TOKEN" ] }
assert_equal [ "GITHUB_TOKEN" ], config.builder.secrets assert_equal [ "GITHUB_TOKEN" ], config_with_builder_option.builder.secrets
end end
test "dockerfile" do test "dockerfile" do
@@ -107,9 +130,9 @@ class ConfigurationBuilderTest < ActiveSupport::TestCase
end end
test "setting dockerfile" do test "setting dockerfile" do
@deploy[:builder]["dockerfile"] = "Dockerfile.dev" @deploy_with_builder_option[:builder] = { "dockerfile" => "Dockerfile.dev" }
assert_equal "Dockerfile.dev", config.builder.dockerfile assert_equal "Dockerfile.dev", config_with_builder_option.builder.dockerfile
end end
test "context" do test "context" do
@@ -117,9 +140,9 @@ class ConfigurationBuilderTest < ActiveSupport::TestCase
end end
test "setting context" do test "setting context" do
@deploy[:builder]["context"] = ".." @deploy_with_builder_option[:builder] = { "context" => ".." }
assert_equal "..", config.builder.context assert_equal "..", config_with_builder_option.builder.context
end end
test "ssh" do test "ssh" do
@@ -127,13 +150,17 @@ class ConfigurationBuilderTest < ActiveSupport::TestCase
end end
test "setting ssh params" do test "setting ssh params" do
@deploy[:builder]["ssh"] = "default=$SSH_AUTH_SOCK" @deploy_with_builder_option[:builder] = { "ssh" => "default=$SSH_AUTH_SOCK" }
assert_equal "default=$SSH_AUTH_SOCK", config.builder.ssh assert_equal "default=$SSH_AUTH_SOCK", config_with_builder_option.builder.ssh
end end
private private
def config def config
Kamal::Configuration.new(@deploy) Kamal::Configuration.new(@deploy)
end end
def config_with_builder_option
Kamal::Configuration.new(@deploy_with_builder_option)
end
end end

View File

@@ -5,7 +5,6 @@ class ConfigurationEnvTagsTest < ActiveSupport::TestCase
@deploy = { @deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => "odd" }, { "1.1.1.2" => "even" }, { "1.1.1.3" => [ "odd", "three" ] } ], servers: [ { "1.1.1.1" => "odd" }, { "1.1.1.2" => "even" }, { "1.1.1.3" => [ "odd", "three" ] } ],
builder: { "arch" => "amd64" },
env: { env: {
"clear" => { "REDIS_URL" => "redis://x/y", "THREE" => "false" }, "clear" => { "REDIS_URL" => "redis://x/y", "THREE" => "false" },
"tags" => { "tags" => {
@@ -65,7 +64,6 @@ class ConfigurationEnvTagsTest < ActiveSupport::TestCase
deploy = { deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => [ "first", "second" ] } ], servers: [ { "1.1.1.1" => [ "first", "second" ] } ],
builder: { "arch" => "amd64" },
env: { env: {
"tags" => { "tags" => {
"first" => { "TYPE" => "first" }, "first" => { "TYPE" => "first" },
@@ -84,7 +82,6 @@ class ConfigurationEnvTagsTest < ActiveSupport::TestCase
deploy = { deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => "secrets" } ], servers: [ { "1.1.1.1" => "secrets" } ],
builder: { "arch" => "amd64" },
env: { env: {
"tags" => { "tags" => {
"secrets" => { "secret" => [ "PASSWORD" ] } "secrets" => { "secret" => [ "PASSWORD" ] }
@@ -102,7 +99,6 @@ class ConfigurationEnvTagsTest < ActiveSupport::TestCase
deploy = { deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => "clearly" } ], servers: [ { "1.1.1.1" => "clearly" } ],
builder: { "arch" => "amd64" },
env: { env: {
"tags" => { "tags" => {
"clearly" => { "clear" => { "FOO" => "bar" } } "clearly" => { "clear" => { "FOO" => "bar" } }

View File

@@ -5,7 +5,6 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
@deploy = { @deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ "1.1.1.1", "1.1.1.2" ], servers: [ "1.1.1.1", "1.1.1.2" ],
builder: { "arch" => "amd64" },
env: { "REDIS_URL" => "redis://x/y" } env: { "REDIS_URL" => "redis://x/y" }
} }

View File

@@ -5,7 +5,6 @@ class ConfigurationSshTest < ActiveSupport::TestCase
@deploy = { @deploy = {
service: "app", image: "dhh/app", service: "app", image: "dhh/app",
registry: { "username" => "dhh", "password" => "secret" }, registry: { "username" => "dhh", "password" => "secret" },
builder: { "arch" => "amd64" },
env: { "REDIS_URL" => "redis://x/y" }, env: { "REDIS_URL" => "redis://x/y" },
servers: [ "1.1.1.1", "1.1.1.2" ], servers: [ "1.1.1.1", "1.1.1.2" ],
volumes: [ "/local/path:/container/path" ] volumes: [ "/local/path:/container/path" ]

View File

@@ -6,7 +6,6 @@ class ConfigurationSshkitTest < ActiveSupport::TestCase
service: "app", image: "dhh/app", service: "app", image: "dhh/app",
registry: { "username" => "dhh", "password" => "secret" }, registry: { "username" => "dhh", "password" => "secret" },
env: { "REDIS_URL" => "redis://x/y" }, env: { "REDIS_URL" => "redis://x/y" },
builder: { "arch" => "amd64" },
servers: [ "1.1.1.1", "1.1.1.2" ], servers: [ "1.1.1.1", "1.1.1.2" ],
volumes: [ "/local/path:/container/path" ] volumes: [ "/local/path:/container/path" ]
} }

View File

@@ -90,8 +90,10 @@ class ConfigurationValidationTest < ActiveSupport::TestCase
test "builder" do test "builder" do
assert_error "builder: unknown key: foo", builder: { "foo" => "bar" } assert_error "builder: unknown key: foo", builder: { "foo" => "bar" }
assert_error "builder/remote: should be a string", builder: { "remote" => { "foo" => "bar" } } assert_error "builder/remote: should be a hash", builder: { "remote" => true }
assert_error "builder/arch: should be an array or a string", builder: { "arch" => {} } assert_error "builder/remote: unknown key: foo", builder: { "remote" => { "foo" => "bar" } }
assert_error "builder/local: unknown key: foo", builder: { "local" => { "foo" => "bar" } }
assert_error "builder/remote/arch: should be a string", builder: { "remote" => { "arch" => [] } }
assert_error "builder/args: should be a hash", builder: { "args" => [ "foo" ] } assert_error "builder/args: should be a hash", builder: { "args" => [ "foo" ] }
assert_error "builder/cache/options: should be a string", builder: { "cache" => { "options" => [] } } assert_error "builder/cache/options: should be a string", builder: { "cache" => { "options" => [] } }
end end
@@ -101,7 +103,6 @@ class ConfigurationValidationTest < ActiveSupport::TestCase
valid_config = { valid_config = {
service: "app", service: "app",
image: "app", image: "app",
builder: { "arch" => "amd64" },
registry: { "username" => "user", "password" => "secret" }, registry: { "username" => "user", "password" => "secret" },
servers: [ "1.1.1.1" ] servers: [ "1.1.1.1" ]
} }

View File

@@ -8,7 +8,6 @@ class ConfigurationTest < ActiveSupport::TestCase
@deploy = { @deploy = {
service: "app", image: "dhh/app", service: "app", image: "dhh/app",
registry: { "username" => "dhh", "password" => "secret" }, registry: { "username" => "dhh", "password" => "secret" },
builder: { "arch" => "amd64" },
env: { "REDIS_URL" => "redis://x/y" }, env: { "REDIS_URL" => "redis://x/y" },
servers: [ "1.1.1.1", "1.1.1.2" ], servers: [ "1.1.1.1", "1.1.1.2" ],
volumes: [ "/local/path:/container/path" ] volumes: [ "/local/path:/container/path" ]
@@ -122,7 +121,7 @@ class ConfigurationTest < ActiveSupport::TestCase
test "version from uncommitted context" do test "version from uncommitted context" do
ENV.delete("VERSION") ENV.delete("VERSION")
config = Kamal::Configuration.new(@deploy.tap { |c| c[:builder]["context"] = "." }) config = Kamal::Configuration.new(@deploy.tap { |c| c[:builder] = { "context" => "." } })
Kamal::Git.expects(:revision).returns("git-version") Kamal::Git.expects(:revision).returns("git-version")
Kamal::Git.expects(:uncommitted_changes).returns("M file\n") Kamal::Git.expects(:uncommitted_changes).returns("M file\n")
@@ -268,7 +267,7 @@ class ConfigurationTest < ActiveSupport::TestCase
ssh_options: { user: "root", port: 22, log_level: :fatal, keepalive: true, keepalive_interval: 30 }, ssh_options: { user: "root", port: 22, log_level: :fatal, keepalive: true, keepalive_interval: 30 },
sshkit: {}, sshkit: {},
volume_args: [ "--volume", "/local/path:/container/path" ], volume_args: [ "--volume", "/local/path:/container/path" ],
builder: { "arch" => "amd64" }, builder: {},
logging: [ "--log-opt", "max-size=\"10m\"" ], logging: [ "--log-opt", "max-size=\"10m\"" ],
healthcheck: { "cmd"=>"curl -f http://localhost:3000/up || exit 1", "interval" => "1s", "path"=>"/up", "port"=>3000, "max_attempts" => 7, "cord" => "/tmp/kamal-cord", "log_lines" => 50 } } healthcheck: { "cmd"=>"curl -f http://localhost:3000/up || exit 1", "interval" => "1s", "path"=>"/up", "port"=>3000, "max_attempts" => 7, "cord" => "/tmp/kamal-cord", "log_lines" => 50 } }

View File

@@ -9,5 +9,3 @@ registry:
server: registry.digitalocean.com server: registry.digitalocean.com
username: <%= "my-user" %> username: <%= "my-user" %>
password: <%= "my-password" %> password: <%= "my-password" %>
builder:
arch: amd64

View File

@@ -4,5 +4,3 @@ registry:
server: registry.digitalocean.com server: registry.digitalocean.com
username: <%= "my-user" %> username: <%= "my-user" %>
password: <%= "my-password" %> password: <%= "my-password" %>
builder:
arch: amd64

View File

@@ -4,6 +4,4 @@ registry:
server: registry.digitalocean.com server: registry.digitalocean.com
username: <%= "my-user" %> username: <%= "my-user" %>
password: <%= "my-password" %> password: <%= "my-password" %>
builder:
arch: amd64
require_destination: true require_destination: true

View File

@@ -17,6 +17,4 @@ registry:
server: registry.digitalocean.com server: registry.digitalocean.com
username: user username: user
password: pw password: pw
builder:
arch: amd64
primary_role: web_tokyo primary_role: web_tokyo

View File

@@ -6,5 +6,3 @@ servers:
registry: registry:
username: user username: user
password: pw password: pw
builder:
arch: amd64

View File

@@ -10,8 +10,6 @@ servers:
registry: registry:
username: user username: user
password: pw password: pw
builder:
arch: amd64
accessories: accessories:
mysql: mysql:

View File

@@ -11,8 +11,6 @@ servers:
console: console:
hosts: hosts:
- 1.1.1.5 - 1.1.1.5
builder:
arch: amd64
registry: registry:
username: user username: user
password: pw password: pw

View File

@@ -6,6 +6,4 @@ servers:
registry: registry:
username: user username: user
password: pw password: pw
builder:
arch: amd64
asset_path: /public/assets asset_path: /public/assets

View File

@@ -7,8 +7,6 @@ servers:
workers: workers:
- "1.1.1.3" - "1.1.1.3"
- "1.1.1.4" - "1.1.1.4"
builder:
arch: amd64
registry: registry:
username: user username: user

View File

@@ -11,8 +11,6 @@ servers:
- 1.1.1.4: site1 - 1.1.1.4: site1
- 1.2.1.3: site2 - 1.2.1.3: site2
- 1.2.1.4: [ site2 experimental ] - 1.2.1.4: [ site2 experimental ]
builder:
arch: amd64
env: env:
clear: clear:
TEST: "root" TEST: "root"

View File

@@ -21,6 +21,4 @@ registry:
server: registry.digitalocean.com server: registry.digitalocean.com
username: user username: user
password: pw password: pw
builder:
arch: amd64
primary_role: web_tokyo primary_role: web_tokyo

View File

@@ -7,8 +7,6 @@ servers:
workers: workers:
- "1.1.1.3" - "1.1.1.3"
- "1.1.1.4" - "1.1.1.4"
builder:
arch: amd64
registry: registry:
username: user username: user

View File

@@ -26,8 +26,6 @@ servers:
hosts: hosts:
- 1.1.1.3 - 1.1.1.3
- 1.1.1.4 - 1.1.1.4
builder:
arch: amd64
env: env:
REDIS_URL: redis://x/y REDIS_URL: redis://x/y
registry: registry:

View File

@@ -7,8 +7,6 @@ servers:
workers: workers:
- "1.1.1.3" - "1.1.1.3"
- "1.1.1.4" - "1.1.1.4"
builder:
arch: amd64
registry: registry:
username: user username: user

View File

@@ -32,11 +32,10 @@ accessories:
port: 6379 port: 6379
directories: directories:
- data:/data - data:/data
builder:
arch: amd64
readiness_delay: 0 readiness_delay: 0
builder: builder:
arch: <%= Kamal::Utils.docker_arch == "arm64" ? "amd64" : "arm64" %> remote:
remote: ssh://app@1.1.1.5 arch: amd64
host: ssh://app@1.1.1.5

View File

@@ -32,8 +32,6 @@ accessories:
port: 6379 port: 6379
directories: directories:
- data:/data - data:/data
builder:
arch: amd64
readiness_delay: 0 readiness_delay: 0
@@ -42,5 +40,6 @@ ssh:
port: 22 port: 22
builder: builder:
arch: <%= Kamal::Utils.docker_arch == "arm64" ? "amd64" : "arm64" %> remote:
remote: ssh://app@1.1.1.5:2122 arch: amd64
host: ssh://app@1.1.1.5:2122

View File

@@ -14,5 +14,3 @@ registry:
server: registry.digitalocean.com server: registry.digitalocean.com
username: user username: user
password: pw password: pw
builder:
arch: amd64

View File

@@ -9,5 +9,3 @@ registry:
env: env:
secret: secret:
- PASSWORD - PASSWORD
builder:
arch: amd64

View File

@@ -13,5 +13,3 @@ registry:
server: registry.digitalocean.com server: registry.digitalocean.com
username: user username: user
password: pw password: pw
builder:
arch: amd64

View File

@@ -6,5 +6,3 @@ servers:
registry: registry:
username: user username: user
password: pw password: pw
builder:
arch: amd64

View File

@@ -36,5 +36,4 @@ accessories:
readiness_delay: 0 readiness_delay: 0
builder: builder:
arch: amd64
context: "." context: "."

View File

@@ -10,5 +10,3 @@ primary_role: workers
registry: registry:
username: user username: user
password: pw password: pw
builder:
arch: amd64

View File

@@ -23,8 +23,7 @@ registry:
username: root username: root
password: root password: root
builder: builder:
driver: docker multiarch: false
arch: <%= Kamal::Utils.docker_arch %>
args: args:
COMMIT_SHA: <%= `git rev-parse HEAD` %> COMMIT_SHA: <%= `git rev-parse HEAD` %>
healthcheck: healthcheck:

View File

@@ -17,8 +17,7 @@ registry:
username: root username: root
password: root password: root
builder: builder:
driver: docker multiarch: false
arch: <%= Kamal::Utils.docker_arch %>
args: args:
COMMIT_SHA: <%= `git rev-parse HEAD` %> COMMIT_SHA: <%= `git rev-parse HEAD` %>
healthcheck: healthcheck:

View File

@@ -77,7 +77,7 @@ class MainTest < IntegrationTest
assert_equal "app-#{version}", config[:service_with_version] assert_equal "app-#{version}", config[:service_with_version]
assert_equal [], config[:volume_args] assert_equal [], config[:volume_args]
assert_equal({ user: "root", port: 22, keepalive: true, keepalive_interval: 30, log_level: :fatal }, config[:ssh_options]) assert_equal({ user: "root", port: 22, keepalive: true, keepalive_interval: 30, log_level: :fatal }, config[:ssh_options])
assert_equal({ "driver" => "docker", "arch" => "amd64", "args" => { "COMMIT_SHA" => version } }, config[:builder]) assert_equal({ "multiarch" => false, "args" => { "COMMIT_SHA" => version } }, config[:builder])
assert_equal [ "--log-opt", "max-size=\"10m\"" ], config[:logging] assert_equal [ "--log-opt", "max-size=\"10m\"" ], config[:logging]
assert_equal({ "cmd"=>"wget -qO- http://localhost > /dev/null || exit 1", "interval"=>"1s", "max_attempts"=>3, "port"=>3000, "path"=>"/up", "cord"=>"/tmp/kamal-cord", "log_lines"=>50 }, config[:healthcheck]) assert_equal({ "cmd"=>"wget -qO- http://localhost > /dev/null || exit 1", "interval"=>"1s", "max_attempts"=>3, "port"=>3000, "path"=>"/up", "cord"=>"/tmp/kamal-cord", "log_lines"=>50 }, config[:healthcheck])
end end