When deploying, if the procfile-get-command fails for a given process, this causes an error to output to stderr. We instead silence this as the error isn't important.
227 lines
9.6 KiB
Bash
Executable File
227 lines
9.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -eo pipefail
|
|
[[ $DOKKU_TRACE ]] && set -x
|
|
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-scheduler-deploy() {
|
|
declare desc="deploys an image tag for a given application"
|
|
declare trigger="scheduler-deploy"
|
|
declare DOKKU_SCHEDULER="$1" APP="$2" IMAGE_TAG="$3"
|
|
|
|
if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then
|
|
return
|
|
fi
|
|
|
|
rm -f "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/failed-containers"
|
|
|
|
local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$APP --label=com.dokku.container-type=deploy"
|
|
local DOKKU_DOCKER_STOP_TIMEOUT DOKKU_HEROKUISH DOKKU_NETWORK_BIND_ALL IMAGE
|
|
DOKKU_HEROKUISH=false
|
|
DOKKU_CNB=false
|
|
IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
|
|
|
|
is_image_cnb_based "$IMAGE" && DOKKU_CNB=true
|
|
is_image_herokuish_based "$IMAGE" "$APP" && DOKKU_HEROKUISH=true
|
|
local IMAGE_SOURCE_TYPE="dockerfile"
|
|
[[ "$DOKKU_HEROKUISH" == "true" ]] && IMAGE_SOURCE_TYPE="herokuish"
|
|
[[ "$DOKKU_CNB" == "true" ]] && IMAGE_SOURCE_TYPE="pack"
|
|
local oldids=$(get_app_container_ids "$APP")
|
|
|
|
DOKKU_NETWORK_BIND_ALL="$(plugn trigger network-get-property "$APP" bind-all-interfaces)"
|
|
DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)"
|
|
[[ $DOKKU_DOCKER_STOP_TIMEOUT ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}"
|
|
|
|
DOKKU_START_CMD="$(config_get "$APP" DOKKU_START_CMD || true)"
|
|
|
|
if [[ -z "$DOKKU_WAIT_TO_RETIRE" ]]; then
|
|
local DOKKU_APP_DOKKU_WAIT_TO_RETIRE=$(config_get "$APP" DOKKU_WAIT_TO_RETIRE || true)
|
|
local DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE=$(config_get --global DOKKU_WAIT_TO_RETIRE || true)
|
|
local DOKKU_WAIT_TO_RETIRE=${DOKKU_APP_DOKKU_WAIT_TO_RETIRE:="$DOKKU_GLOBAL_DOKKU_WAIT_TO_RETIRE"}
|
|
fi
|
|
|
|
local WAIT="${DOKKU_WAIT_TO_RETIRE:-60}"
|
|
|
|
local line
|
|
local PROC_TYPE
|
|
local PROC_COUNT
|
|
local CONTAINER_INDEX
|
|
while read -r line || [[ -n "$line" ]]; do
|
|
PROC_TYPE=${line%%=*}
|
|
PROC_COUNT=${line#*=}
|
|
CONTAINER_INDEX=1
|
|
|
|
if [[ "$(is_app_proctype_checks_disabled "$APP" "$PROC_TYPE")" == "true" ]]; then
|
|
dokku_log_info1 "Zero downtime is disabled for app ($APP.$PROC_TYPE), Stopping currently running containers"
|
|
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 $APP.$PROC_TYPE ($cid)"
|
|
|
|
# Retire the containers to ensure they get removed
|
|
plugn trigger scheduler-register-retired "$APP" "$cid" "$WAIT"
|
|
|
|
# Disable the container restart policy
|
|
"$DOCKER_BIN" container update --restart=no "$cid" &>/dev/null || true
|
|
|
|
# shellcheck disable=SC2086
|
|
"$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$cid" &>/dev/null
|
|
# remove cid from oldids to skip the old container finish processing
|
|
oldids="$(remove_val_from_list "$cid" "$oldids" " ")"
|
|
done
|
|
fi
|
|
|
|
while [[ $CONTAINER_INDEX -le $PROC_COUNT ]]; do
|
|
local cid=""
|
|
local port=""
|
|
local ipaddr=""
|
|
local DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX"
|
|
local DYNO="$PROC_TYPE.$CONTAINER_INDEX"
|
|
|
|
# start the app
|
|
local DOCKER_ARGS
|
|
DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG" "$PROC_TYPE" "$CONTAINER_INDEX")
|
|
DOCKER_ARGS+=" --label=com.dokku.process-type=$PROC_TYPE --label=com.dokku.dyno=$DYNO "
|
|
DOCKER_ARGS+=" --env=DYNO=$DYNO "
|
|
DOCKER_ARGS+=" --name=$APP.$DYNO.upcoming-$RANDOM "
|
|
DOCKER_ARGS+=" --init "
|
|
DOCKER_ARGS+=" $DOCKER_RUN_LABEL_ARGS $DOKKU_GLOBAL_RUN_ARGS "
|
|
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-deploy "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG" "$PROC_TYPE" "$CONTAINER_INDEX")
|
|
[[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" --env=TRACE=true "
|
|
|
|
local START_CMD
|
|
[[ "$DOKKU_HEROKUISH" == "true" ]] && START_CMD="/start $PROC_TYPE"
|
|
[[ "$DOKKU_CNB" == "true" ]] && START_CMD=""
|
|
[[ -n "$DOKKU_START_CMD" ]] && START_CMD="$DOKKU_START_CMD"
|
|
|
|
local DOKKU_PORT=""
|
|
if [[ "$PROC_TYPE" == "web" ]]; then
|
|
ports=($(plugn trigger network-compute-ports "$APP" "$PROC_TYPE" "$DOKKU_HEROKUISH" "$CONTAINER_INDEX"))
|
|
local DOKKU_DOCKER_PORT_ARGS=""
|
|
for p in "${ports[@]}"; do
|
|
if [[ ! "$p" =~ .*udp.* ]]; then
|
|
DOKKU_PORT=${DOKKU_PORT:="$p"}
|
|
fi
|
|
|
|
if [[ "$DOKKU_NETWORK_BIND_ALL" == "true" ]]; then
|
|
DOCKER_ARGS+=" -p $p "
|
|
fi
|
|
done
|
|
fi
|
|
|
|
DOCKER_ARGS+=" --env=PORT=$DOKKU_PORT "
|
|
|
|
START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH" "$DOKKU_PORT")
|
|
DOCKER_ARGS+=" $IMAGE "
|
|
DOCKER_ARGS+=" $START_CMD "
|
|
|
|
cid=$(fn-scheduler-docker-local-start-app-container "$APP" "$DOCKER_ARGS")
|
|
|
|
plugn trigger post-container-create "app" "$cid" "$APP" "deploy" "$PROC_TYPE"
|
|
"$DOCKER_BIN" container start "$cid" >/dev/null || true
|
|
|
|
ipaddr=$(plugn trigger network-get-ipaddr "$APP" "$PROC_TYPE" "$cid")
|
|
port=$(plugn trigger network-get-port "$APP" "$PROC_TYPE" "$cid" "$DOKKU_HEROKUISH")
|
|
|
|
kill_new() {
|
|
declare desc="wrapper function to kill newly started app container"
|
|
declare CID="$1" PROC_TYPE="$2" CONTAINER_INDEX="$3"
|
|
|
|
plugn trigger scheduler-register-retired "$APP" "$CID" "$WAIT"
|
|
mkdir -p "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP"
|
|
echo "${CID} ${PROC_TYPE}.${CONTAINER_INDEX}" >>"${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/failed-containers"
|
|
"$DOCKER_BIN" container inspect "$CID" &>/dev/null && {
|
|
# Disable the container restart policy
|
|
"$DOCKER_BIN" container update --restart=no "$CID" &>/dev/null || true
|
|
"$DOCKER_BIN" container stop "$CID" >/dev/null && "$DOCKER_BIN" container kill "$CID" &>/dev/null
|
|
}
|
|
trap - INT TERM EXIT
|
|
kill -9 $$
|
|
}
|
|
|
|
# run checks first, then post-deploy hooks, which switches proxy traffic
|
|
trap "kill_new $cid $PROC_TYPE $CONTAINER_INDEX" INT TERM EXIT
|
|
if [[ "$(is_app_proctype_checks_disabled "$APP" "$PROC_TYPE")" == "false" ]]; then
|
|
dokku_log_info1 "Attempting pre-flight checks ($PROC_TYPE.$CONTAINER_INDEX)"
|
|
plugn trigger check-deploy "$APP" "$cid" "$PROC_TYPE" "$port" "$ipaddr"
|
|
fi
|
|
trap - INT TERM EXIT
|
|
|
|
if [[ -f "$DOKKU_CONTAINER_ID_FILE" ]]; then
|
|
# schedule old container for retirement
|
|
dokku_log_verbose "Scheduling old container shutdown for $PROC_TYPE.$CONTAINER_INDEX in $WAIT seconds"
|
|
plugn trigger scheduler-register-retired "$APP" "$(cat "$DOKKU_CONTAINER_ID_FILE")" "$WAIT"
|
|
fi
|
|
|
|
# now using the new container
|
|
[[ -n "$cid" ]] && echo "$cid" >"$DOKKU_CONTAINER_ID_FILE"
|
|
[[ -n "$ipaddr" ]] && plugn trigger network-write-ipaddr "$APP" "$PROC_TYPE" "$CONTAINER_INDEX" "$ipaddr"
|
|
[[ -n "$port" ]] && plugn trigger network-write-port "$APP" "$PROC_TYPE" "$CONTAINER_INDEX" "$port"
|
|
|
|
# cleanup pre-migration files
|
|
rm -f "$DOKKU_ROOT/$APP/CONTAINER" "$DOKKU_ROOT/$APP/IP" "$DOKKU_ROOT/$APP/PORT"
|
|
|
|
local CONTAINER_INDEX=$((CONTAINER_INDEX + 1))
|
|
done
|
|
# 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
|
|
for container_state_filetype in CONTAINER IP PORT; do
|
|
cd "$DOKKU_ROOT/$APP"
|
|
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
|
|
done < <(plugn trigger ps-current-scale "$APP")
|
|
|
|
dokku_log_info1 "Running post-deploy"
|
|
plugn trigger core-post-deploy "$APP" "$port" "$ipaddr" "$IMAGE_TAG"
|
|
plugn trigger post-deploy "$APP" "$port" "$ipaddr" "$IMAGE_TAG"
|
|
|
|
# kill the old container
|
|
if [[ -n "$oldids" ]]; then
|
|
# Let the old container finish processing requests, before terminating it
|
|
dokku_log_info1 "Shutting down old containers in $WAIT seconds"
|
|
(
|
|
exec >/dev/null 2>/dev/null </dev/null
|
|
trap '' INT HUP
|
|
sleep "$WAIT"
|
|
for oldid in $oldids; do
|
|
# Disable the container restart policy
|
|
"$DOCKER_BIN" container update --restart=no "$oldid" &>/dev/null || true
|
|
|
|
# Attempt to stop, if that fails, then force a kill as docker seems
|
|
# to not send SIGKILL as the docs would indicate. If that fails, move
|
|
# on to the next.
|
|
# shellcheck disable=SC2086
|
|
"$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$oldid" \
|
|
|| "$DOCKER_BIN" container kill "$oldid" \
|
|
|| plugn trigger retire-container-failed "$APP" "$oldid" # plugin trigger for event logging
|
|
done
|
|
) &
|
|
disown -a
|
|
# Use trap since disown/nohup don't seem to keep child alive
|
|
# Give child process just enough time to set the traps
|
|
sleep 0.1
|
|
fi
|
|
}
|
|
|
|
fn-scheduler-docker-local-extract-start-cmd() {
|
|
declare APP="$1" PROC_TYPE="$2" START_CMD="$3" DOKKU_HEROKUISH="$4" PORT="$5"
|
|
local DOKKU_DOCKERFILE_START_CMD DOKKU_PROCFILE_START_CMD START_CMD
|
|
if [[ "$DOKKU_HEROKUISH" != "false" ]] && [[ -n "$START_CMD" ]]; then
|
|
echo "$START_CMD"
|
|
return
|
|
fi
|
|
|
|
DOKKU_DOCKERFILE_START_CMD=$(config_get "$APP" DOKKU_DOCKERFILE_START_CMD || true)
|
|
DOKKU_PROCFILE_START_CMD=$(plugn trigger procfile-get-command "$APP" "$PROC_TYPE" "$PORT" 2>/dev/null || echo '')
|
|
START_CMD=${DOKKU_DOCKERFILE_START_CMD:-$DOKKU_PROCFILE_START_CMD}
|
|
echo "$START_CMD"
|
|
}
|
|
|
|
trigger-scheduler-docker-local-scheduler-deploy "$@"
|