From fb7e6890d8516618fa3baec0edf84048e2b6601d Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Sat, 15 Mar 2025 00:50:34 -0700 Subject: a docker swarm --- playbooks/roles/docker/files/docker-rollout | 204 ++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100755 playbooks/roles/docker/files/docker-rollout (limited to 'playbooks/roles/docker/files/docker-rollout') diff --git a/playbooks/roles/docker/files/docker-rollout b/playbooks/roles/docker/files/docker-rollout new file mode 100755 index 0000000..c15d5a8 --- /dev/null +++ b/playbooks/roles/docker/files/docker-rollout @@ -0,0 +1,204 @@ +#!/bin/sh +set -e + +# Defaults +HEALTHCHECK_TIMEOUT=60 +NO_HEALTHCHECK_TIMEOUT=10 +WAIT_AFTER_HEALTHY_DELAY=0 + +# Print metadata for Docker CLI plugin +if [ "$1" = "docker-cli-plugin-metadata" ]; then + cat </dev/null 2>&1; then + # shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments + COMPOSE_COMMAND="docker $DOCKER_ARGS compose" +elif docker-compose >/dev/null 2>&1; then + COMPOSE_COMMAND="docker-compose" +else + echo "docker compose or docker-compose is required" + exit 1 +fi + +usage() { + cat < Service '$SERVICE' is not running. Starting the service." + $COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES up --detach --no-recreate "$SERVICE" + exit 0 + fi + + # shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files + OLD_CONTAINER_IDS_STRING=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | tr '\n' '|' | sed 's/|$//') + OLD_CONTAINER_IDS=$(echo "$OLD_CONTAINER_IDS_STRING" | tr '|' ' ') + SCALE=$(echo "$OLD_CONTAINER_IDS" | wc -w | tr -d ' ') + SCALE_TIMES_TWO=$((SCALE * 2)) + echo "==> Scaling '$SERVICE' to '$SCALE_TIMES_TWO' instances" + scale "$SERVICE" $SCALE_TIMES_TWO + + # Create a variable that contains the IDs of the new containers, but not the old ones + # shellcheck disable=SC2086 # COMPOSE_FILES and ENV_FILES must be unquoted to allow multiple files + NEW_CONTAINER_IDS=$($COMPOSE_COMMAND $COMPOSE_FILES $ENV_FILES ps --quiet "$SERVICE" | grep -Ev "$OLD_CONTAINER_IDS_STRING" | tr '\n' ' ') + + # Check if first container has healthcheck + # shellcheck disable=SC2086 # DOCKER_ARGS must be unquoted to allow multiple arguments + if docker $DOCKER_ARGS inspect --format='{{json .State.Health}}' "$(echo $OLD_CONTAINER_IDS | cut -d\ -f 1)" | grep -q "Status"; then + echo "==> Waiting for new containers to be healthy (timeout: $HEALTHCHECK_TIMEOUT seconds)" + for _ in $(seq 1 "$HEALTHCHECK_TIMEOUT"); do + SUCCESS=0 + + for NEW_CONTAINER_ID in $NEW_CONTAINER_IDS; do + if healthcheck "$NEW_CONTAINER_ID"; then + SUCCESS=$((SUCCESS + 1)) + fi + done + + if [ "$SUCCESS" = "$SCALE" ]; then + break + fi + + sleep 1 + done + + SUCCESS=0 + + for NEW_CONTAINER_ID in $NEW_CONTAINER_IDS; do + if healthcheck "$NEW_CONTAINER_ID"; then + SUCCESS=$((SUCCESS + 1)) + fi + done + + if [ "$SUCCESS" != "$SCALE" ]; then + echo "==> New containers are not healthy. Rolling back." >&2 + + docker $DOCKER_ARGS stop $NEW_CONTAINER_IDS + docker $DOCKER_ARGS rm $NEW_CONTAINER_IDS + + exit 1 + fi + + if [ "$WAIT_AFTER_HEALTHY_DELAY" != "0" ]; then + echo "==> Waiting for healthy containers to settle down ($WAIT_AFTER_HEALTHY_DELAY seconds)" + sleep $WAIT_AFTER_HEALTHY_DELAY + fi + else + echo "==> Waiting for new containers to be ready ($NO_HEALTHCHECK_TIMEOUT seconds)" + sleep "$NO_HEALTHCHECK_TIMEOUT" + fi + + echo "==> Stopping and removing old containers" + + # shellcheck disable=SC2086 # DOCKER_ARGS and OLD_CONTAINER_IDS must be unquoted to allow multiple arguments + docker $DOCKER_ARGS stop $OLD_CONTAINER_IDS + # shellcheck disable=SC2086 # DOCKER_ARGS and OLD_CONTAINER_IDS must be unquoted to allow multiple arguments + docker $DOCKER_ARGS rm $OLD_CONTAINER_IDS +} + +while [ $# -gt 0 ]; do + case "$1" in + -h | --help) + usage + exit 0 + ;; + -f | --file) + COMPOSE_FILES="$COMPOSE_FILES -f $2" + shift 2 + ;; + --env-file) + ENV_FILES="$ENV_FILES --env-file $2" + shift 2 + ;; + -t | --timeout) + HEALTHCHECK_TIMEOUT="$2" + shift 2 + ;; + -w | --wait) + NO_HEALTHCHECK_TIMEOUT="$2" + shift 2 + ;; + --wait-after-healthy) + WAIT_AFTER_HEALTHY_DELAY="$2" + shift 2 + ;; + -*) + echo "Unknown option: $1" + exit_with_usage + ;; + *) + if [ -n "$SERVICE" ]; then + echo "SERVICE is already set to '$SERVICE'" + + if [ "$SERVICE" != "$1" ]; then + exit_with_usage + fi + fi + + SERVICE="$1" + shift + ;; + esac +done + +# Require SERVICE argument +if [ -z "$SERVICE" ]; then + echo "SERVICE is missing" + exit_with_usage +fi + +main -- cgit v1.2.3-70-g09d2