feat(migration): Ajoute les scripts backup.sh et restore.sh pour migrer la stack vers un autre serveur.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-04-10 14:17:10 +02:00
parent dbf422a543
commit 8b4ae992f8
2 changed files with 315 additions and 0 deletions

135
backup.sh Executable file
View File

@@ -0,0 +1,135 @@
#!/bin/sh
set -eu
# ============================================================================
# E-COSPLAY - Script de sauvegarde pour migration vers un autre serveur
# ----------------------------------------------------------------------------
# Sauvegarde :
# - Base de données PostgreSQL (pg_dump logique)
# - Volume MinIO (fichiers utilisateurs / médias)
# - Volume Vault (secrets HashiCorp Vault)
# - Fichiers d'environnement (.env.local, google.json, account.json)
#
# Le tout est empaqueté dans une archive tar.gz horodatée, prête à être
# transférée (scp/rsync) puis restaurée avec restore.sh sur le nouveau serveur.
# ============================================================================
RED='\033[0;31m'
ORANGE='\033[0;33m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
RESET='\033[0m'
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$PROJECT_DIR"
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="${BACKUP_DIR:-$PROJECT_DIR/var/backups}"
WORK_DIR="$BACKUP_DIR/tmp_$TIMESTAMP"
ARCHIVE="$BACKUP_DIR/e-cosplay_backup_$TIMESTAMP.tar.gz"
DB_CONTAINER="${DB_CONTAINER:-e-cosplay_db}"
DB_NAME="${DB_NAME:-app_db}"
DB_USER="${DB_USER:-symfony_user}"
MINIO_CONTAINER="${MINIO_CONTAINER:-e-cosplay_minio}"
VAULT_CONTAINER="${VAULT_CONTAINER:-e-cosplay_vault}"
echo "${CYAN}############################${RESET}"
echo "${CYAN}# E-COSPLAY BACKUP START #${RESET}"
echo "${CYAN}############################${RESET}"
echo "${CYAN}Destination : ${ARCHIVE}${RESET}"
mkdir -p "$WORK_DIR"
# ---------------------------------------------------------------------------
# 1) Vérifie que docker tourne et que les conteneurs sont up
# ---------------------------------------------------------------------------
if ! command -v docker >/dev/null 2>&1; then
echo "${RED}docker introuvable dans le PATH${RESET}" >&2
exit 1
fi
ensure_running() {
name="$1"
if ! docker ps --format '{{.Names}}' | grep -q "^${name}$"; then
echo "${ORANGE}> Conteneur ${name} arrêté, démarrage...${RESET}"
docker compose up -d "$(echo "$name" | sed 's/^e-cosplay_//')" || true
sleep 3
fi
}
ensure_running "$DB_CONTAINER"
ensure_running "$MINIO_CONTAINER"
ensure_running "$VAULT_CONTAINER"
# ---------------------------------------------------------------------------
# 2) Dump PostgreSQL (logique, portable entre versions mineures)
# ---------------------------------------------------------------------------
echo "${CYAN}> Dump de la base PostgreSQL (${DB_NAME})...${RESET}"
docker exec -t "$DB_CONTAINER" \
pg_dump -U "$DB_USER" -d "$DB_NAME" --clean --if-exists --no-owner --no-privileges \
| gzip -9 > "$WORK_DIR/database.sql.gz"
echo "${GREEN} ✓ database.sql.gz ($(du -h "$WORK_DIR/database.sql.gz" | cut -f1))${RESET}"
# ---------------------------------------------------------------------------
# 3) Snapshot des données MinIO (tar du dossier /data du conteneur)
# ---------------------------------------------------------------------------
echo "${CYAN}> Sauvegarde des données MinIO...${RESET}"
docker exec "$MINIO_CONTAINER" tar -C /data -czf - . > "$WORK_DIR/minio_data.tar.gz"
echo "${GREEN} ✓ minio_data.tar.gz ($(du -h "$WORK_DIR/minio_data.tar.gz" | cut -f1))${RESET}"
# ---------------------------------------------------------------------------
# 4) Snapshot des données Vault
# ---------------------------------------------------------------------------
echo "${CYAN}> Sauvegarde des données Vault...${RESET}"
if docker exec "$VAULT_CONTAINER" sh -c '[ -d /vault ]' 2>/dev/null; then
docker exec "$VAULT_CONTAINER" tar -C /vault -czf - . > "$WORK_DIR/vault_data.tar.gz"
echo "${GREEN} ✓ vault_data.tar.gz ($(du -h "$WORK_DIR/vault_data.tar.gz" | cut -f1))${RESET}"
else
echo "${ORANGE} ! /vault introuvable, vault ignoré${RESET}"
fi
# ---------------------------------------------------------------------------
# 5) Fichiers d'environnement et credentials
# ---------------------------------------------------------------------------
echo "${CYAN}> Copie des fichiers d'environnement et credentials...${RESET}"
mkdir -p "$WORK_DIR/env"
for f in .env .env.local .env.prod .env.prod.local google.json account.json; do
if [ -f "$PROJECT_DIR/$f" ]; then
cp -a "$PROJECT_DIR/$f" "$WORK_DIR/env/$f"
echo "${GREEN}$f${RESET}"
fi
done
# ---------------------------------------------------------------------------
# 6) Métadonnées (utiles côté restore pour vérifier la cohérence)
# ---------------------------------------------------------------------------
{
echo "timestamp=$TIMESTAMP"
echo "hostname=$(hostname)"
echo "git_commit=$(git -C "$PROJECT_DIR" rev-parse HEAD 2>/dev/null || echo unknown)"
echo "git_branch=$(git -C "$PROJECT_DIR" rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)"
echo "db_container=$DB_CONTAINER"
echo "db_name=$DB_NAME"
echo "db_user=$DB_USER"
echo "minio_container=$MINIO_CONTAINER"
echo "vault_container=$VAULT_CONTAINER"
} > "$WORK_DIR/manifest.txt"
# ---------------------------------------------------------------------------
# 7) Empaquetage final
# ---------------------------------------------------------------------------
echo "${CYAN}> Empaquetage de l'archive finale...${RESET}"
tar -C "$BACKUP_DIR" -czf "$ARCHIVE" "tmp_$TIMESTAMP"
rm -rf "$WORK_DIR"
echo "${GREEN}############################${RESET}"
echo "${GREEN}# BACKUP TERMINÉ #${RESET}"
echo "${GREEN}############################${RESET}"
echo "${GREEN}Archive : ${ARCHIVE}${RESET}"
echo "${GREEN}Taille : $(du -h "$ARCHIVE" | cut -f1)${RESET}"
echo
echo "${CYAN}Pour transférer vers le nouveau serveur :${RESET}"
echo " scp \"$ARCHIVE\" user@nouveau-serveur:/chemin/vers/e-cosplay/var/backups/"
echo " ssh user@nouveau-serveur 'cd /chemin/vers/e-cosplay && ./restore.sh \"var/backups/$(basename "$ARCHIVE")\"'"

