From f6851048a6721ad7f0bee3cc8074bb316edc52fc Mon Sep 17 00:00:00 2001 From: Donal McBreen Date: Wed, 25 Sep 2024 14:31:10 -0400 Subject: [PATCH] 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 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. --- lib/kamal/cli/proxy.rb | 40 +++++++++++ lib/kamal/commands/proxy.rb | 19 ++++- lib/kamal/configuration.rb | 16 ++++- test/cli/accessory_test.rb | 2 +- test/cli/proxy_test.rb | 70 +++++++++++++++++-- test/commands/proxy_test.rb | 36 +++++----- test/integration/docker/deployer/Dockerfile | 2 + .../app_with_traefik/.kamal/hooks/pre-deploy | 3 + .../deployer/app_with_traefik/.kamal/secrets | 1 + .../deployer/app_with_traefik/Dockerfile | 9 +++ .../app_with_traefik/config/deploy.yml | 29 ++++++++ .../deployer/app_with_traefik/default.conf | 17 +++++ test/integration/integration_test.rb | 4 +- test/integration/main_test.rb | 17 +++++ test/test_helper.rb | 7 ++ 15 files changed, 241 insertions(+), 31 deletions(-) create mode 100755 test/integration/docker/deployer/app_with_traefik/.kamal/hooks/pre-deploy create mode 100644 test/integration/docker/deployer/app_with_traefik/.kamal/secrets create mode 100644 test/integration/docker/deployer/app_with_traefik/Dockerfile create mode 100644 test/integration/docker/deployer/app_with_traefik/config/deploy.yml create mode 100644 test/integration/docker/deployer/app_with_traefik/default.conf diff --git a/lib/kamal/cli/proxy.rb b/lib/kamal/cli/proxy.rb index 66912e070..89fb2fd7c 100644 --- a/lib/kamal/cli/proxy.rb +++ b/lib/kamal/cli/proxy.rb @@ -21,6 +21,36 @@ def boot end end + desc "boot_config ", "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 @@ def remove stop remove_container remove_image + remove_proxy_directory end end end @@ -193,6 +224,15 @@ def remove_image 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| diff --git a/lib/kamal/commands/proxy.rb b/lib/kamal/commands/proxy.rb index 5ac1c94e4..acff3dbd6 100644 --- a/lib/kamal/commands/proxy.rb +++ b/lib/kamal/commands/proxy.rb @@ -7,9 +7,8 @@ def run "--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 @@ def cleanup_traefik ) 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 diff --git a/lib/kamal/configuration.rb b/lib/kamal/configuration.rb index 2848a3650..c5db6edf4 100644 --- a/lib/kamal/configuration.rb +++ b/lib/kamal/configuration.rb @@ -246,8 +246,12 @@ def env_tag(name) 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 @@ def proxy_container_name "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 { diff --git a/test/cli/accessory_test.rb b/test/cli/accessory_test.rb index b8da2a7ab..05431fcbd 100644 --- a/test/cli/accessory_test.rb +++ b/test/cli/accessory_test.rb @@ -41,7 +41,7 @@ class CliAccessoryTest < CliTestCase test "upload" do run_command("upload", "mysql").tap do |output| assert_match "mkdir -p app-mysql/etc/mysql", output - assert_match "test/fixtures/files/my.cnf app-mysql/etc/mysql/my.cnf", output + assert_match "test/fixtures/files/my.cnf to app-mysql/etc/mysql/my.cnf", output assert_match "chmod 755 app-mysql/etc/mysql/my.cnf", output end end diff --git a/test/cli/proxy_test.rb b/test/cli/proxy_test.rb index c9987a51a..2cfdf0f3a 100644 --- a/test/cli/proxy_test.rb +++ b/test/cli/proxy_test.rb @@ -4,7 +4,7 @@ class CliProxyTest < CliTestCase test "boot" do run_command("boot").tap do |output| assert_match "docker login", output - assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}", output + assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image}", output end end @@ -18,7 +18,7 @@ class CliProxyTest < CliTestCase exception = assert_raises do run_command("boot").tap do |output| assert_match "docker login", output - assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}", output + assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image}", output end end @@ -36,7 +36,7 @@ class CliProxyTest < CliTestCase run_command("boot").tap do |output| assert_match "docker login", 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 kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}", output + assert_match "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image}", output end ensure Thread.report_on_exception = false @@ -57,13 +57,13 @@ class CliProxyTest < CliTestCase assert_match "docker container stop kamal-proxy on 1.1.1.1", output assert_match "Running docker container stop traefik ; docker container prune --force --filter label=org.opencontainers.image.title=Traefik && docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik on 1.1.1.1", output assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output - assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image} on 1.1.1.1", output + assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image} on 1.1.1.1", output assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target \"abcdefabcdef:80\" --deploy-timeout \"6s\" --drain-timeout \"30s\" --buffer-requests --buffer-responses --log-request-header \"Cache-Control\" --log-request-header \"Last-Modified\" --log-request-header \"User-Agent\" on 1.1.1.1", output assert_match "docker container stop kamal-proxy on 1.1.1.2", output assert_match "Running docker container stop traefik ; docker container prune --force --filter label=org.opencontainers.image.title=Traefik && docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik on 1.1.1.2", output assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.2", output - assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image} on 1.1.1.2", output + assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image} on 1.1.1.2", output assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target \"abcdefabcdef:80\" --deploy-timeout \"6s\" --drain-timeout \"30s\" --buffer-requests --buffer-responses --log-request-header \"Cache-Control\" --log-request-header \"Last-Modified\" --log-request-header \"User-Agent\" on 1.1.1.2", output end end @@ -198,11 +198,11 @@ 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 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 "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") 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 - assert_match %r{/usr/bin/env .* .kamal/apps/app/env/roles/web.env}, output + assert_match "Uploading \"\\n\" to .kamal/apps/app/env/roles/web.env", output assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-.* -e KAMAL_CONTAINER_NAME="app-web-latest" -e KAMAL_VERSION="latest" --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size="10m" --label service="app" --label role="web" --label destination dhh/app:latest}, output assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target \"12345678:80\" --deploy-timeout \"6s\" --drain-timeout \"30s\" --buffer-requests --buffer-responses --log-request-header \"Cache-Control\" --log-request-header \"Last-Modified\" --log-request-header \"User-Agent\"", output assert_match "docker container ls --all --filter name=^app-web-12345678$ --quiet | xargs docker stop", output @@ -236,6 +236,62 @@ class CliProxyTest < CliTestCase end end + test "boot_config set" do + run_command("boot_config", "set").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output + assert_match "Uploading \"--publish 80:80 --publish 443:443\" to .kamal/proxy/options on #{host}", output + end + end + end + + test "boot_config set no publish" do + run_command("boot_config", "set", "--publish", "false").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output + assert_match "Uploading \"\" to .kamal/proxy/options on #{host}", output + end + end + end + + test "boot_config set custom ports" do + run_command("boot_config", "set", "--http-port", "8080", "--https-port", "8443").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output + assert_match "Uploading \"--publish 8080:80 --publish 8443:443\" to .kamal/proxy/options on #{host}", output + end + end + end + + test "boot_config set docker options" do + run_command("boot_config", "set", "--docker_options", "label=foo=bar", "add_host=thishost:thathost").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output + assert_match "Uploading \"--publish 80:80 --publish 443:443 --label=foo=bar --add_host=thishost:thathost\" to .kamal/proxy/options on #{host}", output + end + end + end + + test "boot_config get" do + SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) + .with(:cat, ".kamal/proxy/options", "||", :echo, "\"--publish 80:80 --publish 443:443\"") + .returns("--publish 80:80 --publish 8443:443 --label=foo=bar") + .twice + + run_command("boot_config", "get").tap do |output| + assert_match "Host 1.1.1.1: --publish 80:80 --publish 8443:443 --label=foo=bar", output + assert_match "Host 1.1.1.2: --publish 80:80 --publish 8443:443 --label=foo=bar", output + end + end + + test "boot_config reset" do + run_command("boot_config", "reset").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "rm .kamal/proxy/options on #{host}", output + end + end + end + private def run_command(*command, fixture: :with_proxy) stdouted { Kamal::Cli::Proxy.start([ *command, "-c", "test/fixtures/deploy_#{fixture}.yml" ]) } diff --git a/test/commands/proxy_test.rb b/test/commands/proxy_test.rb index e8a3f2529..4af785335 100644 --- a/test/commands/proxy_test.rb +++ b/test/commands/proxy_test.rb @@ -15,13 +15,7 @@ class CommandsProxyTest < ActiveSupport::TestCase test "run" do assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}", - new_command.run.join(" ") - end - - test "run with ports configured" do - assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}", + "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}", new_command.run.join(" ") end @@ -29,15 +23,7 @@ class CommandsProxyTest < ActiveSupport::TestCase @config.delete(:proxy) assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}", - new_command.run.join(" ") - end - - test "run with logging config" do - @config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } } - - assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}", + "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}", new_command.run.join(" ") end @@ -119,6 +105,24 @@ class CommandsProxyTest < ActiveSupport::TestCase new_command.version.join(" ") end + test "ensure_proxy_directory" do + assert_equal \ + "mkdir -p .kamal/proxy", + new_command.ensure_proxy_directory.join(" ") + end + + test "get_boot_options" do + assert_equal \ + "cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\"", + new_command.get_boot_options.join(" ") + end + + test "reset_boot_options" do + assert_equal \ + "rm .kamal/proxy/options", + new_command.reset_boot_options.join(" ") + end + private def new_command Kamal::Commands::Proxy.new(Kamal::Configuration.new(@config, version: "123")) diff --git a/test/integration/docker/deployer/Dockerfile b/test/integration/docker/deployer/Dockerfile index 269f78b09..c71328619 100644 --- a/test/integration/docker/deployer/Dockerfile +++ b/test/integration/docker/deployer/Dockerfile @@ -19,6 +19,7 @@ RUN apt-get update --fix-missing && apt-get install -y docker-ce docker-ce-cli c COPY *.sh . COPY app/ app/ COPY app_with_roles/ app_with_roles/ +COPY app_with_traefik/ app_with_traefik/ RUN rm -rf /root/.ssh RUN ln -s /shared/ssh /root/.ssh @@ -28,6 +29,7 @@ RUN git config --global user.email "deployer@example.com" RUN git config --global user.name "Deployer" RUN cd app && git init && git add . && git commit -am "Initial version" RUN cd app_with_roles && git init && git add . && git commit -am "Initial version" +RUN cd app_with_traefik && git init && git add . && git commit -am "Initial version" HEALTHCHECK --interval=1s CMD pgrep sleep diff --git a/test/integration/docker/deployer/app_with_traefik/.kamal/hooks/pre-deploy b/test/integration/docker/deployer/app_with_traefik/.kamal/hooks/pre-deploy new file mode 100755 index 000000000..d0483a431 --- /dev/null +++ b/test/integration/docker/deployer/app_with_traefik/.kamal/hooks/pre-deploy @@ -0,0 +1,3 @@ +kamal proxy boot_config set --publish false \ + --docker_options label=traefik.http.services.kamal_proxy.loadbalancer.server.scheme=http \ + label=traefik.http.routers.kamal_proxy.rule=PathPrefix\(\`/\`\) diff --git a/test/integration/docker/deployer/app_with_traefik/.kamal/secrets b/test/integration/docker/deployer/app_with_traefik/.kamal/secrets new file mode 100644 index 000000000..cb2988d6b --- /dev/null +++ b/test/integration/docker/deployer/app_with_traefik/.kamal/secrets @@ -0,0 +1 @@ +SECRET_TOKEN='1234 with "中文"' diff --git a/test/integration/docker/deployer/app_with_traefik/Dockerfile b/test/integration/docker/deployer/app_with_traefik/Dockerfile new file mode 100644 index 000000000..0e6237df4 --- /dev/null +++ b/test/integration/docker/deployer/app_with_traefik/Dockerfile @@ -0,0 +1,9 @@ +FROM registry:4443/nginx:1-alpine-slim + +COPY default.conf /etc/nginx/conf.d/default.conf + +ARG COMMIT_SHA +RUN echo $COMMIT_SHA > /usr/share/nginx/html/version +RUN mkdir -p /usr/share/nginx/html/versions && echo "version" > /usr/share/nginx/html/versions/$COMMIT_SHA +RUN mkdir -p /usr/share/nginx/html/versions && echo "hidden" > /usr/share/nginx/html/versions/.hidden +RUN echo "Up!" > /usr/share/nginx/html/up diff --git a/test/integration/docker/deployer/app_with_traefik/config/deploy.yml b/test/integration/docker/deployer/app_with_traefik/config/deploy.yml new file mode 100644 index 000000000..e48ebc1f8 --- /dev/null +++ b/test/integration/docker/deployer/app_with_traefik/config/deploy.yml @@ -0,0 +1,29 @@ +service: app_with_traefik +image: app_with_traefik +servers: + - vm1 + - vm2 +deploy_timeout: 2 +drain_timeout: 2 +readiness_delay: 0 + +registry: + server: registry:4443 + username: root + password: root +builder: + driver: docker + arch: <%= Kamal::Utils.docker_arch %> + args: + COMMIT_SHA: <%= `git rev-parse HEAD` %> +accessories: + traefik: + service: traefik + image: traefik:v2.10 + port: 80 + cmd: "--providers.docker" + options: + volume: + - "/var/run/docker.sock:/var/run/docker.sock" + roles: + - web diff --git a/test/integration/docker/deployer/app_with_traefik/default.conf b/test/integration/docker/deployer/app_with_traefik/default.conf new file mode 100644 index 000000000..e37a9bc1f --- /dev/null +++ b/test/integration/docker/deployer/app_with_traefik/default.conf @@ -0,0 +1,17 @@ +server { + listen 80; + listen [::]:80; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} diff --git a/test/integration/integration_test.rb b/test/integration/integration_test.rb index ad99f3e22..b6943ced2 100644 --- a/test/integration/integration_test.rb +++ b/test/integration/integration_test.rb @@ -169,10 +169,8 @@ def app_host(app = @app) case app when "app" "127.0.0.1" - when "app_with_roles" - "localhost" else - raise "Unknown app: #{app}" + "localhost" end end end diff --git a/test/integration/main_test.rb b/test/integration/main_test.rb index e3aa1ef37..ce32e6404 100644 --- a/test/integration/main_test.rb +++ b/test/integration/main_test.rb @@ -88,6 +88,14 @@ class MainTest < IntegrationTest end test "setup and remove" do + @app = "app_with_roles" + + kamal :proxy, :set_config, + "--publish=false", + "--options=label=traefik.http.services.kamal_proxy.loadbalancer.server.scheme=http", + "label=traefik.http.routers.kamal_proxy.rule=PathPrefix\\\(\\\`/\\\`\\\)", + "label=traefik.http.routers.kamal_proxy.priority=2" + # Check remove completes when nothing has been setup yet kamal :remove, "-y" assert_no_images_or_containers @@ -123,6 +131,15 @@ class MainTest < IntegrationTest assert_proxy_not_running end + test "deploy with traefik" do + @app = "app_with_traefik" + + first_version = latest_app_version + + kamal :setup + assert_app_is_up version: first_version + end + private def assert_envs(version:) assert_env :CLEAR_TOKEN, "4321", version: version, vm: :vm1 diff --git a/test/test_helper.rb b/test/test_helper.rb index f8f4f4e48..1749ee321 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -13,6 +13,13 @@ # Applies to remote commands only. SSHKit.config.backend = SSHKit::Backend::Printer +class SSHKit::Backend::Printer + def upload!(local, location, **kwargs) + local = local.string.inspect if local.respond_to?(:string) + puts "Uploading #{local} to #{location} on #{host}" + end +end + # Ensure local commands use the printer backend too. # See https://github.com/capistrano/sshkit/blob/master/lib/sshkit/dsl.rb#L9 module SSHKit