Catch up with main
This commit is contained in:
9
lib/kamal/cli/alias/command.rb
Normal file
9
lib/kamal/cli/alias/command.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
class Kamal::Cli::Alias::Command < Thor::DynamicCommand
|
||||
def run(instance, args = [])
|
||||
if (_alias = KAMAL.config.aliases[name])
|
||||
Kamal::Cli::Main.start(Shellwords.split(_alias.command) + ARGV[1..-1])
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -71,11 +71,12 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
||||
end
|
||||
end
|
||||
|
||||
desc "exec [CMD]", "Execute a custom command on servers within the app container (use --help to show options)"
|
||||
desc "exec [CMD...]", "Execute a custom command on servers within the app container (use --help to show options)"
|
||||
option :interactive, aliases: "-i", type: :boolean, default: false, desc: "Execute command over ssh for an interactive shell (use for console/bash)"
|
||||
option :reuse, type: :boolean, default: false, desc: "Reuse currently running container instead of starting a new one"
|
||||
option :env, aliases: "-e", type: :hash, desc: "Set environment variables for the command"
|
||||
def exec(cmd)
|
||||
def exec(*cmd)
|
||||
cmd = Kamal::Utils.join_commands(cmd)
|
||||
env = options[:env]
|
||||
case
|
||||
when options[:interactive] && options[:reuse]
|
||||
|
||||
@@ -6,7 +6,8 @@ module Kamal::Cli
|
||||
class Base < Thor
|
||||
include SSHKit::DSL
|
||||
|
||||
def self.exit_on_failure?() true end
|
||||
def self.exit_on_failure?() false end
|
||||
def self.dynamic_command_class() Kamal::Cli::Alias::Command end
|
||||
|
||||
class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging"
|
||||
class_option :quiet, type: :boolean, aliases: "-q", desc: "Minimal logging"
|
||||
@@ -22,8 +23,14 @@ module Kamal::Cli
|
||||
|
||||
class_option :skip_hooks, aliases: "-H", type: :boolean, default: false, desc: "Don't run hooks"
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
def initialize(args = [], local_options = {}, config = {})
|
||||
if config[:current_command].is_a?(Kamal::Cli::Alias::Command)
|
||||
# When Thor generates a dynamic command, it doesn't attempt to parse the arguments.
|
||||
# For our purposes, it means the arguments are passed in args rather than local_options.
|
||||
super([], args, config)
|
||||
else
|
||||
super
|
||||
end
|
||||
@original_env = ENV.to_h.dup
|
||||
load_env
|
||||
initialize_commander(options_with_subcommand_class_options)
|
||||
|
||||
@@ -30,27 +30,26 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
||||
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
|
||||
end
|
||||
|
||||
# Get the command here to ensure the Dir.chdir doesn't interfere with it
|
||||
push = KAMAL.builder.push
|
||||
|
||||
run_locally do
|
||||
begin
|
||||
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
|
||||
execute *KAMAL.builder.inspect_builder
|
||||
rescue SSHKit::Command::Failed => e
|
||||
if e.message =~ /(context not found|no builder|does not exist)/
|
||||
if e.message =~ /(context not found|no builder|no compatible builder|does not exist)/
|
||||
warn "Missing compatible builder, so creating a new one first"
|
||||
begin
|
||||
cli.remove
|
||||
rescue SSHKit::Command::Failed
|
||||
raise unless e.message =~ /(context not found|no builder|does not exist)/
|
||||
end
|
||||
cli.create
|
||||
else
|
||||
raise
|
||||
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
|
||||
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
||||
end
|
||||
@@ -72,7 +71,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
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
class Kamal::Cli::Server < Kamal::Cli::Base
|
||||
desc "exec", "Run a custom command on the server (use --help to show options)"
|
||||
option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)"
|
||||
def exec(cmd)
|
||||
def exec(*cmd)
|
||||
cmd = Kamal::Utils.join_commands(cmd)
|
||||
hosts = KAMAL.hosts | KAMAL.accessory_hosts
|
||||
|
||||
case
|
||||
|
||||
@@ -18,6 +18,10 @@ registry:
|
||||
password:
|
||||
- KAMAL_REGISTRY_PASSWORD
|
||||
|
||||
# Configure builder setup.
|
||||
builder:
|
||||
arch: amd64
|
||||
|
||||
# Inject ENV variables into containers (secrets come from .env).
|
||||
# Remember to run `kamal env push` after making changes!
|
||||
# env:
|
||||
@@ -30,16 +34,6 @@ registry:
|
||||
# ssh:
|
||||
# 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).
|
||||
# accessories:
|
||||
# db:
|
||||
|
||||
@@ -27,7 +27,11 @@ class Kamal::Commander
|
||||
|
||||
def specific_primary!
|
||||
@specifics = nil
|
||||
self.specific_hosts = [ config.primary_host ]
|
||||
if specific_roles.present?
|
||||
self.specific_hosts = [ specific_roles.first.primary_host ]
|
||||
else
|
||||
self.specific_hosts = [ config.primary_host ]
|
||||
end
|
||||
end
|
||||
|
||||
def specific_roles=(role_names)
|
||||
@@ -113,6 +117,10 @@ class Kamal::Commander
|
||||
@traefik ||= Kamal::Commands::Traefik.new(config)
|
||||
end
|
||||
|
||||
def alias(name)
|
||||
config.aliases[name]
|
||||
end
|
||||
|
||||
|
||||
def with_verbosity(level)
|
||||
old_level = self.verbosity
|
||||
|
||||
@@ -85,6 +85,10 @@ module Kamal::Commands
|
||||
[ :git, *([ "-C", path ] if path), *args.compact ]
|
||||
end
|
||||
|
||||
def grep(*args)
|
||||
args.compact.unshift :grep
|
||||
end
|
||||
|
||||
def tags(**details)
|
||||
Kamal::Tags.from_config(config, **details)
|
||||
end
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
require "active_support/core_ext/string/filters"
|
||||
|
||||
class Kamal::Commands::Builder < Kamal::Commands::Base
|
||||
delegate :create, :remove, :push, :clean, :pull, :info, :context_hosts, :config_context_hosts, :validate_image,
|
||||
:first_mirror, to: :target
|
||||
delegate :create, :remove, :push, :clean, :pull, :info, :inspect_builder, :validate_image, :first_mirror, to: :target
|
||||
delegate :local?, :remote?, :pack?, to: "config.builder"
|
||||
|
||||
include Clone
|
||||
|
||||
@@ -11,49 +11,33 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
|
||||
end
|
||||
|
||||
def target
|
||||
if config.builder.multiarch?
|
||||
if config.builder.remote?
|
||||
if config.builder.local?
|
||||
multiarch_remote
|
||||
else
|
||||
native_remote
|
||||
end
|
||||
elsif config.builder.pack?
|
||||
pack
|
||||
if remote?
|
||||
if local?
|
||||
hybrid
|
||||
else
|
||||
multiarch
|
||||
remote
|
||||
end
|
||||
elsif pack?
|
||||
pack
|
||||
else
|
||||
if config.builder.cached?
|
||||
native_cached
|
||||
else
|
||||
native
|
||||
end
|
||||
local
|
||||
end
|
||||
end
|
||||
|
||||
def native
|
||||
@native ||= Kamal::Commands::Builder::Native.new(config)
|
||||
def remote
|
||||
@remote ||= Kamal::Commands::Builder::Remote.new(config)
|
||||
end
|
||||
|
||||
def native_cached
|
||||
@native ||= Kamal::Commands::Builder::Native::Cached.new(config)
|
||||
def local
|
||||
@local ||= Kamal::Commands::Builder::Local.new(config)
|
||||
end
|
||||
|
||||
def native_remote
|
||||
@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)
|
||||
def hybrid
|
||||
@hybrid ||= Kamal::Commands::Builder::Hybrid.new(config)
|
||||
end
|
||||
|
||||
def pack
|
||||
@pack ||= Kamal::Commands::Builder::Native::Pack.new(config)
|
||||
@pack ||= Kamal::Commands::Builder::Pack.new(config)
|
||||
end
|
||||
|
||||
def ensure_local_dependencies_installed
|
||||
|
||||
@@ -1,20 +1,42 @@
|
||||
|
||||
class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
||||
class BuilderError < StandardError; end
|
||||
|
||||
ENDPOINT_DOCKER_HOST_INSPECT = "'{{.Endpoints.docker.Host}}'"
|
||||
|
||||
delegate :argumentize, to: Kamal::Utils
|
||||
delegate :args, :secrets, :dockerfile, :target, :local_arch, :local_host, :pack_arch, :pack_builder, :pack_buildpacks, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, to: :builder_config
|
||||
delegate \
|
||||
:args, :secrets, :dockerfile, :target, :arches, :local_arches, :remote_arches, :remote,
|
||||
:pack_builder, :pack_buildpacks,
|
||||
:cache_from, :cache_to, :ssh, :driver, :docker_driver?,
|
||||
to: :builder_config
|
||||
|
||||
def clean
|
||||
docker :image, :rm, "--force", config.absolute_image
|
||||
end
|
||||
|
||||
def push
|
||||
docker :buildx, :build,
|
||||
"--push",
|
||||
*platform_options(arches),
|
||||
*([ "--builder", builder_name ] unless docker_driver?),
|
||||
*build_options,
|
||||
build_context
|
||||
end
|
||||
|
||||
def pull
|
||||
docker :pull, config.absolute_image
|
||||
end
|
||||
|
||||
def info
|
||||
combine \
|
||||
docker(:context, :ls),
|
||||
docker(:buildx, :ls)
|
||||
end
|
||||
|
||||
def inspect_builder
|
||||
docker :buildx, :inspect, builder_name unless docker_driver?
|
||||
end
|
||||
|
||||
def build_options
|
||||
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh ]
|
||||
end
|
||||
@@ -32,14 +54,6 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
||||
)
|
||||
end
|
||||
|
||||
def context_hosts
|
||||
:true
|
||||
end
|
||||
|
||||
def config_context_hosts
|
||||
[]
|
||||
end
|
||||
|
||||
def first_mirror
|
||||
docker(:info, "--format '{{index .RegistryConfig.Mirrors 0}}'")
|
||||
end
|
||||
@@ -88,7 +102,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
||||
config.builder
|
||||
end
|
||||
|
||||
def context_host(builder_name)
|
||||
docker :context, :inspect, builder_name, "--format", ENDPOINT_DOCKER_HOST_INSPECT
|
||||
def platform_options(arches)
|
||||
argumentize "--platform", arches.map { |arch| "linux/#{arch}" }.join(",") if arches.any?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ module Kamal::Commands::Builder::Clone
|
||||
end
|
||||
|
||||
def clone
|
||||
git :clone, Kamal::Git.root, path: clone_directory
|
||||
git :clone, Kamal::Git.root, "--recurse-submodules", path: clone_directory
|
||||
end
|
||||
|
||||
def clone_reset_steps
|
||||
@@ -14,7 +14,8 @@ module Kamal::Commands::Builder::Clone
|
||||
git(:remote, "set-url", :origin, Kamal::Git.root, path: build_directory),
|
||||
git(:fetch, :origin, path: build_directory),
|
||||
git(:reset, "--hard", Kamal::Git.revision, path: build_directory),
|
||||
git(:clean, "-fdx", path: build_directory)
|
||||
git(:clean, "-fdx", path: build_directory),
|
||||
git(:submodule, :update, "--init", path: build_directory)
|
||||
]
|
||||
end
|
||||
|
||||
|
||||
21
lib/kamal/commands/builder/hybrid.rb
Normal file
21
lib/kamal/commands/builder/hybrid.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
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, remote_context_name
|
||||
end
|
||||
end
|
||||
14
lib/kamal/commands/builder/local.rb
Normal file
14
lib/kamal/commands/builder/local.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
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
|
||||
@@ -1,41 +0,0 @@
|
||||
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
|
||||
@@ -1,61 +0,0 @@
|
||||
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
|
||||
@@ -1,20 +0,0 @@
|
||||
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
|
||||
@@ -1,25 +0,0 @@
|
||||
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
|
||||
@@ -1,67 +0,0 @@
|
||||
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
|
||||
@@ -1,4 +1,4 @@
|
||||
class Kamal::Commands::Builder::Native::Pack < Kamal::Commands::Builder::Native
|
||||
class Kamal::Commands::Builder::Pack < Kamal::Commands::Builder::Base
|
||||
def push
|
||||
combine \
|
||||
pack(:build,
|
||||
@@ -17,7 +17,7 @@ class Kamal::Commands::Builder::Native::Pack < Kamal::Commands::Builder::Native
|
||||
|
||||
private
|
||||
def platform
|
||||
"linux/#{pack_arch}"
|
||||
"linux/#{local_arches.first}"
|
||||
end
|
||||
|
||||
def buildpacks
|
||||
63
lib/kamal/commands/builder/remote.rb
Normal file
63
lib/kamal/commands/builder/remote.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
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
|
||||
|
||||
def inspect_builder
|
||||
combine \
|
||||
combine inspect_buildx, inspect_remote_context,
|
||||
[ "(echo no compatible builder && exit 1)" ],
|
||||
by: "||"
|
||||
end
|
||||
|
||||
private
|
||||
def builder_name
|
||||
"kamal-remote-#{remote.gsub(/[^a-z0-9_-]/, "-")}"
|
||||
end
|
||||
|
||||
def remote_context_name
|
||||
"#{builder_name}-context"
|
||||
end
|
||||
|
||||
def inspect_buildx
|
||||
pipe \
|
||||
docker(:buildx, :inspect, builder_name),
|
||||
grep("-q", "Endpoint:.*#{remote_context_name}")
|
||||
end
|
||||
|
||||
def inspect_remote_context
|
||||
pipe \
|
||||
docker(:context, :inspect, remote_context_name, "--format", ENDPOINT_DOCKER_HOST_INSPECT),
|
||||
grep("-xq", remote)
|
||||
end
|
||||
|
||||
def create_remote_context
|
||||
docker :context, :create, remote_context_name, "--description", "'#{builder_name} host'", "--docker", "'host=#{remote}'"
|
||||
end
|
||||
|
||||
def remove_remote_context
|
||||
docker :context, :rm, remote_context_name
|
||||
end
|
||||
|
||||
def create_buildx
|
||||
docker :buildx, :create, "--name", builder_name, remote_context_name
|
||||
end
|
||||
|
||||
def remove_buildx
|
||||
docker :buildx, :rm, builder_name
|
||||
end
|
||||
end
|
||||
@@ -9,7 +9,7 @@ class Kamal::Commands::Prune < Kamal::Commands::Base
|
||||
def tagged_images
|
||||
pipe \
|
||||
docker(:image, :ls, *service_filter, "--format", "'{{.ID}} {{.Repository}}:{{.Tag}}'"),
|
||||
"grep -v -w \"#{active_image_list}\"",
|
||||
grep("-v -w \"#{active_image_list}\""),
|
||||
"while read image tag; do docker rmi $tag; done"
|
||||
end
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class Kamal::Configuration
|
||||
delegate :argumentize, :optionize, to: Kamal::Utils
|
||||
|
||||
attr_reader :destination, :raw_config
|
||||
attr_reader :accessories, :boot, :builder, :env, :healthcheck, :logging, :traefik, :servers, :ssh, :sshkit, :registry
|
||||
attr_reader :accessories, :aliases, :boot, :builder, :env, :healthcheck, :logging, :traefik, :servers, :ssh, :sshkit, :registry
|
||||
|
||||
include Validation
|
||||
|
||||
@@ -54,6 +54,7 @@ class Kamal::Configuration
|
||||
@registry = Registry.new(config: self)
|
||||
|
||||
@accessories = @raw_config.accessories&.keys&.collect { |name| Accessory.new(name, config: self) } || []
|
||||
@aliases = @raw_config.aliases&.keys&.to_h { |name| [ name, Alias.new(name, config: self) ] } || {}
|
||||
@boot = Boot.new(config: self)
|
||||
@builder = Builder.new(config: self)
|
||||
@env = Env.new(config: @raw_config.env || {})
|
||||
|
||||
15
lib/kamal/configuration/alias.rb
Normal file
15
lib/kamal/configuration/alias.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
class Kamal::Configuration::Alias
|
||||
include Kamal::Configuration::Validation
|
||||
|
||||
attr_reader :name, :command
|
||||
|
||||
def initialize(name, config:)
|
||||
@name, @command = name.inquiry, config.raw_config["aliases"][name]
|
||||
|
||||
validate! \
|
||||
command,
|
||||
example: validation_yml["aliases"]["uname"],
|
||||
context: "aliases/#{name}",
|
||||
with: Kamal::Configuration::Validator::Alias
|
||||
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 local_disabled?
|
||||
[]
|
||||
elsif 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?
|
||||
!!builder_config["remote"]
|
||||
remote_arches.any?
|
||||
end
|
||||
|
||||
def local?
|
||||
!local_disabled? && (arches.empty? || local_arches.any?)
|
||||
end
|
||||
|
||||
def cached?
|
||||
@@ -59,12 +81,8 @@ class Kamal::Configuration::Builder
|
||||
builder_config["context"] || "."
|
||||
end
|
||||
|
||||
def local_arch
|
||||
builder_config["local"]["arch"] if local?
|
||||
end
|
||||
|
||||
def local_host
|
||||
builder_config["local"]["host"] if local?
|
||||
def driver
|
||||
builder_config.fetch("driver", "docker-container")
|
||||
end
|
||||
|
||||
def pack_arch
|
||||
@@ -79,12 +97,8 @@ class Kamal::Configuration::Builder
|
||||
builder_config["pack"]["buildpacks"] if pack?
|
||||
end
|
||||
|
||||
def remote_arch
|
||||
builder_config["remote"]["arch"] if remote?
|
||||
end
|
||||
|
||||
def remote_host
|
||||
builder_config["remote"]["host"] if remote?
|
||||
def local_disabled?
|
||||
builder_config["local"] == false
|
||||
end
|
||||
|
||||
def cache_from
|
||||
@@ -130,7 +144,23 @@ class Kamal::Configuration::Builder
|
||||
end
|
||||
end
|
||||
|
||||
def docker_driver?
|
||||
driver == "docker"
|
||||
end
|
||||
|
||||
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
|
||||
builder_config["cache"]&.fetch("image", nil) || "#{image}-build-cache"
|
||||
end
|
||||
@@ -166,4 +196,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
|
||||
|
||||
26
lib/kamal/configuration/docs/alias.yml
Normal file
26
lib/kamal/configuration/docs/alias.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
# Aliases
|
||||
#
|
||||
# Aliases are shortcuts for Kamal commands.
|
||||
#
|
||||
# For example, for a Rails app, you might open a console with:
|
||||
#
|
||||
# ```shell
|
||||
# kamal app exec -i -r console "rails console"
|
||||
# ```
|
||||
#
|
||||
# By defining an alias, like this:
|
||||
aliases:
|
||||
console: app exec -r console -i "rails console"
|
||||
# You can now open the console with:
|
||||
# ```shell
|
||||
# kamal console
|
||||
# ```
|
||||
|
||||
# Configuring aliases
|
||||
#
|
||||
# Aliases are defined in the root config under the alias key
|
||||
#
|
||||
# Each alias is named and can only contain lowercase letters, numbers, dashes and underscores.
|
||||
|
||||
aliases:
|
||||
uname: app exec -p -q -r web "uname -a"
|
||||
@@ -1,10 +1,10 @@
|
||||
# Builder
|
||||
#
|
||||
# The builder configuration controls how the application is built with `docker build` or `docker buildx build`
|
||||
# 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`
|
||||
# 2. Use `docker buildx build` to build a multiarch image for linux/amd64,linux/arm64 with that context
|
||||
# 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,37 +12,34 @@
|
||||
#
|
||||
# Options go under the builder key in the root configuration.
|
||||
builder:
|
||||
# Driver
|
||||
#
|
||||
# The build driver to use, defaults to `docker-container`
|
||||
driver: docker
|
||||
|
||||
# Multiarch
|
||||
# Arch
|
||||
#
|
||||
# Enables multiarch builds, defaults to `true`
|
||||
multiarch: false
|
||||
|
||||
# Local configuration
|
||||
#
|
||||
# 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
|
||||
|
||||
# Whether to allow local builds
|
||||
#
|
||||
# Defaults to true
|
||||
local: true
|
||||
|
||||
# Buildpack configuration
|
||||
#
|
||||
# The build configuration for using pack to build a Cloud Native Buildpack image.
|
||||
pack:
|
||||
builder: heroku/builder:24
|
||||
arch: amd64
|
||||
buildpacks:
|
||||
- heroku/ruby
|
||||
- heroku/procfile
|
||||
@@ -51,7 +48,7 @@ builder:
|
||||
#
|
||||
# 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
|
||||
|
||||
@@ -166,3 +166,9 @@ healthcheck:
|
||||
# Docker logging configuration, see kamal docs logging
|
||||
logging:
|
||||
...
|
||||
|
||||
# Aliases
|
||||
#
|
||||
# Alias configuration, see kamal docs alias
|
||||
aliases:
|
||||
...
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Environment variables
|
||||
#
|
||||
# Environment variables can be set directory in the Kamal configuration or
|
||||
# for loaded from a .env file, for secrets that should not be checked into Git.
|
||||
# Environment variables can be set directly in the Kamal configuration or
|
||||
# loaded from a .env file, for secrets that should not be checked into Git.
|
||||
|
||||
# Reading environment variables from the configuration
|
||||
#
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# On roles that are running Traefik, Kamal will supply a default healthcheck to `docker run`.
|
||||
# For other roles, by default no healthcheck is supplied.
|
||||
#
|
||||
# If no healthcheck is supplied and the image does not define one, they we wait for the container
|
||||
# If no healthcheck is supplied and the image does not define one, then we wait for the container
|
||||
# to reach a running state and then pause for the readiness delay.
|
||||
#
|
||||
# The default healthcheck is `curl -f http://localhost:<port>/<path>`, so it assumes that `curl`
|
||||
|
||||
@@ -13,32 +13,38 @@ class Kamal::Configuration::Validator
|
||||
|
||||
private
|
||||
def validate_against_example!(validation_config, example)
|
||||
validate_type! validation_config, Hash
|
||||
validate_type! validation_config, example.class
|
||||
|
||||
check_unknown_keys! validation_config, example
|
||||
if example.class == Hash
|
||||
check_unknown_keys! validation_config, example
|
||||
|
||||
validation_config.each do |key, value|
|
||||
next if extension?(key)
|
||||
with_context(key) do
|
||||
example_value = example[key]
|
||||
validation_config.each do |key, value|
|
||||
next if extension?(key)
|
||||
with_context(key) do
|
||||
example_value = example[key]
|
||||
|
||||
if example_value == "..."
|
||||
validate_type! value, *(Array if key == :servers), Hash
|
||||
elsif key == "hosts"
|
||||
validate_servers! value
|
||||
elsif example_value.is_a?(Array)
|
||||
validate_array_of! value, example_value.first.class
|
||||
elsif example_value.is_a?(Hash)
|
||||
case key.to_s
|
||||
when "options", "args"
|
||||
validate_type! value, Hash
|
||||
when "labels"
|
||||
validate_hash_of! value, example_value.first[1].class
|
||||
if example_value == "..."
|
||||
validate_type! value, *(Array if key == :servers), Hash
|
||||
elsif key == "hosts"
|
||||
validate_servers! value
|
||||
elsif example_value.is_a?(Array)
|
||||
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"
|
||||
validate_type! value, Hash
|
||||
when "labels"
|
||||
validate_hash_of! value, example_value.first[1].class
|
||||
else
|
||||
validate_against_example! value, example_value
|
||||
end
|
||||
else
|
||||
validate_against_example! value, example_value
|
||||
validate_type! value, example_value.class
|
||||
end
|
||||
else
|
||||
validate_type! value, example_value.class
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -69,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
|
||||
|
||||
|
||||
15
lib/kamal/configuration/validator/alias.rb
Normal file
15
lib/kamal/configuration/validator/alias.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
class Kamal::Configuration::Validator::Alias < Kamal::Configuration::Validator
|
||||
def validate!
|
||||
super
|
||||
|
||||
name = context.delete_prefix("aliases/")
|
||||
|
||||
if name !~ /\A[a-z0-9_-]+\z/
|
||||
error "Invalid alias name: '#{name}'. Must only contain lowercase letters, alphanumeric, hyphens and underscores."
|
||||
end
|
||||
|
||||
if Kamal::Cli::Main.commands.include?(name)
|
||||
error "Alias '#{name}' conflicts with a built-in command."
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,5 +5,9 @@ class Kamal::Configuration::Validator::Builder < Kamal::Configuration::Validator
|
||||
if config["cache"] && config["cache"]["type"]
|
||||
error "Invalid cache type: #{config["cache"]["type"]}" unless [ "gha", "registry" ].include?(config["cache"]["type"])
|
||||
end
|
||||
|
||||
error "Builder arch not set" unless config["arch"].present?
|
||||
|
||||
error "Cannot disable local builds, no remote is set" if config["local"] == false && config["remote"].blank?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -77,4 +77,20 @@ module Kamal::Utils
|
||||
def stable_sort!(elements, &block)
|
||||
elements.sort_by!.with_index { |element, index| [ block.call(element), index ] }
|
||||
end
|
||||
|
||||
def join_commands(commands)
|
||||
commands.map(&:strip).join(" ")
|
||||
end
|
||||
|
||||
def docker_arch
|
||||
arch = `docker info --format '{{.Architecture}}'`.strip
|
||||
case arch
|
||||
when /aarch64/
|
||||
"arm64"
|
||||
when /x86_64/
|
||||
"amd64"
|
||||
else
|
||||
arch
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module Kamal
|
||||
VERSION = "1.8.1"
|
||||
VERSION = "2.0.0.alpha"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user