Merge branch 'main' into feat/custom-ssl

This commit is contained in:
Dainel Vera
2025-05-19 15:38:33 -06:00
committed by GitHub
27 changed files with 199 additions and 80 deletions

View File

@@ -14,6 +14,10 @@ class Kamal::Cli::Build < Kamal::Cli::Base
def push
cli = self
# Ensure pre-connect hooks run before the build, they may needed for a remote builder
# or the pre-build hooks.
pre_connect_if_required
ensure_docker_installed
login_to_registry_locally

View File

@@ -31,6 +31,8 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
option :registry, type: :string, default: nil, desc: "Registry to use for the proxy image"
option :repository, type: :string, default: nil, desc: "Repository for the proxy image"
option :image_version, type: :string, default: nil, desc: "Version of the proxy to run"
option :metrics_port, type: :numeric, default: nil, desc: "Port to report prometheus metrics on"
option :debug, type: :boolean, default: false, desc: "Whether to run the proxy in debug mode"
option :docker_options, type: :array, default: [], desc: "Docker options to pass to the proxy container", banner: "option=value option2=value2"
def boot_config(subcommand)
proxy_boot_config = KAMAL.config.proxy_boot
@@ -40,6 +42,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
boot_options = [
*(proxy_boot_config.publish_args(options[:http_port], options[:https_port], options[:publish_host_ip]) if options[:publish]),
*(proxy_boot_config.logging_args(options[:log_max_size])),
*("--expose=#{options[:metrics_port]}" if options[:metrics_port]),
*options[:docker_options].map { |option| "--#{option}" }
]
@@ -51,6 +54,9 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
image_version = options[:image_version]
run_command_options = { debug: options[:debug] || nil, "metrics-port": options[:metrics_port] }.compact
run_command = "kamal-proxy run #{Kamal::Utils.optionize(run_command_options).join(" ")}" if run_command_options.any?
on(KAMAL.proxy_hosts) do |host|
execute(*KAMAL.proxy.ensure_proxy_directory)
if boot_options != proxy_boot_config.default_boot_options
@@ -70,6 +76,12 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
else
execute *KAMAL.proxy.reset_image_version, raise_on_non_zero_exit: false
end
if run_command
upload! StringIO.new(run_command), proxy_boot_config.run_command_file
else
execute *KAMAL.proxy.reset_run_command, raise_on_non_zero_exit: false
end
end
when "get"
@@ -81,6 +93,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
execute *KAMAL.proxy.reset_boot_options, raise_on_non_zero_exit: false
execute *KAMAL.proxy.reset_image, raise_on_non_zero_exit: false
execute *KAMAL.proxy.reset_image_version, raise_on_non_zero_exit: false
execute *KAMAL.proxy.reset_run_command, raise_on_non_zero_exit: false
end
else
raise ArgumentError, "Unknown boot_config subcommand #{subcommand}"
@@ -107,18 +120,6 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
execute *KAMAL.proxy.ensure_apps_config_directory
execute *KAMAL.proxy.run
KAMAL.roles_on(host).select(&:running_proxy?).each do |role|
app = KAMAL.app(role: role, host: host)
version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
endpoint = capture_with_info(*app.container_id_for_version(version)).strip
if endpoint.present?
info "Deploying #{endpoint} for role `#{role}` on #{host}..."
execute *app.deploy(target: endpoint)
end
end
end
run_hook "post-proxy-reboot", hosts: host_list
end

View File

@@ -7,7 +7,7 @@
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_ROLES (if set)
# KAMAL_DESTINATION (if set)
# KAMAL_RUNTIME

View File

@@ -13,7 +13,7 @@
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_ROLES (if set)
# KAMAL_DESTINATION (if set)
if [ -n "$(git status --porcelain)" ]; then

View File

@@ -9,7 +9,7 @@
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_ROLES (if set)
# KAMAL_DESTINATION (if set)
# KAMAL_RUNTIME

View File

@@ -13,7 +13,7 @@
# KAMAL_HOSTS
# KAMAL_COMMAND
# KAMAL_SUBCOMMAND
# KAMAL_ROLE (if set)
# KAMAL_ROLES (if set)
# KAMAL_DESTINATION (if set)
# Only check the build status for production deployments

View File

@@ -11,7 +11,7 @@ class Kamal::Commander::Specifics
@primary_role = primary_or_first_role(roles_on(primary_host))
stable_sort!(roles) { |role| role == primary_role ? 0 : 1 }
stable_sort!(hosts) { |host| roles_on(host).any? { |role| role == primary_role } ? 0 : 1 }
sort_primary_role_hosts_first!(hosts)
end
def roles_on(host)
@@ -19,7 +19,7 @@ class Kamal::Commander::Specifics
end
def app_hosts
config.app_hosts & specified_hosts
@app_hosts ||= sort_primary_role_hosts_first!(config.app_hosts & specified_hosts)
end
def proxy_hosts
@@ -55,4 +55,8 @@ class Kamal::Commander::Specifics
specified_hosts
end
end
def sort_primary_role_hosts_first!(hosts)
stable_sort!(hosts) { |host| roles_on(host).any? { |role| role == primary_role } ? 0 : 1 }
end
end

View File

@@ -70,7 +70,7 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
end
def boot_config
[ :echo, "#{substitute(read_boot_options)} #{substitute(read_image)}:#{substitute(read_image_version)}" ]
[ :echo, "#{substitute(read_boot_options)} #{substitute(read_image)}:#{substitute(read_image_version)} #{substitute(read_run_command)}" ]
end
def read_boot_options
@@ -85,6 +85,10 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
read_file(config.proxy_boot.image_version_file, default: Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION)
end
def read_run_command
read_file(config.proxy_boot.run_command_file)
end
def reset_boot_options
remove_file config.proxy_boot.options_file
end
@@ -97,6 +101,10 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
remove_file config.proxy_boot.image_version_file
end
def reset_run_command
remove_file config.proxy_boot.run_command_file
end
private
def container_name
config.proxy_boot.container_name

