Files
Momento/scripts/deploy-prod.sh
Antigravity 76a8135567
Some checks failed
CI / Deploy production (on server) (push) Has been cancelled
CI / Lint, Unit Tests & Build (push) Has been cancelled
debug(monitoring): add Grafana provisioning diagnostics during deployment
2026-05-30 11:51:33 +00:00

196 lines
7.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Déploiement prod sur 192.168.1.190 — exécuter SUR LE SERVEUR (runner docker-host).
set -euo pipefail
# Telegram notification function
telegram_notify() {
local status="$1"
local message="$2"
local bot_token="${TELEGRAM_BOT_TOKEN:-}"
local chat_id="${TELEGRAM_CHAT_ID:-}"
if [ -z "$bot_token" ] || [ -z "$chat_id" ]; then
echo "TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID not set — skipping notification"
return 0
fi
local emoji="✅"
if [ "$status" = "failure" ]; then
emoji="❌"
elif [ "$status" = "rollback" ]; then
emoji="🔄"
fi
local commit_msg=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "unknown")
# Escape markdown special characters in commit message
commit_msg=$(echo "$commit_msg" | sed 's/[_*`[\]()~>#+=|{}.!\\-]/\\&/g')
local commit_short="${GIT_COMMIT:0:8}"
curl -s -X POST "https://api.telegram.org/bot${bot_token}/sendMessage" \
-d "chat_id=${chat_id}" \
-d "text=${emoji} Momento Deploy ${status}
Commit: ${commit_short}
Message: ${commit_msg}
Details: ${message}" \
-d "parse_mode=Markdown" > /dev/null 2>&1 || echo "Telegram notification failed"
}
# Rollback functions
rollback_save_image() {
echo "=== Saving current image for rollback ==="
if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^memento-memento-note:latest"; then
docker tag memento-memento-note:latest memento-memento-note:rollback || echo "WARN: Failed to tag rollback image"
echo "Rollback image saved: memento-memento-note:rollback"
else
echo "WARN: No current memento-note image found to save"
fi
}
rollback_restore_image() {
echo "=== Rolling back to previous image ==="
if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^memento-memento-note:rollback"; then
docker tag memento-memento-note:rollback memento-memento-note:latest || echo "ERROR: Failed to restore rollback image"
docker compose up -d --force-recreate memento-note || echo "ERROR: Failed to restart container"
echo "Rollback completed"
else
echo "ERROR: No rollback image found"
return 1
fi
}
ROOT="${DEPLOY_ROOT:-/opt/memento}"
ARTIFACT_TGZ="${ARTIFACT_TGZ:-}"
EXPECTED_COMMIT="${EXPECTED_COMMIT:-}"
# Health check configuration: 24 iterations × 5 seconds = 2 minutes total timeout
# This allows Next.js cold start time while keeping feedback fast
HEALTH_CHECK_MAX_ITERATIONS=24
HEALTH_CHECK_SLEEP_SECONDS=5
cd "$ROOT"
git config --global --add safe.directory "$ROOT" 2>/dev/null || true
git fetch origin main
git reset --hard origin/main
export GIT_COMMIT="$(git rev-parse HEAD)"
echo "=== Deploy $GIT_COMMIT ==="
if [ -n "$EXPECTED_COMMIT" ] && [ "$GIT_COMMIT" != "$EXPECTED_COMMIT" ]; then
echo "ERROR: git HEAD $GIT_COMMIT != expected $EXPECTED_COMMIT"
exit 1
fi
docker compose up -d postgres
for i in $(seq 1 30); do
docker compose exec -T postgres pg_isready -U "${POSTGRES_USER:-memento}" >/dev/null 2>&1 && break
[ "$i" -eq 30 ] && { echo "Postgres not ready"; exit 1; }
sleep 2
done
docker compose exec -T postgres psql -U "${POSTGRES_USER:-memento}" -d "${POSTGRES_DB:-memento}" -c "CREATE EXTENSION IF NOT EXISTS vector;" >/dev/null
if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -q '^memento-note/prisma/migrations/'; then
DUMP_FILE="/opt/memento/backups/pre-migrate-$(date +%Y%m%d-%H%M%S).sql.gz"
mkdir -p /opt/memento/backups
docker compose exec -T postgres pg_dump -U "${POSTGRES_USER:-memento}" -d "${POSTGRES_DB:-memento}" --clean --if-exists | gzip > "$DUMP_FILE"
DUMP_SIZE=$(stat -c%s "$DUMP_FILE")
if [ "$DUMP_SIZE" -lt 1048576 ]; then
echo "ERROR: Dump too small ($DUMP_SIZE bytes)"
exit 1
fi
echo "Backup: $DUMP_FILE ($(( DUMP_SIZE / 1024 ))KB)"
else
echo "No migration change — skip pre-migrate dump"
fi
export COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1
export GIT_COMMIT
# Save current image for rollback before building new one
rollback_save_image
if [ -n "$ARTIFACT_TGZ" ] && [ -f "$ARTIFACT_TGZ" ]; then
echo "=== Fast image (CI artifact) ==="
tar xzf "$ARTIFACT_TGZ" -C memento-note/
export MEMENTO_DOCKERFILE=Dockerfile.prebuilt
export MEMENTO_SOCKET_DOCKERFILE=Dockerfile.socket.prebuilt
else
echo "=== Full docker build (no artifact) ==="
export MEMENTO_DOCKERFILE=Dockerfile
export MEMENTO_SOCKET_DOCKERFILE=Dockerfile.socket
fi
docker compose build memento-note
docker compose build memento-socket
if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -q '^mcp-server/'; then
docker compose build mcp-server
fi
docker compose up -d --remove-orphans --force-recreate memento-note
docker compose up -d memento-socket
docker compose up -d mcp-server 2>/dev/null || true
# Monitoring stack updates are handled at the end of successful deployment
echo "=== Migrations (Prisma CLI via node, pas npx) ==="
if docker compose exec -T memento-note test -f ./node_modules/prisma/build/index.js 2>/dev/null; then
docker compose exec -T memento-note node ./node_modules/prisma/build/index.js migrate deploy
else
echo "WARN: prisma CLI absent de l'image — les migrations tournent au démarrage (entrypoint) ou via psql manuel"
fi
nginx -t 2>/dev/null && systemctl reload nginx 2>/dev/null || true
for i in $(seq 1 "$HEALTH_CHECK_MAX_ITERATIONS"); do
BODY=$(docker compose exec -T memento-note node -e "require('http').get('http://localhost:3000/api/build-info',r=>{let d='';r.on('data',c=>d+=c);r.on('end',()=>{console.log(d);process.exit(0)})}).on('error',()=>process.exit(1))" 2>/dev/null || true)
ACTUAL=$(echo "$BODY" | jq -r '.commit // empty' 2>/dev/null || true)
if [ "$ACTUAL" = "$GIT_COMMIT" ]; then
echo "OK build-info commit=$ACTUAL"
echo "=== Updating monitoring stack ==="
if [ -f /opt/memento/.env.docker ]; then
export $(cat /opt/memento/.env.docker | grep -v '^#' | xargs)
fi
if [ -n "${TELEGRAM_BOT_TOKEN:-}" ] && [ -n "${TELEGRAM_CHAT_ID:-}" ]; then
echo "=== Starting Monitoring Stack (with Telegram bot) ==="
docker compose -f monitoring/docker-compose.monitoring.yml --profile telegram up -d --remove-orphans 2>&1 || echo "WARN: Failed to bring up monitoring stack"
else
echo "=== Starting Monitoring Stack (without Telegram bot) ==="
docker compose -f monitoring/docker-compose.monitoring.yml up -d --remove-orphans 2>&1 || echo "WARN: Failed to bring up monitoring stack"
fi
# Force recreation of Grafana to reload physical JSON dashboards mounted from the host
echo "=== Recreating Grafana to load updated dashboards ==="
docker compose -f monitoring/docker-compose.monitoring.yml up -d --force-recreate grafana 2>&1 || true
# Diagnostics for Grafana dashboard loading
echo "=== Waiting for Grafana initialization ==="
sleep 4
echo "=== Grafana Mounted Dashboards ==="
docker exec memento-grafana ls -la /etc/grafana/dashboards || true
echo "=== Grafana Container Logs (Provisioning/Errors) ==="
docker logs memento-grafana --tail=100 || true
if docker ps --format '{{.Names}}' | grep -q "^memento-prometheus$"; then
echo "=== Reloading Prometheus configuration ==="
docker compose -f monitoring/docker-compose.monitoring.yml exec -T prometheus kill -SIGHUP 1 2>/dev/null || true
fi
if docker ps --format '{{.Names}}' | grep -q "^memento-alertmanager$"; then
echo "=== Reloading Alertmanager configuration ==="
docker compose -f monitoring/docker-compose.monitoring.yml exec -T alertmanager kill -SIGHUP 1 2>/dev/null || true
fi
docker compose ps
telegram_notify "success" "Deployment successful — app is healthy"
exit 0
fi
sleep "$HEALTH_CHECK_SLEEP_SECONDS"
done
echo "ERROR: build-info=$ACTUAL expected=$GIT_COMMIT"
docker logs memento-web --tail=40
# Rollback on health check failure
rollback_restore_image
telegram_notify "rollback" "Health check failed — rolled back to previous version"
exit 1