mirror of
https://github.com/dokku/dokku.git
synced 2025-12-29 00:25:08 +01:00
This change makes Dokku start up the new container, run a set of checks against it, and only switch traffic over to the new containers if all checks complete successfully. No requests are dropped during the switch over. To specify checks, add a CHECKS file to the root of your project directory. This is a text file with one line per check. Empty lines and lines starting with # are ignored. A check is a relative URL and may be followed by expected content from the page, for example: /about Our Amazing Team Even if you don’t use any checks, this change will prevent downtime during switching from old to new container. See: https://labnotes.org/zero-downtime-deploy-with-dokku/
75 lines
2.6 KiB
Bash
Executable File
75 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Hook to check server against list of checks specified in CHECKS file. Each
|
|
# check is a relative path and, optionally, expected content.
|
|
#
|
|
# For example:
|
|
# / My Amazing App
|
|
# /stylesheets/index.css .body
|
|
# /scripts/index.js $(function()
|
|
# /images/logo.png
|
|
#
|
|
# Waits 5 seconds, giving server time to start, before running the checks. For
|
|
# shorter/longer wait, change the DOKKU_CHECKS_WAIT environment variable (value
|
|
# in seconds).
|
|
|
|
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
|
CONTAINERID="$1"; APP="$2"; PORT="$3" ; HOSTNAME="${4:-localhost}"
|
|
|
|
# source in app env to get DOKKU_CHECKS_WAIT and any other necessary vars
|
|
[[ -f "$DOKKU_ROOT/$APP/ENV" ]] && source $DOKKU_ROOT/$APP/ENV
|
|
# echo "DOKKU_CHECKS_WAIT is $DOKKU_CHECKS_WAIT"
|
|
FILENAME="$DOKKU_ROOT/$APP/CHECKS"
|
|
WAIT="${DOKKU_CHECKS_WAIT:-5}"
|
|
|
|
# try to copy CHECKS from container if not in APP dir & quit gracefully if it doesn't exist
|
|
# docker cp exits with status 1 when run as non-root user when it tries to chown the file
|
|
# after successfully copying the file. Thus, we suppress stderr.
|
|
# ref: https://github.com/dotcloud/docker/issues/3986
|
|
if [[ ! -f "$FILENAME" ]] ; then
|
|
echo " check-deploy: $FILENAME not found. attempting to retrieve it from container ..."
|
|
TMPDIR=$(mktemp -d /tmp/CHECKS.XXXXX)
|
|
docker cp $CONTAINERID:/app/CHECKS $TMPDIR 2> /dev/null || true
|
|
if [[ ! -s "${TMPDIR}/CHECKS" ]] ; then
|
|
echo " CHECKS file not found in container. skipping checks."
|
|
rm -rf $TMPDIR
|
|
exit 0
|
|
else
|
|
echo " CHECKS file found in container"
|
|
FILENAME=${TMPDIR}/CHECKS
|
|
|
|
function cleanup() {
|
|
echo " removing CHECKS file copied from container"
|
|
rm -rf $TMPDIR
|
|
}
|
|
trap cleanup EXIT
|
|
fi
|
|
fi
|
|
|
|
echo "Waiting $WAIT seconds ..."
|
|
sleep $WAIT
|
|
|
|
# -q do not use .curlrc (must come first)
|
|
# --compressed Test compression handled correctly
|
|
# --fail Fail on server errors (4xx, 5xx)
|
|
# --location Follow redirects
|
|
CURL_OPTIONS="-q --compressed --fail --location --max-time 30"
|
|
|
|
cat "$FILENAME" | while read PATHNAME EXPECTED ; do
|
|
# Ignore empty lines and lines starting with #
|
|
[[ -z "$PATHNAME" || "$PATHNAME" =~ ^\# ]] && continue
|
|
|
|
URL="http://$HOSTNAME:$PORT$PATHNAME"
|
|
|
|
echo "checking with: curl $CURL_OPTIONS $URL"
|
|
HTML=$(curl $CURL_OPTIONS $URL)
|
|
if [[ -n "$EXPECTED" && ! "$HTML" =~ "$EXPECTED" ]] ; then
|
|
echo -e "\033[31m\033[1m$URL: expected to but did not find: \"$EXPECTED\"\033[0m"
|
|
exit 1
|
|
else
|
|
echo -e "\033[32m\033[1m$URL => \"$EXPECTED\"\033[0m"
|
|
fi
|
|
done
|
|
|
|
echo -e "\033[32m\033[1mAll checks successful!\033[0m"
|