Aller au contenu

Backup base de données

Version métier : voir Sauvegarde de la base de données.

Pipeline 100 % shell CI — pas de commande Symfony associée. Le job tourne directement sur le runner GitLab.

Dump complet de la base MySQL applicative toutes les 4 heures, poussé par rsync (clé SSH dédiée) sur $BACKUP_SERVER_URL avec :

  • un fichier horodaté ~/internal/${MYSQL_NAME}_YYYYMMDD_HHMMSS.sql (historique) ;
  • un fichier ~/internal/${MYSQL_NAME}_latest.sql (restauration rapide).

La rétention est gérée par le schedule complémentaire Purge des backups.

Planification GitLab (via pipeline_schedules API, 2026-04-23) :

  • Description : Backup database
  • ID du schedule : 4081502
  • Cron : 0 */4 * * * (fuseau : Europe/Paris) — 00:00, 04:00, 08:00, 12:00, 16:00, 20:00 Paris.
  • Branche : refs/heads/master
  • État : actif
  • Variable injectée : SCHEDULE_TYPE=backup

Job CI : backup_job dans ci-jobs/.scheduled-ci.yml (stage backup).

Pas de commande Symfony : tout se passe en shell sur le runner, qui ouvre deux connexions SSH (une vers $DATABASE_SERVER_URL pour le dump, une vers $BACKUP_SERVER_URL pour le dépôt rsync).

  1. before_script : installe openssh-client rsync, démarre ssh-agent, charge $DEPLOYER_SSH_PRIVATE_KEY.
  2. Dump : SSH sur $USER@$DATABASE_SERVER_URL qui exécute :
    Fenêtre de terminal
    docker run --rm --network mysql --env MYSQL_PWD=${MYSQL_PWD} mysql:latest \
    mysqldump -h mysql -u $MYSQL_USER $MYSQL_NAME
    La sortie stdout est redirigée vers backup.sql local au runner.
  3. Clé de backup : écrit $BACKUP_PRIVATE_KEY dans backup_key (chmod 600).
  4. Upload horodaté :
    Fenêtre de terminal
    rsync -avz -e "ssh -i backup_key -o StrictHostKeyChecking=no -p ${SSH_PORT}" \
    backup.sql \
    $BACKUP_USER@$BACKUP_SERVER_URL:~/internal/${MYSQL_NAME}_$(date +%Y%m%d_%H%M%S).sql
  5. Upload « latest » : même rsync vers ~/internal/${MYSQL_NAME}_latest.sql (écrase l’alias).
  6. after_script : rm -f backup_key backup.sql (nettoyage sur le runner).

Aucune entité applicative. Le job dump la base entière (schéma + données).

  • Pas de retry. Un échec de connexion SSH, un mysqldump en erreur ou un rsync refusé fait échouer le pipeline GitLab.
  • Pas de vérification d’intégrité du SQL : pas de --single-transaction, pas de --quick. Le dump est lancé sur une base en production, donc potentiellement non cohérent transactionnellement.

TODO(review) : considérer l’ajout de --single-transaction --quick --routines --triggers au mysqldump pour garantir la cohérence InnoDB.

  • Serveur DB ($DATABASE_SERVER_URL) — doit exposer le réseau Docker mysql et avoir docker disponible pour lancer mysql:latest.
  • Serveur de backup ($BACKUP_SERVER_URL, utilisateur $BACKUP_USER) — destination des .sql.
  • Runner GitLab — stockage temporaire de backup.sql le temps du rsync.

TODO(review) : envisager un alerting dédié (webhook GitLab vers Sentry Cron Monitoring, Slack, Discord) — un backup raté est un incident critique, le canal GitLab seul est fragile.

  • Job CI : ci-jobs/.scheduled-ci.yml (job backup_job)
  • Commande Symfony associée : aucune
  • $DEPLOYER_SSH_PRIVATE_KEY, $SSH_PORT, $USER, $APP_NAME
  • $DATABASE_SERVER_URL, $MYSQL_USER, $MYSQL_PWD, $MYSQL_NAME
  • $BACKUP_PRIVATE_KEY, $BACKUP_USER, $BACKUP_SERVER_URL