9e7b98579b
deploy-vps.sh: BRANCH default V2.0.0 invece di main. README: clone con -b V2.0.0, nota che il branch in produzione è V2.0.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
149 lines
6.0 KiB
Bash
Executable File
149 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# deploy-vps.sh — deploy Cerbero MCP V2 sul VPS senza passare per registry.
|
|
#
|
|
# Workflow:
|
|
# 1. git fetch + reset al ramo target
|
|
# 2. docker compose build (rebuild immagine se SHA è cambiata)
|
|
# 3. docker compose down (graceful, max 15s)
|
|
# 4. docker compose up -d
|
|
# 5. attesa healthcheck su /health
|
|
# 6. rollback automatico al SHA precedente se health fallisce
|
|
#
|
|
# Eseguito ON THE VPS, dentro la directory del repo (es. /opt/cerbero-mcp).
|
|
#
|
|
# Uso (sul VPS):
|
|
# cd /opt/cerbero-mcp
|
|
# bash scripts/deploy-vps.sh
|
|
#
|
|
# Uso (da macchina dev, via SSH):
|
|
# ssh user@vps 'cd /opt/cerbero-mcp && bash scripts/deploy-vps.sh'
|
|
#
|
|
# Variabili env (opzionali):
|
|
# BRANCH ramo git da deployare (default: V2.0.0)
|
|
# SERVICE nome servizio docker compose (default: cerbero-mcp)
|
|
# PORT porta /health da pingare (default: dal .env, fallback 9000)
|
|
# HEALTH_TIMEOUT_SECONDS attesa max health (default: 30)
|
|
# HEALTH_INTERVAL secondi tra retry health (default: 2)
|
|
# FORCE se "1", rebuild + restart anche se SHA invariata
|
|
# SKIP_ROLLBACK se "1", non fare rollback su health fail (per debug)
|
|
|
|
set -euo pipefail
|
|
|
|
# ─── Config ──────────────────────────────────────────────────────────────
|
|
BRANCH="${BRANCH:-V2.0.0}"
|
|
SERVICE="${SERVICE:-cerbero-mcp}"
|
|
HEALTH_TIMEOUT_SECONDS="${HEALTH_TIMEOUT_SECONDS:-30}"
|
|
HEALTH_INTERVAL="${HEALTH_INTERVAL:-2}"
|
|
|
|
# Risolvi PORT da .env se non passata
|
|
if [[ -z "${PORT:-}" ]]; then
|
|
if [[ -f .env ]] && grep -q '^PORT=' .env; then
|
|
PORT="$(grep '^PORT=' .env | head -1 | cut -d= -f2 | tr -d '[:space:]"')"
|
|
fi
|
|
fi
|
|
PORT="${PORT:-9000}"
|
|
HEALTH_URL="http://localhost:${PORT}/health"
|
|
|
|
# ─── Pre-check ───────────────────────────────────────────────────────────
|
|
command -v git >/dev/null || { echo "FATAL: git non installato"; exit 1; }
|
|
command -v docker >/dev/null || { echo "FATAL: docker non installato"; exit 1; }
|
|
command -v curl >/dev/null || { echo "FATAL: curl non installato"; exit 1; }
|
|
docker compose version >/dev/null 2>&1 || { echo "FATAL: docker compose non disponibile"; exit 1; }
|
|
|
|
if [[ ! -f .env ]]; then
|
|
echo "FATAL: .env non trovato in $(pwd)."
|
|
echo " Copia .env.example → .env e compila i valori prima del primo deploy."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f docker-compose.yml ]]; then
|
|
echo "FATAL: docker-compose.yml non trovato in $(pwd)."
|
|
exit 1
|
|
fi
|
|
|
|
# Verifica working tree pulito
|
|
if [[ -n "$(git status --porcelain)" ]]; then
|
|
echo "FATAL: working tree non pulito. Modifiche locali non gestite:"
|
|
git status --short
|
|
echo " Risolvi prima di deployare (es. git stash o git reset)."
|
|
exit 1
|
|
fi
|
|
|
|
# ─── Stato corrente ──────────────────────────────────────────────────────
|
|
CURRENT_SHA="$(git rev-parse --short HEAD)"
|
|
echo "==> SHA attuale (rollback target): $CURRENT_SHA"
|
|
echo "==> branch: $BRANCH"
|
|
echo "==> port: $PORT"
|
|
|
|
# ─── Fetch + reset ───────────────────────────────────────────────────────
|
|
echo "==> git fetch + reset --hard origin/${BRANCH}"
|
|
git fetch --prune origin
|
|
git reset --hard "origin/${BRANCH}"
|
|
|
|
NEW_SHA="$(git rev-parse --short HEAD)"
|
|
echo "==> SHA nuovo: $NEW_SHA"
|
|
|
|
if [[ "$CURRENT_SHA" == "$NEW_SHA" ]] && [[ "${FORCE:-0}" != "1" ]]; then
|
|
echo "==> Già aggiornato a $NEW_SHA. Nessun deploy necessario."
|
|
echo " (esporta FORCE=1 per riavviare comunque)"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$CURRENT_SHA" == "$NEW_SHA" ]]; then
|
|
echo "==> FORCE=1 → rebuild e restart anche se SHA invariata"
|
|
fi
|
|
|
|
# ─── Funzione di rollback ────────────────────────────────────────────────
|
|
rollback() {
|
|
if [[ "${SKIP_ROLLBACK:-0}" == "1" ]]; then
|
|
echo "==> SKIP_ROLLBACK=1 → niente rollback automatico"
|
|
return
|
|
fi
|
|
if [[ "$CURRENT_SHA" == "$NEW_SHA" ]]; then
|
|
echo "==> SHA invariata, niente da rollbackare"
|
|
return
|
|
fi
|
|
echo "==> ROLLBACK a $CURRENT_SHA"
|
|
git reset --hard "$CURRENT_SHA"
|
|
docker compose build "$SERVICE"
|
|
docker compose up -d --force-recreate "$SERVICE"
|
|
echo "==> rollback eseguito. Verifica manualmente lo stato."
|
|
}
|
|
|
|
# ─── Build ───────────────────────────────────────────────────────────────
|
|
echo "==> docker compose build $SERVICE"
|
|
docker compose build "$SERVICE"
|
|
|
|
# ─── Down + up ───────────────────────────────────────────────────────────
|
|
echo "==> docker compose down --timeout 15"
|
|
docker compose down --timeout 15
|
|
|
|
echo "==> docker compose up -d"
|
|
docker compose up -d
|
|
|
|
# ─── Health check ────────────────────────────────────────────────────────
|
|
echo "==> attendo /health (timeout ${HEALTH_TIMEOUT_SECONDS}s, retry ogni ${HEALTH_INTERVAL}s)"
|
|
deadline=$(( $(date +%s) + HEALTH_TIMEOUT_SECONDS ))
|
|
while [[ $(date +%s) -lt $deadline ]]; do
|
|
if curl -fsS "$HEALTH_URL" >/dev/null 2>&1; then
|
|
echo
|
|
echo "==> health OK"
|
|
curl -s "$HEALTH_URL"
|
|
echo
|
|
echo
|
|
echo "==> deploy DONE (SHA $CURRENT_SHA → $NEW_SHA, branch $BRANCH)"
|
|
exit 0
|
|
fi
|
|
printf "."
|
|
sleep "$HEALTH_INTERVAL"
|
|
done
|
|
|
|
echo
|
|
echo "==> FAIL: /health non risponde dopo ${HEALTH_TIMEOUT_SECONDS}s"
|
|
echo "==> log container (ultime 40 righe):"
|
|
docker compose logs --tail 40 "$SERVICE" || true
|
|
|
|
rollback
|
|
|
|
exit 1
|