diff --git a/docs/appendices/0.31.0-migration-guide.md b/docs/appendices/0.31.0-migration-guide.md index b4ff4a82401..f873a9da17b 100644 --- a/docs/appendices/0.31.0-migration-guide.md +++ b/docs/appendices/0.31.0-migration-guide.md @@ -6,6 +6,7 @@ - The `vector` container integration now mounts config to `/etc/vector` instead of the path `/etc/vector/vector.json`, allowing users the ability to provide extra configuration for Vector Sinks. To take advantage of the new functionality, the vector container should be stopped (via `dokku logs:vector-stop`) and then started (via `dokku logs:vector-start`). - The `traefik` integration now mounts config to `/data` instead of the path `/acme.json`, fixing permissions issues under certain architectures. To take advantage of the new functionality, the traefik container should be stopped (via `dokku traefik:stop`) and then started (via `dokku traefik:start`). - Users no longer need to clear the `source-image` git property when transitioning from image-based deploys (`git:from-image` and `git:load-image`) to other deployment methods (git push, `git:from-archive`, `git:sync`). +- For deploys via the `git:from-image` and `git:load-image` commands, the `CHECKS` file is now extracted from the configured `WORKDIR` property of the image. For all other deploys - git push, `git:from-archive`, `git:sync` - will have the `CHECKS` extracted directly from the source code. The filename in both cases is `CHECKS` and cannot be modified. ## Deprecations diff --git a/docs/deployment/zero-downtime-deploys.md b/docs/deployment/zero-downtime-deploys.md index c4e43779727..1d6bc3f8874 100644 --- a/docs/deployment/zero-downtime-deploys.md +++ b/docs/deployment/zero-downtime-deploys.md @@ -139,15 +139,13 @@ If your application needs a longer period to boot up - perhaps to load data into Checks are run against the detected `web` process from your application's `Procfile`. For non-web processes, Dokku will fallback to the aforementioned process uptime check. -To specify checks, add a `CHECKS` file to the root of your project directory. The `CHECKS` file should be plain text and may contain: +For deploys via the `git:from-image` and `git:load-image` commands, the `CHECKS` file is extracted from the configured `WORKDIR` property of the image. For all other deploys - git push, `git:from-archive`, `git:sync` - will have the `CHECKS` extracted directly from the source code. The filename in both cases is `CHECKS` and cannot be modified. The `CHECKS` file should be plain text and may contain: - check instructions - settings (NAME=VALUE) - comments (lines starting with #) - empty lines -> For Dockerfile and Docker Image based deploys, the file *must* be in the `WORKDIR` directory of the built image. `/app` is used by default as the root container directory for buildpack-based deploys. - ### Check instructions The format of a check instruction is a path or relative URL, optionally followed by the expected content: diff --git a/plugins/scheduler-docker-local/check-deploy b/plugins/scheduler-docker-local/check-deploy index 363b0c16883..678ae2677a5 100755 --- a/plugins/scheduler-docker-local/check-deploy +++ b/plugins/scheduler-docker-local/check-deploy @@ -38,6 +38,7 @@ set -eo pipefail source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/checks/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/internal-functions" trigger-scheduler-docker-local-check-deploy() { declare desc="scheduler-docker-local check-deploy plugin trigger" @@ -76,16 +77,14 @@ trigger-scheduler-docker-local-check-deploy() { # use this number of retries for checks local ATTEMPTS="${DOKKU_CHECKS_ATTEMPTS:-5}" - local CHECK_DEPLOY_TMP_WORK_DIR=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") - local CHECKS_FILENAME=${CHECK_DEPLOY_TMP_WORK_DIR}/CHECKS + local CHECKS_FILENAME="$(fn-scheduler-docker-local-get-process-specific-checks-file-path "$APP")" local IMAGE_TAG="$(get_running_image_tag "$APP")" local IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG") - copy_from_image "$IMAGE" "CHECKS" "$CHECKS_FILENAME" 2>/dev/null || true checks_check_deploy_cleanup() { - declare desc="cleans up CHECK_DEPLOY_TMP_WORK_DIR and print container output" + declare desc="print container output" local id="$1" - rm -rf "$CHECK_DEPLOY_TMP_WORK_DIR" &>/dev/null || true + if [[ $id ]]; then dokku_log_info2_quiet "Start of $APP container output ($DOKKU_APP_CONTAINER_TYPE.$CONTAINER_INDEX)" dokku_container_log_verbose_quiet "$id" @@ -96,8 +95,6 @@ trigger-scheduler-docker-local-check-deploy() { # We allow custom check for web instances only if [[ ! -s "${CHECKS_FILENAME}" ]] || [[ "$DOKKU_APP_CONTAINER_TYPE" != "web" ]]; then - rm -rf "$CHECK_DEPLOY_TMP_WORK_DIR" &>/dev/null || true - # simple default check to see if the container stuck around local DOKKU_DEFAULT_CHECKS_WAIT="${DOKKU_DEFAULT_CHECKS_WAIT:-10}" dokku_log_verbose "Waiting for $DOKKU_DEFAULT_CHECKS_WAIT seconds ($DOKKU_APP_CONTAINER_TYPE.$CONTAINER_INDEX)" @@ -115,15 +112,6 @@ trigger-scheduler-docker-local-check-deploy() { dokku_log_verbose "Default container check successful ($DOKKU_APP_CONTAINER_TYPE.$CONTAINER_INDEX)" && exit 0 fi - local NEW_CHECKS_FILENAME="${CHECK_DEPLOY_TMP_WORK_DIR}/NEW_CHECKS" - template_checks() { - eval "$(config_export app "$APP" --merged)" - sigil -f "$CHECKS_FILENAME" | cat -s >"$NEW_CHECKS_FILENAME" - } - - template_checks - CHECKS_FILENAME="$NEW_CHECKS_FILENAME" - # Reads name/value pairs, sets the WAIT and TIMEOUT variables exec <"$CHECKS_FILENAME" local line diff --git a/plugins/scheduler-docker-local/core-post-deploy b/plugins/scheduler-docker-local/core-post-deploy index bd02b2d4421..592bd0af105 100755 --- a/plugins/scheduler-docker-local/core-post-deploy +++ b/plugins/scheduler-docker-local/core-post-deploy @@ -15,6 +15,18 @@ trigger-scheduler-docker-local-core-post-deploy() { return fi + # move over the checks file appropriately + checks_file="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS" + process_specific_checks_file="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS.$DOKKU_PID" + if [[ -f "$process_specific_checks_file" ]]; then + mv "$process_specific_checks_file" "$checks_file" + elif [[ -f "$process_specific_checks_file.missing" ]]; then + rm -f "$process_specific_checks_file.missing" + if [[ -f "$checks_file" ]]; then + rm -f "$checks_file" + fi + fi + dokku_log_info1 "Renaming containers" local PROCTYPES="$(plugn trigger ps-current-scale "$APP" | awk -F '=' '{ print $1 }' | xargs)" local CONTAINER_FILES="$(find "$DOKKU_ROOT/$APP" -maxdepth 1 -name "CONTAINER.*" -printf "%f\n" 2>/dev/null | sort -t . -k 3 -n | xargs)" diff --git a/plugins/scheduler-docker-local/core-post-extract b/plugins/scheduler-docker-local/core-post-extract new file mode 100755 index 00000000000..f8809136f83 --- /dev/null +++ b/plugins/scheduler-docker-local/core-post-extract @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/internal-functions" + +fn-scheduler-docker-local-copy-from-image() { + declare APP="$1" IMAGE_NAME="$2" CHECKS_PATH="$3" + + mkdir -p "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP" + rm -f "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS."* + copy_from_image "$IMAGE_NAME" "$CHECKS_PATH" "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS.$DOKKU_PID" 2>/dev/null || true + if [[ ! -f "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS.$DOKKU_PID" ]]; then + touch "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS.$DOKKU_PID.missing" + fi +} + +fn-scheduler-docker-local-copy-from-directory() { + declare APP="$1" SOURCECODE_WORK_DIR="$2" CHECKS_PATH="$3" + + pushd "$SOURCECODE_WORK_DIR" >/dev/null + mkdir -p "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP" + + if [[ -z "$CHECKS_PATH" ]]; then + touch "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS.$DOKKU_PID.missing" + return + fi + + if [[ ! -f "$CHECKS_PATH" ]]; then + touch "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS.$DOKKU_PID.missing" + return + fi + + rm -f "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS."* + cp -f "$CHECKS_PATH" "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS.$DOKKU_PID" + popd &>/dev/null || pushd "/tmp" >/dev/null +} + +trigger-scheduler-docker-local-core-post-extract() { + declare desc="scheduler-docker-local post-extract plugin trigger" + declare trigger="post-extract" + declare APP="$1" SOURCECODE_WORK_DIR="$2" + local CHECKS_PATH="CHECKS" CHECKS_FILENAME="${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS.$DOKKU_PID" + local app_source_image + + app_source_image="$(plugn trigger git-get-property "$APP" "source-image")" + if [[ -n "$app_source_image" ]]; then + fn-scheduler-docker-local-copy-from-image "$APP" "$app_source_image" "$CHECKS_PATH" + else + fn-scheduler-docker-local-copy-from-directory "$APP" "$SOURCECODE_WORK_DIR" "$CHECKS_PATH" + fi + + if [[ -f "$CHECKS_FILENAME" ]]; then + local TMP_CHECKS_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") + trap "rm -rf '$TMP_CHECKS_FILE' >/dev/null" RETURN INT TERM EXIT + + template_checks() { + declare desc="templates out the checks file" + declare APP="$1" CHECKS_FILENAME="$2" + eval "$(config_export app "$APP" --format exports --merged)" + sigil -f "$CHECKS_FILENAME" | cat -s >"$TMP_CHECKS_FILE" + mv "$TMP_CHECKS_FILE" "$CHECKS_FILENAME" + } + + template_checks "$APP" "$CHECKS_FILENAME" + fi +} + +trigger-scheduler-docker-local-core-post-extract "$@" diff --git a/plugins/scheduler-docker-local/internal-functions b/plugins/scheduler-docker-local/internal-functions index a8985eef21e..33f16100e9b 100755 --- a/plugins/scheduler-docker-local/internal-functions +++ b/plugins/scheduler-docker-local/internal-functions @@ -67,6 +67,44 @@ cmd-scheduler-docker-local-report-single() { fi } +fn-scheduler-docker-local-get-checks-file-path() { + declare APP="$1" + + echo "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/CHECKS" +} + +fn-scheduler-docker-local-get-process-specific-checks-file-path() { + declare APP="$1" + + checks_path="$(fn-scheduler-docker-local-get-checks-file-path "$APP")" + process_specific_checks_path="$checks_path.$DOKKU_PID" + if [[ -f "$process_specific_checks_path" ]]; then + echo "$process_specific_checks_path" + return + fi + + echo "$checks_path" +} + +fn-scheduler-docker-local-has-checks-file() { + declare APP="$1" + + checks_path="$(fn-scheduler-docker-local-get-checks-file-path "$APP")" + if [[ -f "$checks_path.$DOKKU_PID.missing" ]]; then + return 1 + fi + + if [[ -f "$checks_path.$DOKKU_PID" ]]; then + return 0 + fi + + if [[ -f "$checks_path" ]]; then + return 0 + fi + + return 1 +} + fn-scheduler-docker-local-retire-container() { declare APP="$1" CID="$2" local STATE diff --git a/plugins/scheduler-docker-local/pre-deploy b/plugins/scheduler-docker-local/pre-deploy index b6d1bb1973b..217ce6630e3 100755 --- a/plugins/scheduler-docker-local/pre-deploy +++ b/plugins/scheduler-docker-local/pre-deploy @@ -4,6 +4,7 @@ set -eo pipefail source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/internal-functions" trigger-scheduler-docker-local-pre-deploy() { declare desc="scheduler-docker-local pre-deploy plugin trigger" @@ -16,7 +17,7 @@ trigger-scheduler-docker-local-pre-deploy() { fi scheduler-docker-local-pre-deploy-chown-app "$APP" "$IMAGE_TAG" - scheduler-docker-local-pre-deploy-precheck "$APP" "$IMAGE_TAG" + scheduler-docker-local-pre-deploy-precheck "$APP" } scheduler-docker-local-pre-deploy-chown-app() { @@ -63,14 +64,10 @@ scheduler-docker-local-pre-deploy-chown-app() { scheduler-docker-local-pre-deploy-precheck() { declare desc="Outputs the checks messages if necessary" - declare APP="$1" IMAGE_TAG="$2" - local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") - local CHECKS_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") - trap "rm -rf '$CHECKS_FILE' >/dev/null" RETURN INT TERM EXIT - copy_from_image "$IMAGE" "CHECKS" "$CHECKS_FILE" 2>/dev/null || true + declare APP="$1" dokku_log_info2 "Processing deployment checks" - if [[ ! -s "${CHECKS_FILE}" ]]; then + if ! fn-scheduler-docker-local-has-checks-file "$APP"; then local CHECKS_URL="${DOKKU_CHECKS_URL:-https://dokku.com/docs/deployment/zero-downtime-deploys/}" dokku_log_verbose "No CHECKS file found. Simple container checks will be performed." dokku_log_verbose "For more efficient zero downtime deployments, create a CHECKS file. See ${CHECKS_URL} for examples"