180
restore.sh Executable file
View File

@@ -0,0 +1,180 @@
#!/bin/sh
set -eu
# ============================================================================
# E-COSPLAY - Script de restauration sur un nouveau serveur
# ----------------------------------------------------------------------------
# Usage : ./restore.sh <chemin/vers/e-cosplay_backup_YYYYMMDD_HHMMSS.tar.gz>
#
# Étapes :
# 1. Décompresse l'archive de sauvegarde
# 2. Restaure les fichiers d'environnement (.env.local, etc.)
# 3. Démarre la stack docker compose
# 4. Restaure la base PostgreSQL via psql
# 5. Restaure les volumes MinIO et Vault
# 6. Vide le cache Symfony et lance les migrations Doctrine éventuelles
#
# ATTENTION : la restauration ÉCRASE les données existantes (DB + volumes).
# ============================================================================
RED='\033[0;31m'
ORANGE='\033[0;33m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
RESET='\033[0m'
if [ $# -lt 1 ]; then
echo "${RED}Usage : $0 <archive.tar.gz>${RESET}" >&2
exit 1
fi
ARCHIVE="$1"
if [ ! -f "$ARCHIVE" ]; then
echo "${RED}Archive introuvable : $ARCHIVE${RESET}" >&2
exit 1
fi
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$PROJECT_DIR"
# Résout l'archive en chemin absolu AVANT de cd dans le dossier de travail
case "$ARCHIVE" in
/*) ARCHIVE_ABS="$ARCHIVE" ;;
*) ARCHIVE_ABS="$(pwd)/$ARCHIVE" ;;
esac
DB_CONTAINER="${DB_CONTAINER:-e-cosplay_db}"
DB_NAME="${DB_NAME:-app_db}"
DB_USER="${DB_USER:-symfony_user}"
MINIO_CONTAINER="${MINIO_CONTAINER:-e-cosplay_minio}"
VAULT_CONTAINER="${VAULT_CONTAINER:-e-cosplay_vault}"
WORK_DIR="$(mktemp -d /tmp/e-cosplay_restore.XXXXXX)"
trap 'rm -rf "$WORK_DIR"' EXIT
echo "${CYAN}#############################${RESET}"
echo "${CYAN}# E-COSPLAY RESTORE START #${RESET}"
echo "${CYAN}#############################${RESET}"
echo "${CYAN}Archive : ${ARCHIVE_ABS}${RESET}"
# ---------------------------------------------------------------------------
# Confirmation interactive (skip avec FORCE=1)
# ---------------------------------------------------------------------------
if [ "${FORCE:-0}" != "1" ]; then
printf "${ORANGE}La restauration va ÉCRASER la base et les volumes existants. Continuer ? [y/N] ${RESET}"
read -r answer
case "$answer" in
y|Y|yes|YES) ;;
*) echo "Annulé."; exit 0 ;;
esac
fi
# ---------------------------------------------------------------------------
# 1) Décompression
# ---------------------------------------------------------------------------
echo "${CYAN}> Décompression de l'archive...${RESET}"
tar -xzf "$ARCHIVE_ABS" -C "$WORK_DIR"
SRC="$(find "$WORK_DIR" -mindepth 1 -maxdepth 1 -type d | head -n1)"
if [ -z "$SRC" ] || [ ! -f "$SRC/manifest.txt" ]; then
echo "${RED}Archive invalide : manifest.txt introuvable${RESET}" >&2
exit 1
fi
echo "${GREEN} ✓ Contenu :${RESET}"
ls -la "$SRC"
echo "${GREEN} ✓ Manifest :${RESET}"
sed 's/^/ /' "$SRC/manifest.txt"
# ---------------------------------------------------------------------------
# 2) Restauration des fichiers d'environnement
# ---------------------------------------------------------------------------
if [ -d "$SRC/env" ]; then
echo "${CYAN}> Restauration des fichiers d'environnement...${RESET}"
for f in "$SRC"/env/*; do
[ -e "$f" ] || continue
name="$(basename "$f")"
if [ -f "$PROJECT_DIR/$name" ]; then
cp -a "$PROJECT_DIR/$name" "$PROJECT_DIR/$name.bak.$(date +%s)"
fi
cp -a "$f" "$PROJECT_DIR/$name"
echo "${GREEN}$name${RESET}"
done
fi
# ---------------------------------------------------------------------------
# 3) Démarrage de la stack docker compose
# ---------------------------------------------------------------------------
echo "${CYAN}> Démarrage de la stack docker compose...${RESET}"
docker compose up -d db minio vault
echo "${CYAN} Attente que PostgreSQL soit prêt...${RESET}"
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
if docker exec "$DB_CONTAINER" pg_isready -U "$DB_USER" -d "$DB_NAME" >/dev/null 2>&1; then
echo "${GREEN} ✓ PostgreSQL prêt${RESET}"
break
fi
sleep 2
if [ "$i" = "15" ]; then
echo "${RED}PostgreSQL n'est pas devenu disponible à temps${RESET}" >&2
exit 1
fi
done
# ---------------------------------------------------------------------------
# 4) Restauration PostgreSQL
# ---------------------------------------------------------------------------
if [ -f "$SRC/database.sql.gz" ]; then
echo "${CYAN}> Restauration de la base PostgreSQL...${RESET}"
gunzip -c "$SRC/database.sql.gz" \
| docker exec -i "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -v ON_ERROR_STOP=1 >/dev/null
echo "${GREEN} ✓ Base restaurée${RESET}"
else
echo "${ORANGE} ! database.sql.gz absent, étape ignorée${RESET}"
fi
# ---------------------------------------------------------------------------
# 5) Restauration MinIO
# ---------------------------------------------------------------------------
if [ -f "$SRC/minio_data.tar.gz" ]; then
echo "${CYAN}> Restauration des données MinIO...${RESET}"
docker exec "$MINIO_CONTAINER" sh -c 'rm -rf /data/* /data/..?* /data/.[!.]* 2>/dev/null || true'
docker exec -i "$MINIO_CONTAINER" tar -C /data -xzf - < "$SRC/minio_data.tar.gz"
echo "${GREEN} ✓ MinIO restauré${RESET}"
else
echo "${ORANGE} ! minio_data.tar.gz absent, étape ignorée${RESET}"
fi
# ---------------------------------------------------------------------------
# 6) Restauration Vault
# ---------------------------------------------------------------------------
if [ -f "$SRC/vault_data.tar.gz" ]; then
echo "${CYAN}> Restauration des données Vault...${RESET}"
docker exec "$VAULT_CONTAINER" sh -c 'rm -rf /vault/file 2>/dev/null || true'
docker exec -i "$VAULT_CONTAINER" tar -C /vault -xzf - < "$SRC/vault_data.tar.gz"
echo "${CYAN} Redémarrage du conteneur Vault...${RESET}"
docker compose restart vault
echo "${GREEN} ✓ Vault restauré${RESET}"
else
echo "${ORANGE} ! vault_data.tar.gz absent, étape ignorée${RESET}"
fi
# ---------------------------------------------------------------------------
# 7) Démarrage du reste de la stack + cache + migrations
# ---------------------------------------------------------------------------
echo "${CYAN}> Démarrage du reste de la stack...${RESET}"
docker compose up -d
if docker ps --format '{{.Names}}' | grep -q '^e-cosplay_php$'; then
echo "${CYAN}> Vidage du cache Symfony...${RESET}"
docker exec e-cosplay_php php bin/console cache:clear --no-warmup || true
docker exec e-cosplay_php php bin/console cache:warmup || true
echo "${CYAN}> Application des migrations Doctrine éventuelles...${RESET}"
docker exec e-cosplay_php php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration || true
fi
echo "${GREEN}#############################${RESET}"
echo "${GREEN}# RESTORE TERMINÉ #${RESET}"
echo "${GREEN}#############################${RESET}"
echo "${GREEN}Pense à vérifier :${RESET}"
echo " - les variables d'environnement spécifiques au nouveau serveur (PATH_URL, DEV_URL, etc.)"
echo " - les certificats et la configuration Caddy"
echo " - le déverrouillage de Vault si tu utilises un mode non-dev"