62 lines
2.3 KiB
Bash
62 lines
2.3 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
umask 077
|
|
|
|
root=$1
|
|
upload=$2
|
|
commit=$3
|
|
build=$4
|
|
case "$root" in /opt/*|/srv/*|/home/*/*) ;; *) echo "Use a dedicated absolute deployment directory" >&2; exit 1;; esac
|
|
case "$root" in *..*|*[!a-zA-Z0-9_./-]*) echo "Invalid deployment path" >&2; exit 1;; esac
|
|
mkdir -p "$root/releases" "$root/backups"
|
|
root=$(cd "$root" && pwd -P)
|
|
exec 9>"$root/deploy.lock"
|
|
flock -w 600 9
|
|
if [ -f "$root/last-build" ] && [ "$build" -le "$(cat "$root/last-build")" ]; then
|
|
echo "A newer or identical build is already deployed"
|
|
exit 0
|
|
fi
|
|
|
|
release="$root/releases/$commit-$build"
|
|
mkdir -p "$release"
|
|
tar -xzf "$upload/lottery.tar.gz" -C "$release"
|
|
install -m 600 "$upload/runtime.env" "$release/.env.prod"
|
|
cd "$release"
|
|
export BOT_IMAGE="new_lottery_bot:$commit"
|
|
compose() { docker compose --project-name new_lottery_bot --env-file .env.prod "$@"; }
|
|
compose config --quiet
|
|
compose build --pull bot
|
|
old_image=$(docker inspect --format '{{.Image}}' lottery_bot 2>/dev/null || true)
|
|
old_project=$(docker inspect --format '{{index .Config.Labels "com.docker.compose.project"}}' lottery_bot 2>/dev/null || true)
|
|
if [ -n "$old_image" ] && [ "$old_project" != "new_lottery_bot" ]; then
|
|
echo "Existing lottery_bot belongs to another stack; align the Compose project before the first deployment" >&2
|
|
exit 1
|
|
fi
|
|
services=$(compose config --services | grep -v '^bot$')
|
|
# Service names come from this repository's trusted Compose file.
|
|
compose up -d --wait $services
|
|
compose run --rm --no-deps --user "$(id -u):$(id -g)" \
|
|
-v "$root/backups:/backups" -e BACKUP_FILE="/backups/$commit-$build-$(date -u +%Y%m%dT%H%M%SZ).dump" \
|
|
bot python scripts/backup_database.py
|
|
|
|
rollback() {
|
|
code=$?
|
|
trap - EXIT
|
|
if [ "$code" -ne 0 ] && [ -n "$old_image" ]; then
|
|
echo "Deployment failed; restoring previous application image" >&2
|
|
BOT_IMAGE="$old_image" compose up -d --no-build --no-deps bot || true
|
|
fi
|
|
exit "$code"
|
|
}
|
|
trap rollback EXIT
|
|
compose stop bot
|
|
compose run --rm --no-deps bot python -m alembic upgrade head
|
|
compose run --rm --no-deps bot python scripts/check_schema.py
|
|
compose up -d --no-build --wait --wait-timeout 180 bot
|
|
docker exec lottery_bot python -m src.core.health
|
|
ln -s "$release" "$root/current.$build"
|
|
mv -Tf "$root/current.$build" "$root/current"
|
|
printf '%s\n' "$build" > "$root/last-build"
|
|
trap - EXIT
|
|
echo "Deployment verified: $commit (build $build)"
|