diff --git a/docs/deployment/zero-downtime-deploys.md b/docs/deployment/zero-downtime-deploys.md index b97c7b269..3adf99755 100644 --- a/docs/deployment/zero-downtime-deploys.md +++ b/docs/deployment/zero-downtime-deploys.md @@ -3,10 +3,11 @@ > New as of 0.5.0 ``` -checks # Show zero-downtime status -checks:disable [process-type(s)] # Disable zero-downtime deployment for all processes (or comma-separated process-type list) ***WARNING: this will cause downtime during deployments*** -checks:enable [process-type(s)] # Enable zero-downtime deployment for all processes (or comma-separated process-type list) -checks:skip [process-type(s)] # Skip zero-downtime checks for all processes (or comma-separated process-type list) +checks Show zero-downtime status +checks:disable [process-type(s)] Disable zero-downtime deployment for all processes (or comma-separated process-type list) ***WARNING: this will cause downtime during deployments*** +checks:enable [process-type(s)] Enable zero-downtime deployment for all processes (or comma-separated process-type list) +checks:run [process-type(s)] Runs zero-downtime checks for all processes (or comma-separated process-type list) +checks:skip [process-type(s)] Skip zero-downtime checks for all processes (or comma-separated process-type list) ``` Following a deploy, dokku will wait `10` seconds before routing traffic to the new container to give your application time to boot up. If the application is not running after this time, then the deploy is failed and your old container will continue serving traffic. You can modify this value globally or on a per-application basis: @@ -56,6 +57,62 @@ dokku config:set DOKKU_WAIT_TO_RETIRE=120 > Note that during this time, multiple containers may be running on your server, which can be an issue for memory-hungry applications on memory-constrained servers. +Checks can also be manually invoked via the `checks:run` command. This can be used to check the status of an application via cron to provide integration with external healthchecking software. + +``` +# checks are run against a specific application +$ dokku checks:run APP +-----> Running pre-flight checks +-----> Running checks for app (APP.web.1) + For more efficient zero downtime deployments, create a file CHECKS. + See http://dokku.viewdocs.io/dokku/checks-examples.md for examples + CHECKS file not found in container: Running simple container check... +-----> Waiting for 10 seconds ... +-----> Default container check successful! +-----> Running checks for app (APP.web.2) + For more efficient zero downtime deployments, create a file CHECKS. + See http://dokku.viewdocs.io/dokku/checks-examples.md for examples + CHECKS file not found in container: Running simple container check... +-----> Waiting for 10 seconds ... +-----> Default container check successful! +-----> Running checks for app (APP.worker.1) + For more efficient zero downtime deployments, create a file CHECKS. + See http://dokku.viewdocs.io/dokku/checks-examples.md for examples + CHECKS file not found in container: Running simple container check... +-----> Waiting for 10 seconds ... +-----> Default container check successful! + +# checks can be scoped to a particular process type +$ dokku checks:run APP worker +-----> Running pre-flight checks +-----> Running checks for app (APP.worker.1) + For more efficient zero downtime deployments, create a file CHECKS. + See http://dokku.viewdocs.io/dokku/checks-examples.md for examples + CHECKS file not found in container: Running simple container check... +-----> Waiting for 10 seconds ... +-----> Default container check successful! + +# a container id may also be specified +$ dokku checks:run APP web.2 +-----> Running pre-flight checks +-----> Running checks for app (APP.web.2) + For more efficient zero downtime deployments, create a file CHECKS. + See http://dokku.viewdocs.io/dokku/checks-examples.md for examples + CHECKS file not found in container: Running simple container check... +-----> Waiting for 10 seconds ... +-----> Default container check successful! + +# non-existent process types will result in an error +$ dokku checks:run APP non-existent +-----> Running pre-flight checks +Invalid process type specified (APP.non-existent) + +# non-existent container ids will *also* result in an error +$ dokku checks:run APP web.3 +-----> Running pre-flight checks +Invalid container id specified (APP.web.3) +``` + ## Checks If your application needs a longer period to boot up - perhaps to load data into memory, or because of slow boot time - you may also use dokku's `checks` functionality to more precisely check whether an application can serve traffic or not. diff --git a/plugins/checks/check-deploy b/plugins/checks/check-deploy index f2b0a46c3..861c8005c 100755 --- a/plugins/checks/check-deploy +++ b/plugins/checks/check-deploy @@ -53,7 +53,6 @@ checks_check_deploy() { local DOKKU_APP_CONTAINER_ID=${DOKKU_APP_CIDS[0]} fi - # source global and in-app envs to get DOKKU_CHECKS_WAIT and any other necessary vars eval "$(config_export global)" eval "$(config_export app "$APP")" diff --git a/plugins/checks/commands b/plugins/checks/commands index 7c85af9a8..2400b5ee0 100755 --- a/plugins/checks/commands +++ b/plugins/checks/commands @@ -10,6 +10,7 @@ case "$1" in checks , Show zero-downtime status checks:disable [process-type(s)], Disable zero-downtime deployment for all processes (or comma-separated process-type list) ***WARNING: this will cause downtime during deployments*** checks:enable [process-type(s)], Enable zero-downtime deployment for all processes (or comma-separated process-type list) + checks:run [process-type(s)], Runs zero-downtime checks for all processes (or comma-separated process-type list) checks:skip [process-type(s)], Skip zero-downtime checks for all processes (or comma-separated process-type list) help_content } diff --git a/plugins/checks/subcommands/run b/plugins/checks/subcommands/run new file mode 100755 index 000000000..9f9b9f2f9 --- /dev/null +++ b/plugins/checks/subcommands/run @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/checks/functions" + +check_all_processes() { + local APP="$1"; CHECK_PROC_TYPE="$2" + local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE" + local VALID_CHECK_PROC_TYPE=false + + local line; local PROC_TYPE; local PROC_COUNT + while read -r line || [[ -n "$line" ]]; do + [[ "$line" =~ ^#.* ]] && continue + line="$(strip_inline_comments "$line")" + local PROC_TYPE=${line%%=*} + local PROC_COUNT=${line#*=} + + if [[ -n "$CHECK_PROC_TYPE" ]] && [[ "$CHECK_PROC_TYPE" != "$PROC_TYPE" ]]; then + continue + fi + + VALID_CHECK_PROC_TYPE=true + if [[ "$(is_app_proctype_checks_disabled "$APP" "$PROC_TYPE")" == "true" ]]; then + dokku_log_info1 "Zero downtime is disabled for app ($APP.$PROC_TYPE). Skipping checks" + continue + fi + + check_process_type "$APP" "$PROC_TYPE" "$PROC_COUNT" + done < "$DOKKU_SCALE_FILE" + + if [[ "$VALID_CHECK_PROC_TYPE" == "false" ]]; then + dokku_log_fail "Invalid process type specified ($APP.$CHECK_PROC_TYPE)" + fi +} + +check_process_type() { + local APP="$1" PROC_TYPE="$2" PROC_COUNT="$3" + local CONTAINER_INDEX=1 + + while [[ $CONTAINER_INDEX -le $PROC_COUNT ]]; do + check_process "$APP" "$PROC_TYPE" "$CONTAINER_INDEX" + local CONTAINER_INDEX=$(( CONTAINER_INDEX + 1 )) + done +} + +check_process() { + local APP="$1" PROC_TYPE="$2" CONTAINER_INDEX="$3" + local DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX" + local DOKKU_IP_FILE="$DOKKU_ROOT/$APP/IP.$PROC_TYPE.$CONTAINER_INDEX" + local DOKKU_PORT_FILE="$DOKKU_ROOT/$APP/PORT.$PROC_TYPE.$CONTAINER_INDEX" + + if [[ ! -f "$DOKKU_CONTAINER_ID_FILE" ]]; then + dokku_log_fail "Invalid container index specified ($APP.$PROC_TYPE.$CONTAINER_INDEX)" + fi + + dokku_log_info1 "Running checks for app ($APP.$PROC_TYPE.$CONTAINER_INDEX)" + local CONTAINER_ID=$(< "$DOKKU_CONTAINER_ID_FILE") + local IP=$(< "$DOKKU_IP_FILE") + local PORT=$(< "$DOKKU_PORT_FILE") + plugn trigger check-deploy "$APP" "$CONTAINER_ID" "$PROC_TYPE" "$PORT" "$IP" +} + +checks_run_cmd() { + declare desc="run zero-downtime checks for app/proctypes" + local cmd="checks:run" + [[ "$1" == "$cmd" ]] && shift 1 + local APP="$1"; verify_app_name "$APP" + local PROCTYPES="${2:-_all_}" + + dokku_log_info1 "Running pre-flight checks" + if [[ "$PROCTYPES" == "_all_" ]]; then + check_all_processes "$APP" + else + local PROC_TYPE OIFS="$IFS" IFS=, + for PROC_TYPE in $PROCTYPES; do + IFS="$OIFS" + + local CONTAINER_INDEX=$(echo "$PROC_TYPE" | cut -d'.' -f2 -s) + local PROC_TYPE=$(echo "$PROC_TYPE" | cut -d'.' -f1) + if [[ -n "$CONTAINER_INDEX" ]]; then + check_process "$APP" "$PROC_TYPE" "$CONTAINER_INDEX" + else + check_all_processes "$APP" "$PROC_TYPE" + fi + done + fi +} + +checks_run_cmd "$@" diff --git a/plugins/common/functions b/plugins/common/functions index 7018e1766..2952ee25d 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -618,7 +618,7 @@ dokku_deploy_cmd() { trap 'kill_new $id' INT TERM EXIT if [[ "$(is_app_proctype_checks_disabled "$APP" "$PROC_TYPE")" == "false" ]]; then dokku_log_info1 "Attempting pre-flight checks" - plugn trigger check-deploy "$APP" "$id" "$PROC_TYPE" "$port" "$ipaddr" + plugn trigger check-deploy "$APP" "$id" "$PROC_TYPE" "$port" "$ipaddr" fi trap - INT TERM EXIT diff --git a/tests/unit/10_checks.bats b/tests/unit/10_checks.bats index b5b8f90f8..8fb37cca5 100644 --- a/tests/unit/10_checks.bats +++ b/tests/unit/10_checks.bats @@ -173,6 +173,45 @@ teardown() { assert_output "web,notifications" } +@test "(checks) checks:run" { + run bash -c "dokku ps:scale $TEST_APP worker=1" + echo "output: "$output + echo "status: "$status + assert_success + + deploy_app + + run bash -c "dokku checks:run $TEST_APP" + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku checks:run $TEST_APP web" + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku checks:run $TEST_APP web,worker" + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku checks:run $TEST_APP worker.1" + echo "output: "$output + echo "status: "$status + assert_success + + run bash -c "dokku checks:run $TEST_APP web2" + echo "output: "$output + echo "status: "$status + assert_failure + + run bash -c "dokku checks:run $TEST_APP web.2" + echo "output: "$output + echo "status: "$status + assert_failure +} + @test "(checks) checks:disable -> app start with missing containers" { run bash -c "dokku ps:scale $TEST_APP worker=1" echo "output: "$output