View File

@@ -63,7 +63,7 @@ class Kamal::Configuration
@env = Env.new(config: @raw_config.env || {}, secrets: secrets)
@logging = Logging.new(logging_config: @raw_config.logging)
@proxy = Proxy.new(config: self, proxy_config: @raw_config.key?(:proxy) ? @raw_config.proxy : {}, secrets: secrets)
@proxy = Proxy.new(config: self, proxy_config: @raw_config.proxy, secrets: secrets)
@proxy_boot = Proxy::Boot.new(config: self)
@ssh = Ssh.new(config: self)
@sshkit = Sshkit.new(config: self)

View File

@@ -32,7 +32,7 @@ class Kamal::Configuration::Accessory
end
def hosts
hosts_from_host || hosts_from_hosts || hosts_from_roles
hosts_from_host || hosts_from_hosts || hosts_from_roles || hosts_from_tags
end
def port
@@ -202,11 +202,31 @@ class Kamal::Configuration::Accessory
end
def hosts_from_roles
if accessory_config.key?("roles")
if accessory_config.key?("role")
config.role(accessory_config["role"])&.hosts
elsif accessory_config.key?("roles")
accessory_config["roles"].flat_map { |role| config.role(role)&.hosts }
end
end
def hosts_from_tags
if accessory_config.key?("tag")
extract_hosts_from_config_with_tag(accessory_config["tag"])
elsif accessory_config.key?("tags")
accessory_config["tags"].flat_map { |tag| extract_hosts_from_config_with_tag(tag) }
end
end
def extract_hosts_from_config_with_tag(tag)
if (servers_with_roles = config.raw_config.servers).is_a?(Hash)
servers_with_roles.flat_map do |role, servers_in_role|
servers_in_role.filter_map do |host|
host.keys.first if host.is_a?(Hash) && host.values.first.include?(tag)
end
end
end
end
def network
accessory_config["network"] || DEFAULT_NETWORK
end
@@ -214,6 +234,8 @@ class Kamal::Configuration::Accessory
def ensure_valid_roles
if accessory_config["roles"] && (missing_roles = accessory_config["roles"] - config.roles.map(&:name)).any?
raise Kamal::ConfigurationError, "accessories/#{name}: unknown roles #{missing_roles.join(", ")}"
elsif accessory_config["role"] && !config.role(accessory_config["role"])
raise Kamal::ConfigurationError, "accessories/#{name}: unknown role #{accessory_config["role"]}"
end
end
end

View File

@@ -46,13 +46,18 @@ accessories:
# Accessory hosts
#
# Specify one of `host`, `hosts`, or `roles`:
# Specify one of `host`, `hosts`, `role`, `roles`, `tag` or `tags`:
host: mysql-db1
hosts:
- mysql-db1
- mysql-db2
role: mysql
roles:
- mysql
tag: writer
tags:
- writer
- reader
# Custom command
#

View File

@@ -10,11 +10,6 @@
# They are application-specific, so they are not shared when multiple applications
# run on the same proxy.
#
# The proxy is enabled by default on the primary role but can be disabled by
# setting `proxy: false`.
#
# It is disabled by default on all other roles but can be enabled by setting
# `proxy: true` or providing a proxy configuration.
proxy:
# Hosts
#
@@ -126,3 +121,30 @@ proxy:
response_headers:
- X-Request-ID
- X-Request-Start
# Enabling/disabling the proxy on roles
#
# The proxy is enabled by default on the primary role but can be disabled by
# setting `proxy: false` in the primary role's configuration.
#
# ```yaml
# servers:
# web:
# hosts:
# - ...
# proxy: false
# ```
#
# It is disabled by default on all other roles but can be enabled by setting
# `proxy: true` or providing a proxy configuration for that role.
#
# ```yaml
# servers:
# web:
# hosts:
# - ...
# web2:
# hosts:
# - ...
# proxy: true
# ```

View File

@@ -11,6 +11,7 @@ class Kamal::Configuration::Proxy
def initialize(config:, proxy_config:, secrets:, context: "proxy")
@config = config
@proxy_config = proxy_config
@proxy_config = {} if @proxy_config.nil?
@secrets = secrets
validate! @proxy_config, with: Kamal::Configuration::Validator::Proxy, context: context
end

View File

@@ -1,5 +1,5 @@
class Kamal::Configuration::Proxy::Boot
MINIMUM_VERSION = "v0.8.7"
MINIMUM_VERSION = "v0.9.0"
DEFAULT_HTTP_PORT = 80
DEFAULT_HTTPS_PORT = 443
DEFAULT_LOG_MAX_SIZE = "10m"
@@ -66,6 +66,10 @@ class Kamal::Configuration::Proxy::Boot
File.join host_directory, "image_version"
end
def run_command_file
File.join host_directory, "run_command"
end
def apps_directory
File.join host_directory, "apps-config"
end

View File

@@ -2,8 +2,8 @@ class Kamal::Configuration::Validator::Accessory < Kamal::Configuration::Validat
def validate!
super
if (config.keys & [ "host", "hosts", "roles" ]).size != 1
error "specify one of `host`, `hosts` or `roles`"
if (config.keys & [ "host", "hosts", "role", "roles", "tag", "tags" ]).size != 1
error "specify one of `host`, `hosts`, `role`, `roles`, `tag` or `tags`"
end
validate_docker_options!(config["options"])

View File

@@ -1,3 +1,3 @@
module Kamal
VERSION = "2.5.3"
VERSION = "2.6.1"
end