#!/usr/bin/env bash set -Eeuo pipefail : "${DEPLOY_USER:?DEPLOY_USER is required}" : "${DEPLOY_HOST:?DEPLOY_HOST is required}" : "${CI_REGISTRY_IMAGE:?CI_REGISTRY_IMAGE is required}" : "${CI_REGISTRY_USER:?CI_REGISTRY_USER is required}" : "${CI_REGISTRY_PASSWORD:?CI_REGISTRY_PASSWORD is required}" DEPLOY_PORT="${DEPLOY_PORT:-22}" DEPLOY_PATH="${DEPLOY_PATH:-/opt/vault-dash}" COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.deploy.yml}" COMPOSE_SERVICE="${COMPOSE_SERVICE:-vault-dash}" DEPLOY_TIMEOUT="${DEPLOY_TIMEOUT:-120}" HEALTHCHECK_URL="${HEALTHCHECK_URL:-http://127.0.0.1:${APP_PORT:-8000}/health}" IMAGE_TAG="${IMAGE_TAG:-${CI_COMMIT_SHA}}" APP_IMAGE="${APP_IMAGE:-${CI_REGISTRY_IMAGE}:${IMAGE_TAG}}" REMOTE_ENV_FILE="${REMOTE_ENV_FILE:-$DEPLOY_PATH/.env}" SSH_OPTS=(-p "$DEPLOY_PORT" -o StrictHostKeyChecking=no) REMOTE_TARGET="${DEPLOY_USER}@${DEPLOY_HOST}" ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" "mkdir -p '$DEPLOY_PATH'" if [[ -n "${APP_ENV_FILE:-}" ]]; then printf '%s\n' "$APP_ENV_FILE" | ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" "cat > '$REMOTE_ENV_FILE'" else ssh "${SSH_OPTS[@]}" "$REMOTE_TARGET" "cat > '$REMOTE_ENV_FILE'" </dev/null 2>&1; then CURRENT_CONTAINER="$(docker compose -f "$COMPOSE_FILE" --env-file "$REMOTE_ENV_FILE" ps -q "$COMPOSE_SERVICE" || true)" if [[ -n "$CURRENT_CONTAINER" ]]; then CURRENT_IMAGE="$(docker inspect -f '{{ .Config.Image }}' "$CURRENT_CONTAINER")" if [[ -n "$CURRENT_IMAGE" ]]; then PREVIOUS_IMAGE="$CURRENT_IMAGE" fi fi fi echo "$CI_REGISTRY_PASSWORD" | docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" --password-stdin docker pull "$APP_IMAGE" sed -i.bak "/^APP_IMAGE=/d" "$REMOTE_ENV_FILE" printf 'APP_IMAGE=%s\n' "$APP_IMAGE" | cat - "$REMOTE_ENV_FILE.bak" > "$REMOTE_ENV_FILE" rm -f "$REMOTE_ENV_FILE.bak" docker compose -f "$COMPOSE_FILE" --env-file "$REMOTE_ENV_FILE" up -d --remove-orphans end_time=$((SECONDS + DEPLOY_TIMEOUT)) until curl -fsS "$HEALTHCHECK_URL" >/dev/null; do if (( SECONDS >= end_time )); then echo "Deployment health check failed, attempting rollback" >&2 if [[ -n "$PREVIOUS_IMAGE" ]]; then sed -i.bak "/^APP_IMAGE=/d" "$REMOTE_ENV_FILE" printf 'APP_IMAGE=%s\n' "$PREVIOUS_IMAGE" | cat - "$REMOTE_ENV_FILE.bak" > "$REMOTE_ENV_FILE" rm -f "$REMOTE_ENV_FILE.bak" docker pull "$PREVIOUS_IMAGE" || true docker compose -f "$COMPOSE_FILE" --env-file "$REMOTE_ENV_FILE" up -d --remove-orphans fi exit 1 fi sleep 5 done echo "$APP_IMAGE" > .last_successful_image EOF