Proxy boot config

Add commands for managing proxy boot config. Since the proxy can be
shared by multiple applications, the configuration doesn't belong in
`config/deploy.yml`.

Instead you can set the config with:

```
Usage:
  kamal proxy boot_config <set|get|clear>

Options:
      [--publish], [--no-publish], [--skip-publish]   # Publish the proxy ports on the host
                                                      # Default: true
      [--http-port=N]                                 # HTTP port to publish on the host
                                                      # Default: 80
      [--https-port=N]                                # HTTPS port to publish on the host
                                                      # Default: 443
      [--docker-options=option=value option2=value2]  # Docker options to pass to the proxy container
```

By default we boot the proxy with `--publish 80:80 --publish 443:443`.

You can stop it from publishing ports, specify different ports and pass
other docker options.

The config is stored in `.kamal/proxy/options` as arguments to be passed
verbatim to docker run.

Where someone wants to set the options in their application they can do
that by calling `kamal proxy boot_config set` in a pre-deploy hook.

There's an example in the integration tests showing how to use this to
front kamal-proxy with Traefik, using an accessory.
This commit is contained in:
Donal McBreen
2024-09-25 14:31:10 -04:00
parent e71bfcbadd
commit f6851048a6
15 changed files with 241 additions and 31 deletions

View File

@@ -21,6 +21,36 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
end
end
desc "boot_config <set|get|clear>", "Mange kamal-proxy boot configuration"
option :publish, type: :boolean, default: true, desc: "Publish the proxy ports on the host"
option :http_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTP_PORT, desc: "HTTP port to publish on the host"
option :https_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTPS_PORT, desc: "HTTPS port to publish on the host"
option :docker_options, type: :array, default: [], desc: "Docker options to pass to the proxy container", banner: "option=value option2=value2"
def boot_config(subcommand)
case subcommand
when "set"
boot_options = [
*(KAMAL.config.proxy_publish_args(options[:http_port], options[:https_port]) if options[:publish]),
*options[:docker_options].map { |option| "--#{option}" }
]
on(KAMAL.proxy_hosts) do |host|
execute(*KAMAL.proxy.ensure_proxy_directory)
upload! StringIO.new(boot_options.join(" ")), KAMAL.config.proxy_options_file
end
when "get"
on(KAMAL.proxy_hosts) do |host|
puts "Host #{host}: #{capture_with_info(*KAMAL.proxy.get_boot_options)}"
end
when "reset"
on(KAMAL.proxy_hosts) do |host|
execute *KAMAL.proxy.reset_boot_options
end
else
raise ArgumentError, "Unknown boot_config subcommand #{subcommand}"
end
end
desc "reboot", "Reboot proxy on servers (stop container, remove container, start new container)"
option :rolling, type: :boolean, default: false, desc: "Reboot proxy on hosts in sequence, rather than in parallel"
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
@@ -169,6 +199,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
stop
remove_container
remove_image
remove_proxy_directory
end
end
end
@@ -193,6 +224,15 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
end
end
desc "remove_proxy_directory", "Remove the proxy directory from servers", hide: true
def remove_proxy_directory
with_lock do
on(KAMAL.proxy_hosts) do
execute *KAMAL.proxy.remove_proxy_directory, raise_on_non_zero_exit: false
end
end
end
private
def removal_allowed?(force)
on(KAMAL.proxy_hosts) do |host|

View File

@@ -7,9 +7,8 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
"--network", "kamal",
"--detach",
"--restart", "unless-stopped",
*config.proxy_publish_args,
"--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy",
*config.logging_args,
"\$\(#{get_boot_options.join(" ")}\)",
config.proxy_image
end
@@ -65,6 +64,22 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
)
end
def ensure_proxy_directory
make_directory config.proxy_directory
end
def remove_proxy_directory
remove_directory config.proxy_directory
end
def get_boot_options
combine [ :cat, config.proxy_options_file ], [ :echo, "\"#{config.proxy_options_default.join(" ")}\"" ], by: "||"
end
def reset_boot_options
remove_file config.proxy_options_file
end
private
def container_name
config.proxy_container_name

View File

@@ -246,8 +246,12 @@ class Kamal::Configuration
env_tags.detect { |t| t.name == name.to_s }
end
def proxy_publish_args
argumentize "--publish", [ "#{PROXY_HTTP_PORT}:#{PROXY_HTTP_PORT}", "#{PROXY_HTTPS_PORT}:#{PROXY_HTTPS_PORT}" ]
def proxy_publish_args(http_port, https_port)
argumentize "--publish", [ "#{http_port}:#{PROXY_HTTP_PORT}", "#{https_port}:#{PROXY_HTTPS_PORT}" ]
end
def proxy_options_default
proxy_publish_args PROXY_HTTP_PORT, PROXY_HTTPS_PORT
end
def proxy_image
@@ -258,6 +262,14 @@ class Kamal::Configuration
"kamal-proxy"
end
def proxy_directory
File.join run_directory, "proxy"
end
def proxy_options_file
File.join proxy_directory, "options"
end
def to_h
{