When scaling a process type to a smaller count, the indices above the new count had their `CONTAINER.<proctype>.<idx>` state files deleted but the underlying Docker containers were never registered for retirement, so they remained running indefinitely. The cleanup block now reads each orphaned state file and registers its container id with the existing `scheduler-register-retired` trigger before the file is removed.
110 lines
4.8 KiB
Bash
Executable File
110 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -eo pipefail
|
|
[[ $DOKKU_TRACE ]] && set -x
|
|
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
|
source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
|
|
source "$PLUGIN_AVAILABLE_PATH/checks/functions"
|
|
|
|
fn-scheduler-deploy-process() {
|
|
declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE="$3" IMAGE_TAG="$4" PROC_TYPE="$5" PROC_COUNT="$6"
|
|
local CONTAINER_INDEX=1
|
|
local image_vendor
|
|
|
|
dokku_log_info1 "Deploying $PROC_TYPE (count=$PROC_COUNT)"
|
|
DOKKU_CHECKS_DISABLED="$(is_app_proctype_checks_disabled "$APP" "$PROC_TYPE")"
|
|
if [[ "$DOKKU_CHECKS_DISABLED" == "true" ]]; then
|
|
dokku_log_verbose "Zero downtime is disabled, stopping currently running containers ($PROC_TYPE)"
|
|
local cid proctype_oldids="$(get_app_running_container_ids "$APP" "$PROC_TYPE" 2>/dev/null)"
|
|
for cid in $proctype_oldids; do
|
|
dokku_log_verbose "Stopping $cid ($PROC_TYPE)"
|
|
|
|
# Retire the containers to ensure they get removed
|
|
plugn trigger scheduler-register-retired "$APP" "$cid" "$DOKKU_WAIT_TO_RETIRE"
|
|
|
|
# Disable the container restart policy
|
|
"$DOCKER_BIN" container update --restart=no "$cid" &>/dev/null || true
|
|
|
|
"$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$cid" &>/dev/null
|
|
done
|
|
fi
|
|
|
|
local PROCESS_TMP_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
|
|
trap "rm -rf '$PROCESS_TMP_FILE' >/dev/null" RETURN INT TERM EXIT
|
|
|
|
while [[ $CONTAINER_INDEX -le $PROC_COUNT ]]; do
|
|
echo "$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/bin/scheduler-deploy-process-container $APP $IMAGE_SOURCE_TYPE $IMAGE $IMAGE_TAG $PROC_TYPE $PROC_COUNT $CONTAINER_INDEX" >>"$PROCESS_TMP_FILE"
|
|
CONTAINER_INDEX=$((CONTAINER_INDEX + 1))
|
|
done
|
|
|
|
INJECT_INIT_FLAG="$(fn-plugin-property-get "scheduler-docker-local" "$APP" "init-process" "")"
|
|
if [[ -z "$INJECT_INIT_FLAG" ]]; then
|
|
# special-case linuxserver.io images as those always use an s6-overlay
|
|
image_vendor="$("$DOCKER_BIN" image inspect --format '{{ index .Config.Labels "org.opencontainers.image.vendor" }}' "$IMAGE")"
|
|
if [[ "$image_vendor" == "linuxserver.io" ]]; then
|
|
INJECT_INIT_FLAG="false"
|
|
else
|
|
INJECT_INIT_FLAG="true"
|
|
fi
|
|
fi
|
|
|
|
local DOCKER_ARGS
|
|
DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG" "$PROC_TYPE")
|
|
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-deploy "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG" "$PROC_TYPE")
|
|
DOCKER_ARGS=" $DOCKER_ARGS "
|
|
declare -a ARG_ARRAY
|
|
eval "ARG_ARRAY=($DOCKER_ARGS)"
|
|
|
|
local port_published=false
|
|
for arg in "${ARG_ARRAY[@]}"; do
|
|
if [[ "$arg" == "-p "* ]] || [[ "$arg" =~ "--publish "* ]] || [[ "$arg" == "-P" ]] || [[ "$arg" =~ "--publish-all"* ]]; then
|
|
port_published=true
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ "$port_published" == "true" ]]; then
|
|
local warned_on_publish=false
|
|
if [[ "$PROC_COUNT" -gt 1 ]]; then
|
|
warned_on_publish=true
|
|
dokku_log_warn "Deploys may fail when publishing ports and scaling to multiple containers. Consider scaling process type $PROC_TYPE to 1."
|
|
fi
|
|
if [[ "$DOKKU_CHECKS_DISABLED" != "true" ]] && [[ "$warned_on_publish" == "false" ]]; then
|
|
warned_on_publish=true
|
|
dokku_log_warn "Deploys may fail when publishing ports and enabling zero downtime. Consider disabling zero downtime for process type $PROC_TYPE."
|
|
fi
|
|
fi
|
|
|
|
PARALLEL_DEPLOY_COUNT="$(plugn trigger "app-json-process-deploy-parallelism" "$APP" "$PROC_TYPE")"
|
|
DOKKU_CHECKS_DISABLED="$DOKKU_CHECKS_DISABLED" INJECT_INIT_FLAG="$INJECT_INIT_FLAG" parallel --will-cite --halt soon,fail=1 --jobs "$PARALLEL_DEPLOY_COUNT" --ungroup <"$PROCESS_TMP_FILE"
|
|
|
|
plugn trigger scheduler-post-deploy-process "$APP" "$PROC_TYPE"
|
|
|
|
# cleanup when we scale down
|
|
if [[ "$PROC_COUNT" == 0 ]]; then
|
|
local CONTAINER_IDX_OFFSET=0
|
|
else
|
|
local CONTAINER_IDX_OFFSET=$((PROC_COUNT + 1))
|
|
fi
|
|
local container_state_filetype orphaned_container_file orphaned_cid
|
|
pushd "$DOKKU_ROOT/$APP" >/dev/null
|
|
for orphaned_container_file in $(find . -maxdepth 1 -name "CONTAINER.$PROC_TYPE.*" -printf "%f\n" | sort -t . -k 3 -n | tail -n +$CONTAINER_IDX_OFFSET); do
|
|
[[ -s "$orphaned_container_file" ]] || continue
|
|
orphaned_cid="$(<"$orphaned_container_file")"
|
|
[[ -z "$orphaned_cid" ]] && continue
|
|
dokku_log_verbose "Scheduling orphaned container shutdown in $DOKKU_WAIT_TO_RETIRE seconds (${orphaned_container_file#CONTAINER.})"
|
|
plugn trigger scheduler-register-retired "$APP" "$orphaned_cid" "$DOKKU_WAIT_TO_RETIRE"
|
|
done
|
|
for container_state_filetype in CONTAINER IP PORT; do
|
|
find . -maxdepth 1 -name "$container_state_filetype.$PROC_TYPE.*" -printf "%f\n" | sort -t . -k 3 -n | tail -n +$CONTAINER_IDX_OFFSET | xargs rm -f
|
|
done
|
|
popd &>/dev/null || pushd "/tmp" >/dev/null
|
|
}
|
|
|
|
main() {
|
|
declare desc="wrapper function to ensure tmp files are properly annotated"
|
|
|
|
fn-scheduler-deploy-process "$@"
|
|
}
|
|
|
|
main "$@"
|