diff --git a/lib/kamal/cli/main.rb b/lib/kamal/cli/main.rb index 3a56be4c..a47d8592 100644 --- a/lib/kamal/cli/main.rb +++ b/lib/kamal/cli/main.rb @@ -123,7 +123,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base end end - desc "docs", "Show Kamal documentation for configuration setting" + desc "docs [SECTION]", "Show Kamal configuration documentation" def docs(section = nil) case section when NilClass diff --git a/lib/kamal/cli/proxy.rb b/lib/kamal/cli/proxy.rb index 545cee2a..12d4c6b0 100644 --- a/lib/kamal/cli/proxy.rb +++ b/lib/kamal/cli/proxy.rb @@ -62,7 +62,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base end end - desc "upgrade", "Upgrade to kamal-proxy on servers (stop container, remove container, start new container, reboot app)" + desc "upgrade", "Upgrade to kamal-proxy on servers (stop container, remove container, start new container, reboot app)", hide: true 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" def upgrade diff --git a/lib/kamal/configuration/docs/builder.yml b/lib/kamal/configuration/docs/builder.yml index 6209a4a6..1c41a386 100644 --- a/lib/kamal/configuration/docs/builder.yml +++ b/lib/kamal/configuration/docs/builder.yml @@ -12,25 +12,25 @@ # # Options go under the builder key in the root configuration. builder: - # Driver - # - # The build driver to use, defaults to `docker-container` - driver: docker # Arch # - # 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 + # The architectures to build for - you can set an array or just a single value. + # + # Allowed values are `amd64` and `arm64` arch: - amd64 - # Remote configuration + # Remote # - # If you have a remote builder, you can configure it here + # The connection string for a remote builder. If supplied Kamal will use this + # for builds that do not match the local architecture of the deployment host. remote: ssh://docker@docker-builder - # Whether to allow local builds + # Local + # + # If set to false, Kamal will always use the remote builder even when building + # the local architecture. # # Defaults to true local: true @@ -78,7 +78,7 @@ builder: # Build secrets # - # Values are read from the environment. + # Values are read from the .kamal/secrets. # secrets: - SECRET1 @@ -103,3 +103,8 @@ builder: # # SSH agent socket or keys to expose to the build ssh: default=$SSH_AUTH_SOCK + + # Driver + # + # The build driver to use, defaults to `docker-container` + driver: docker diff --git a/lib/kamal/configuration/docs/env.yml b/lib/kamal/configuration/docs/env.yml index c2cf0ed0..513799d4 100644 --- a/lib/kamal/configuration/docs/env.yml +++ b/lib/kamal/configuration/docs/env.yml @@ -1,7 +1,7 @@ # Environment variables # # 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. +# read from .kamal/secrets. # Reading environment variables from the configuration # @@ -12,19 +12,20 @@ env: DATABASE_HOST: mysql-db1 DATABASE_PORT: 3306 -# Using .env file to load required environment variables +# Using .kamal/secrets file to load required environment variables # -# Kamal uses dotenv to automatically load environment variables set in the .env file present -# in the application root. +# Kamal uses dotenv to automatically load environment variables set in the .kamal/secrets file. # # This file can be used to set variables like KAMAL_REGISTRY_PASSWORD or database passwords. -# But for this reason you must ensure that .env files are not checked into Git or included -# in your Dockerfile! The format is just key-value like: +# You can use variable or command substitution in the secrets file. +# # ``` -# KAMAL_REGISTRY_PASSWORD=pw -# DB_PASSWORD=secret123 +# KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD +# RAILS_MASTER_KEY=$(cat config/master.key) # ``` # +# If you store secrets directly in .kamal/secrets, ensure that it is not checked into version control. +# # To pass the secrets you should list them under the `secret` key. When you do this the # other variables need to be moved under the `clear` key. # diff --git a/lib/kamal/configuration/docs/proxy.yml b/lib/kamal/configuration/docs/proxy.yml index 8e80d0be..6840a75c 100644 --- a/lib/kamal/configuration/docs/proxy.yml +++ b/lib/kamal/configuration/docs/proxy.yml @@ -1,5 +1,9 @@ # Proxy # +# Kamal uses [kamal-proxy](https://github.com/basecamp/kamal-proxy) to provide +# gapless deployments. It runs on ports 80 and 443 and forwards requests to the +# application container. +# # The proxy is configured in the root configuration under `proxy`. These are # options that are set when deploying the application, not when booting the proxy # @@ -13,20 +17,25 @@ proxy: # to this host to your app. # # If no hosts are set, then all requests will be forwarded, except for matching - # requests for other apps that do have a host set. + # requests for other apps deployed on that server that do have a host set. host: foo.example.com # App port # # The port the application container is exposed on + # # Defaults to 80 app_port: 3000 # SSL # - # Kamal Proxy can automatically obtain and renew TLS certificates for your applications. - # To ensure this set, the ssl flag. This only works if we are deploying to one server and - # the host flag is set. + # kamal-proxy can provide automatic HTTPS for your application via Let's Encrypt. + # + # This requires that we are deploying to a one server and the host option is set. + # The host value must point to the server we are deploying to and port 443 must be + # open for the Let's Encrypt challenge to succeed. + # + # Defaults to false ssl: true # Deploy timeout @@ -36,8 +45,8 @@ proxy: # Response timeout # - # How long to wait for requests to complete before timing out, defaults to 10 seconds - response_timeout: 30s + # How long to wait for requests to complete before timing out, defaults to 30 seconds + response_timeout: 10s # Healthcheck # @@ -70,7 +79,7 @@ proxy: # # Configure request logging for the proxy # You can specify request and response headers to log. - # By default, Cache-Control and Last-Modified request headers are logged + # By default, Cache-Control, Last-Modified and User-Agent request headers are logged logging: request_headers: - Cache-Control @@ -84,4 +93,7 @@ proxy: # Whether to forward the X-Forwarded-For and X-Forwarded-Proto headers (defaults to false) # # If you are behind a trusted proxy, you can set this to true to forward the headers. + # + # By default kamal-proxy will not forward the headers the ssl option is set to true, and + # will forward them if it is set to false. forward_headers: true diff --git a/lib/kamal/configuration/docs/registry.yml b/lib/kamal/configuration/docs/registry.yml index 3254e454..3fea9ad6 100644 --- a/lib/kamal/configuration/docs/registry.yml +++ b/lib/kamal/configuration/docs/registry.yml @@ -27,11 +27,13 @@ registry: # and [set up roles and permissions](https://cloud.google.com/artifact-registry/docs/access-control#permissions). # Normally, assigning a roles/artifactregistry.writer role should be sufficient. # -# Once the service account is ready, you need to generate and download a JSON key, base64 encode it and add to .env: +# Once the service account is ready, you need to generate and download a JSON key and base64 encode it: # # ```shell -# echo "KAMAL_REGISTRY_PASSWORD=$(base64 -i /path/to/key.json)" | tr -d "\\n" >> .env +# base64 -i /path/to/key.json | tr -d "\\n") # ``` +# You'll then need to set the KAMAL_REGISTRY_PASSWORD secret to that value. +# # Use the env variable as password along with _json_key_base64 as username. # Here’s the final configuration: diff --git a/lib/kamal/configuration/docs/role.yml b/lib/kamal/configuration/docs/role.yml index 8ed6e46c..0f75c550 100644 --- a/lib/kamal/configuration/docs/role.yml +++ b/lib/kamal/configuration/docs/role.yml @@ -47,4 +47,3 @@ servers: env: ... asset_path: /public - diff --git a/lib/kamal/configuration/proxy.rb b/lib/kamal/configuration/proxy.rb index 2671b4c8..8cce49b0 100644 --- a/lib/kamal/configuration/proxy.rb +++ b/lib/kamal/configuration/proxy.rb @@ -1,7 +1,7 @@ class Kamal::Configuration::Proxy include Kamal::Configuration::Validation - MINIMUM_VERSION = "v0.1.0" + MINIMUM_VERSION = "v0.3.0" DEFAULT_HTTP_PORT = 80 DEFAULT_HTTPS_PORT = 443 DEFAULT_IMAGE = "basecamp/kamal-proxy:#{MINIMUM_VERSION}" diff --git a/test/cli/proxy_test.rb b/test/cli/proxy_test.rb index 97520071..9466ec41 100644 --- a/test/cli/proxy_test.rb +++ b/test/cli/proxy_test.rb @@ -22,7 +22,7 @@ class CliProxyTest < CliTestCase end end - assert_includes exception.message, "kamal-proxy version v0.0.1 is too old, please reboot to update to at least v0.1.0" + assert_includes exception.message, "kamal-proxy version v0.0.1 is too old, please reboot to update to at least #{Kamal::Configuration::Proxy::MINIMUM_VERSION}" ensure Thread.report_on_exception = false end @@ -31,7 +31,7 @@ class CliProxyTest < CliTestCase Thread.report_on_exception = false SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :cut, "-d:", "-f2") - .returns("v0.1.0") + .returns(Kamal::Configuration::Proxy::MINIMUM_VERSION) .at_least_once run_command("boot").tap do |output| @@ -189,7 +189,7 @@ class CliProxyTest < CliTestCase SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :cut, "-d:", "-f2") - .returns("v0.1.0") + .returns(Kamal::Configuration::Proxy::MINIMUM_VERSION) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) .with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'") @@ -205,7 +205,7 @@ class CliProxyTest < CliTestCase assert_match "/usr/bin/env mkdir -p .kamal", output assert_match "docker network create kamal", output assert_match "docker login -u [REDACTED] -p [REDACTED]", output - assert_match "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" basecamp/kamal-proxy:v0.1.0", output + assert_match "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" basecamp/kamal-proxy:#{Kamal::Configuration::Proxy::MINIMUM_VERSION}", output assert_match "/usr/bin/env mkdir -p .kamal", output assert_match %r{docker rename app-web-latest app-web-latest_replaced_.*}, output assert_match "/usr/bin/env mkdir -p .kamal/apps/app/env/roles", output @@ -228,7 +228,7 @@ class CliProxyTest < CliTestCase SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :cut, "-d:", "-f2") - .returns("v0.1.0") + .returns(Kamal::Configuration::Proxy::MINIMUM_VERSION) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) .with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'") diff --git a/test/integration/main_test.rb b/test/integration/main_test.rb index 5a4eb91c..11e2ac94 100644 --- a/test/integration/main_test.rb +++ b/test/integration/main_test.rb @@ -28,7 +28,7 @@ class MainTest < IntegrationTest assert_match /Proxy Host: vm2/, details assert_match /App Host: vm1/, details assert_match /App Host: vm2/, details - assert_match /basecamp\/kamal-proxy:v0.1.0/, details + assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::Proxy::MINIMUM_VERSION}/, details assert_match /registry:4443\/app:#{first_version}/, details audit = kamal :audit, capture: true diff --git a/test/integration/proxy_test.rb b/test/integration/proxy_test.rb index f9c7133b..2888ebfd 100644 --- a/test/integration/proxy_test.rb +++ b/test/integration/proxy_test.rb @@ -53,11 +53,11 @@ class ProxyTest < IntegrationTest private def assert_proxy_running - assert_match /basecamp\/kamal-proxy:v0.1.0 \"kamal-proxy run\"/, proxy_details + assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::Proxy::MINIMUM_VERSION} \"kamal-proxy run\"/, proxy_details end def assert_proxy_not_running - assert_no_match /basecamp\/kamal-proxy:v0.1.0 \"kamal-proxy run\"/, proxy_details + assert_no_match /basecamp\/kamal-proxy:#{Kamal::Configuration::Proxy::MINIMUM_VERSION} \"kamal-proxy run\"/, proxy_details end def proxy_details