diff --git a/docs/networking/proxies/traefik.md b/docs/networking/proxies/traefik.md index 486c0b299..9a793870f 100644 --- a/docs/networking/proxies/traefik.md +++ b/docs/networking/proxies/traefik.md @@ -112,7 +112,17 @@ Traefik log output is set to `ERROR` by default. It may be changed by setting th dokku traefik:set --global log-level DEBUG ``` -After modifying, the Traefik container will need to be restarted. +After modifying, the Traefik container will need to be restarted. + +### Setting rule priority + +By default, app deployments will result in the newer traefik rules using a higher priority in order to have any newer rules respected by Traefik. Rule priorities will always increase according to the current unix timestamp. The priority may be fixed by setting the app-level `priority` property: + +```shell +dokku traefik:set node-js-app priority 12345 +``` + +After modifying, the app container will need to be recreated via a `ps:rebuild` or an app deployment. ### SSL Configuration diff --git a/plugins/traefik-vhosts/command-functions b/plugins/traefik-vhosts/command-functions index 1df4b90c8..af59aaaef 100755 --- a/plugins/traefik-vhosts/command-functions +++ b/plugins/traefik-vhosts/command-functions @@ -44,6 +44,7 @@ cmd-traefik-report-single() { "--traefik-letsencrypt-email: $(fn-traefik-letsencrypt-email)" "--traefik-letsencrypt-server: $(fn-traefik-letsencrypt-server)" "--traefik-log-level: $(fn-traefik-log-level)" + "--traefik-priority: $(fn-traefik-priority "$APP")" ) if [[ -z "$INFO_FLAG" ]]; then diff --git a/plugins/traefik-vhosts/docker-args-process-deploy b/plugins/traefik-vhosts/docker-args-process-deploy index d69c706d5..a681b8d4f 100755 --- a/plugins/traefik-vhosts/docker-args-process-deploy +++ b/plugins/traefik-vhosts/docker-args-process-deploy @@ -1,5 +1,6 @@ #!/usr/bin/env bash source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/traefik-vhosts/internal-functions" set -eo pipefail [[ $DOKKU_TRACE ]] && set -x @@ -81,7 +82,10 @@ trigger-traefik-vhosts-docker-args-process-deploy() { traefik_domains="${traefik_domains// /\\\`,\\\`}" fi - priority="$(date +%s)" + priority="$(fn-traefik-priority "$APP")" + if [[ -z "$priority" ]]; then + priority="$(date +%s)" + fi output="--label traefik.enable=true" if [[ -n "$proxy_container_http_port" ]] || [[ -n "$proxy_container_http_port_candidate" ]]; then diff --git a/plugins/traefik-vhosts/internal-functions b/plugins/traefik-vhosts/internal-functions index 9429504b1..9bc89ee1a 100755 --- a/plugins/traefik-vhosts/internal-functions +++ b/plugins/traefik-vhosts/internal-functions @@ -92,3 +92,8 @@ fn-traefik-log-level() { log_level="$(fn-plugin-property-get-default "traefik" "--global" "log-level" "ERROR")" echo "${log_level^^}" } + +fn-traefik-priority() { + declare APP="$1" + fn-plugin-property-get-default "traefik" "$APP" "priority" "" +} diff --git a/plugins/traefik-vhosts/post-delete b/plugins/traefik-vhosts/post-delete new file mode 100755 index 000000000..a3cd1e77a --- /dev/null +++ b/plugins/traefik-vhosts/post-delete @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-traefik-vhosts-post-delete() { + declare desc="traefik-vhosts post-delete trigger" + declare trigger="post-delete" + declare APP="$1" + + fn-plugin-property-destroy "traefik" "$APP" +} + +trigger-traefik-vhosts-post-delete "$@" diff --git a/plugins/traefik-vhosts/subcommands/set b/plugins/traefik-vhosts/subcommands/set index 2adfbd2a0..0c51777b2 100755 --- a/plugins/traefik-vhosts/subcommands/set +++ b/plugins/traefik-vhosts/subcommands/set @@ -9,13 +9,13 @@ cmd-traefik-set() { declare cmd="traefik:set" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" KEY="$2" VALUE="$3" - local VALID_KEYS=("api-enabled" "api-vhost" "dashboard-enabled" "basic-auth-username" "basic-auth-password" "image" "letsencrypt-email" "log-level") - local GLOBAL_KEYS=("api-enabled" "api-vhost" "dashboard"-enabled "basic-auth-username" "basic-auth-password" "image" "letsencrypt-email" "log-level") + local VALID_KEYS=("api-enabled" "api-vhost" "dashboard-enabled" "basic-auth-username" "basic-auth-password" "image" "letsencrypt-email" "letsencrypt-server" "log-level" "priority") + local GLOBAL_KEYS=("api-enabled" "api-vhost" "dashboard"-enabled "basic-auth-username" "basic-auth-password" "image" "letsencrypt-email" "letsencrypt-server" "log-level") [[ -z "$KEY" ]] && dokku_log_fail "No key specified" if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then - dokku_log_fail "Invalid key specified, valid keys include: api-enabled api-vhost dashboard-enabled basic-auth-username basic-auth-password image letsencrypt-email log-level" + dokku_log_fail "Invalid key specified, valid keys include: api-enabled api-vhost dashboard-enabled basic-auth-username basic-auth-password image letsencrypt-email letsencrypt-server log-level priority" fi if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then diff --git a/tests/unit/traefik.bats b/tests/unit/traefik.bats index a37624afb..2ac9d82ca 100644 --- a/tests/unit/traefik.bats +++ b/tests/unit/traefik.bats @@ -81,3 +81,25 @@ teardown() { assert_success assert_output "python/http.server" } + +@test "(traefik) traefik:set priority" { + run /bin/bash -c "dokku proxy:set $TEST_APP traefik" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku traefik:set $TEST_APP priority 12345" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-http-12345.loadbalancer.server.port\" }}'" + echo "output: $output" + echo "status: $status" + assert_output "5000" +}