Files
dokku/plugins/scheduler-docker-local/bin/scheduler-deploy-process
Jose Diaz-Gonzalez 4927ca092d fix: retire orphaned containers when scaling down
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.
2026-04-27 03:23:15 -04:00

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 "$@"