This reduces duplication and allows users to rely on global arguments to generate most labels needed. The 'commit' command cannot have global arguments because the whitespace within the label change breaks string-based interpolation, and shell arrays cannot be exported.
218 lines
9.1 KiB
Bash
Executable File
218 lines
9.1 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/ps/functions"
|
|
source "$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/internal-functions"
|
|
|
|
scheduler-docker-local-scheduler-deploy() {
|
|
declare desc="deploys an image tag for a given application"
|
|
declare trigger="scheduler-docker-local 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"
|
|
local DOKKU_DOCKER_STOP_TIMEOUT DOKKU_HEROKUISH DOKKU_NETWORK_BIND_ALL IMAGE
|
|
DOKKU_HEROKUISH=false
|
|
IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
|
|
verify_app_name "$APP"
|
|
plugn trigger pre-deploy "$APP" "$IMAGE_TAG"
|
|
|
|
is_image_herokuish_based "$IMAGE" && DOKKU_HEROKUISH=true
|
|
local IMAGE_SOURCE_TYPE="dockerfile"
|
|
[[ "$DOKKU_HEROKUISH" == "true" ]] && IMAGE_SOURCE_TYPE="herokuish"
|
|
local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE"
|
|
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}"
|
|
|
|
local line
|
|
local PROC_TYPE
|
|
local PROC_COUNT
|
|
local CONTAINER_INDEX
|
|
while read -r line || [[ -n "$line" ]]; do
|
|
[[ "$line" =~ ^#.* ]] && continue
|
|
line="$(strip_inline_comments "$line")"
|
|
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")"
|
|
for cid in $proctype_oldids; do
|
|
dokku_log_info2 "stopping $APP.$PROC_TYPE ($cid)"
|
|
|
|
# Disable the container restart policy
|
|
"$DOCKER_BIN" container update --restart=no "$cid" &>/dev/null || true
|
|
|
|
# shellcheck disable=SC2086
|
|
"$DOCKER_BIN" 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"
|
|
|
|
# start the app
|
|
local DOCKER_ARGS
|
|
DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG" "$PROC_TYPE" "$CONTAINER_INDEX")
|
|
DOCKER_ARGS+=" -e DYNO=$PROC_TYPE.$CONTAINER_INDEX "
|
|
DOCKER_ARGS+=$(: | plugn trigger docker-args-process-deploy "$APP" "$IMAGE_TAG" "$IMAGE_SOURCE_TYPE" "$PROC_TYPE" "$CONTAINER_INDEX")
|
|
[[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true "
|
|
|
|
declare -a ARG_ARRAY
|
|
eval "ARG_ARRAY=($DOCKER_ARGS)"
|
|
|
|
local START_CMD
|
|
[[ "$DOKKU_HEROKUISH" == "true" ]] && START_CMD="/start $PROC_TYPE"
|
|
|
|
if [[ "$PROC_TYPE" == "web" ]]; then
|
|
ports=($(plugn trigger network-compute-ports "$APP" "$PROC_TYPE" "$DOKKU_HEROKUISH"))
|
|
local DOKKU_DOCKER_PORT_ARGS=""
|
|
local DOKKU_PORT=""
|
|
for p in "${ports[@]}"; do
|
|
if [[ ! "$p" =~ .*udp.* ]]; then
|
|
DOKKU_PORT=${DOKKU_PORT:="$p"}
|
|
fi
|
|
DOKKU_DOCKER_PORT_ARGS+=" -p $p "
|
|
done
|
|
|
|
START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH" "$DOKKU_PORT")
|
|
if [[ "$DOKKU_NETWORK_BIND_ALL" == "false" ]]; then
|
|
# shellcheck disable=SC2086
|
|
cid=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d -e PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD)
|
|
else
|
|
# shellcheck disable=SC2086
|
|
cid=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d $DOKKU_DOCKER_PORT_ARGS -e PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD)
|
|
fi
|
|
else
|
|
START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH")
|
|
|
|
# shellcheck disable=SC2086
|
|
cid=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d "${ARG_ARRAY[@]}" $IMAGE $START_CMD)
|
|
fi
|
|
|
|
ipaddr=$(plugn trigger network-get-ipaddr "$APP" "$PROC_TYPE" "$cid")
|
|
port=$(plugn trigger network-get-port "$APP" "$PROC_TYPE" "$DOKKU_HEROKUISH" "$cid")
|
|
|
|
kill_new() {
|
|
declare desc="wrapper function to kill newly started app container"
|
|
declare CID="$1" PROC_TYPE="$2" CONTAINER_INDEX="$3"
|
|
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" inspect "$CID" &>/dev/null && {
|
|
# Disable the container restart policy
|
|
"$DOCKER_BIN" container update --restart=no "$CID" &>/dev/null || true
|
|
"$DOCKER_BIN" stop "$CID" >/dev/null && "$DOCKER_BIN" 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"
|
|
plugn trigger check-deploy "$APP" "$cid" "$PROC_TYPE" "$port" "$ipaddr"
|
|
fi
|
|
trap - INT TERM EXIT
|
|
|
|
# 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 <"$DOKKU_SCALE_FILE"
|
|
|
|
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
|
|
|
|
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
|
|
|
|
# Let the old container finish processing requests, before terminating it
|
|
local WAIT="${DOKKU_WAIT_TO_RETIRE:-60}"
|
|
dokku_log_info1 "Shutting down old containers in $WAIT seconds"
|
|
local oldid
|
|
for oldid in $oldids; do
|
|
dokku_log_info2 "$oldid"
|
|
fn-scheduler-docker-local-register-retired-container "$APP" "$oldid" "$WAIT"
|
|
done
|
|
(
|
|
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" stop $DOCKER_STOP_TIME_ARG "$oldid" \
|
|
|| "$DOCKER_BIN" 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" ]]; then
|
|
echo "$START_CMD"
|
|
return
|
|
fi
|
|
|
|
DOKKU_DOCKERFILE_START_CMD=$(config_get "$APP" DOKKU_DOCKERFILE_START_CMD || true)
|
|
DOKKU_PROCFILE_START_CMD=$(get_cmd_from_procfile "$APP" "$PROC_TYPE" "$PORT")
|
|
START_CMD=${DOKKU_DOCKERFILE_START_CMD:-$DOKKU_PROCFILE_START_CMD}
|
|
echo "$START_CMD"
|
|
}
|
|
|
|
scheduler-docker-local-scheduler-deploy "$@"
|