alphax/scripts/deploy_server.sh
2026-06-01 00:16:01 +08:00

144 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
# Incremental deployment for an existing Dockerized AlphaX server.
#
# Required:
# DEPLOY_HOST="user@server"
# REMOTE_DIR="/path/to/existing/alphax-docker"
#
# Optional:
# DEPLOY_BRANCH="main"
# DEPLOY_MESSAGE="deploy: update alphax"
# DEPLOY_REMOTE="origin"
# DEPLOY_SERVICES="alphax-web alphax-scheduler alphax-price-streamer"
# DEPLOY_RUN_MIGRATIONS=1
# DEPLOY_HEALTHCHECK_URL="http://127.0.0.1:8191/api/stats"
# DEPLOY_SKIP_COMMIT=1
# DEPLOY_SKIP_PUSH=1
# DEPLOY_SKIP_BUILD=1
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DEPLOY_HOST="${DEPLOY_HOST:-}"
REMOTE_DIR="${REMOTE_DIR:-}"
DEPLOY_BRANCH="${DEPLOY_BRANCH:-main}"
DEPLOY_REMOTE="${DEPLOY_REMOTE:-origin}"
DEPLOY_MESSAGE="${DEPLOY_MESSAGE:-}"
DEPLOY_SERVICES="${DEPLOY_SERVICES:-alphax-web alphax-scheduler alphax-price-streamer}"
DEPLOY_RUN_MIGRATIONS="${DEPLOY_RUN_MIGRATIONS:-1}"
DEPLOY_HEALTHCHECK_URL="${DEPLOY_HEALTHCHECK_URL:-http://127.0.0.1:8191/api/stats}"
DEPLOY_SKIP_COMMIT="${DEPLOY_SKIP_COMMIT:-0}"
DEPLOY_SKIP_PUSH="${DEPLOY_SKIP_PUSH:-0}"
DEPLOY_SKIP_BUILD="${DEPLOY_SKIP_BUILD:-0}"
die() {
echo "[deploy] ERROR: $*" >&2
exit 1
}
info() {
echo "[deploy] $*"
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
}
quote_remote() {
printf "%q" "$1"
}
if [[ -z "$DEPLOY_HOST" || -z "$REMOTE_DIR" ]]; then
cat >&2 <<'USAGE'
Usage:
DEPLOY_HOST="user@server" REMOTE_DIR="/path/to/alphax-docker" DEPLOY_MESSAGE="deploy: xxx" bash scripts/deploy_server.sh
What it does on the existing server directory:
git fetch + git pull --ff-only
docker compose build
docker compose up -d postgres alphax-web alphax-scheduler alphax-price-streamer
Useful options:
DEPLOY_BRANCH=main
DEPLOY_SERVICES="alphax-web alphax-scheduler alphax-price-streamer"
DEPLOY_RUN_MIGRATIONS=1
DEPLOY_SKIP_COMMIT=1
DEPLOY_SKIP_PUSH=1
USAGE
exit 2
fi
require_cmd git
require_cmd ssh
cd "$ROOT_DIR"
current_branch="$(git branch --show-current)"
if [[ "$current_branch" != "$DEPLOY_BRANCH" ]]; then
die "current branch is '$current_branch', expected '$DEPLOY_BRANCH'. Set DEPLOY_BRANCH or switch branch first."
fi
if [[ -n "$(git status --porcelain)" ]]; then
if [[ "$DEPLOY_SKIP_COMMIT" == "1" ]]; then
die "working tree has changes, but DEPLOY_SKIP_COMMIT=1. Commit or stash first."
fi
if [[ -z "$DEPLOY_MESSAGE" ]]; then
die "working tree has changes. Provide DEPLOY_MESSAGE='deploy: ...' to commit them."
fi
info "staging local changes"
git add -A
info "creating local commit"
git commit -m "$DEPLOY_MESSAGE"
else
info "working tree clean; no local commit needed"
fi
if [[ "$DEPLOY_SKIP_PUSH" != "1" ]]; then
info "pushing $DEPLOY_REMOTE/$DEPLOY_BRANCH"
git push "$DEPLOY_REMOTE" "$DEPLOY_BRANCH"
else
info "skip git push"
fi
remote_dir_q="$(quote_remote "$REMOTE_DIR")"
branch_q="$(quote_remote "$DEPLOY_BRANCH")"
remote_q="$(quote_remote "$DEPLOY_REMOTE")"
services_q="$DEPLOY_SERVICES"
health_q="$(quote_remote "$DEPLOY_HEALTHCHECK_URL")"
remote_cmd="
set -Eeuo pipefail
cd $remote_dir_q
test -d .git || { echo '[deploy:remote] ERROR: REMOTE_DIR is not an existing git checkout'; exit 1; }
test -f docker-compose.yml || { echo '[deploy:remote] ERROR: docker-compose.yml not found in REMOTE_DIR'; exit 1; }
echo '[deploy:remote] fetching code'
git fetch $remote_q $branch_q
echo '[deploy:remote] checking out and pulling branch'
git checkout $branch_q
git pull --ff-only $remote_q $branch_q
echo '[deploy:remote] docker compose config check'
docker compose config >/dev/null
if [[ '$DEPLOY_SKIP_BUILD' != '1' ]]; then
echo '[deploy:remote] docker compose build'
docker compose build $services_q
else
echo '[deploy:remote] skip docker build'
fi
if [[ '$DEPLOY_RUN_MIGRATIONS' == '1' ]]; then
echo '[deploy:remote] running PostgreSQL migrations'
docker compose run --rm alphax-web python scripts/postgres/run_migrations.py
fi
echo '[deploy:remote] docker compose up'
docker compose up -d postgres $services_q
echo '[deploy:remote] service status'
docker compose ps
if [[ -n $health_q ]]; then
echo '[deploy:remote] healthcheck'
curl -fsS $health_q >/dev/null
fi
"
info "deploying on $DEPLOY_HOST:$REMOTE_DIR"
ssh "$DEPLOY_HOST" "$remote_cmd"
info "deployment complete"