diff --git a/.env.example b/.env.example index a7d18c3..0d7d8e3 100644 --- a/.env.example +++ b/.env.example @@ -20,6 +20,11 @@ REDIS_HOST_PASSWORD=CHANGEME_GENERATE_STRONG_PASSWORD BACKUP_DESTINATION=./backups BACKUP_RETENTION_DAYS=7 +# Docker Compose +# Le nom du projet est auto-détecté depuis le nom du dossier +# Vous pouvez le surcharger ici si nécessaire: +# COMPOSE_PROJECT_NAME=mon-nextcloud + # ============================================ # DÉVELOPPEMENT (localhost) # ============================================ diff --git a/Makefile b/Makefile index b2edbbc..a060d13 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help up down restart logs logs-all ps shell db-shell redis-shell occ backup restore update health check-health recover clean permissions +.PHONY: help up down restart logs logs-all ps shell db-shell redis-shell occ backup restore update health check-health recover clean permissions cron-logs cron-status include .env export @@ -47,6 +47,10 @@ help: @echo " → Docker, containers, Nextcloud, DB, Redis" @echo " → Espace disque, backups, logs" @echo "" + @echo "Automatisation:" + @echo " make cron-status - Afficher le statut et le planning des backups auto" + @echo " make cron-logs - Afficher les logs des tâches cron" + @echo "" @echo "Outils:" @echo " make occ - Exécuter une commande OCC Nextcloud" @echo " make shell - Ouvrir un shell dans le container Nextcloud" @@ -124,6 +128,30 @@ clean: @$(DOCKER_COMPOSE) exec -T nextcloud php occ files:cleanup 2>/dev/null && echo "✅ Fichiers orphelins nettoyés" || true @echo "✅ Nettoyage terminé" +cron-status: + @echo "=== Statut du service de backup automatique ===" + @echo "" + @echo "Container backup-cron:" + @$(DOCKER_COMPOSE) ps backup-cron + @echo "" + @echo "Planning des tâches:" + @$(DOCKER_COMPOSE) exec -T backup-cron cat /etc/crontabs/root 2>/dev/null | grep -v "^#" | grep -v "^$$" || echo "⚠ Container non démarré" + @echo "" + @echo "Heure du container:" + @$(DOCKER_COMPOSE) exec -T backup-cron date 2>/dev/null || echo "⚠ Container non démarré" + +cron-logs: + @echo "=== Logs des tâches automatiques ===" + @echo "" + @echo "Logs de backup (10 dernières lignes):" + @tail -n 10 ./logs/cron_backup.log 2>/dev/null || echo "Aucun log de backup" + @echo "" + @echo "Logs de health check (10 dernières lignes):" + @tail -n 10 ./logs/cron_health.log 2>/dev/null || echo "Aucun log de health check" + @echo "" + @echo "Logs de nettoyage (10 dernières lignes):" + @tail -n 10 ./logs/cron_clean.log 2>/dev/null || echo "Aucun log de nettoyage" + # Catch-all target pour permettre les arguments aux commandes occ et restore %: @: diff --git a/cron/Dockerfile b/cron/Dockerfile new file mode 100644 index 0000000..2b95336 --- /dev/null +++ b/cron/Dockerfile @@ -0,0 +1,24 @@ +FROM alpine:latest + +# Installer les dépendances nécessaires +RUN apk add --no-cache \ + docker-cli \ + docker-cli-compose \ + bash \ + tzdata + +# Configurer le fuseau horaire +ENV TZ=Europe/Paris +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# Copier le fichier crontab +COPY crontab /etc/crontabs/root + +# Copier le script d'entrée +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +# Créer le répertoire pour les logs +RUN mkdir -p /logs + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/cron/README.md b/cron/README.md new file mode 100644 index 0000000..4f1df8b --- /dev/null +++ b/cron/README.md @@ -0,0 +1,147 @@ +# Backup Automatique Nextcloud + +Ce dossier contient la configuration pour les backups automatiques via un container Docker dédié. + +## Architecture + +Le service `backup-cron` est un container Alpine Linux léger qui exécute des tâches planifiées: + +- **Image**: Alpine Linux avec Docker CLI et docker-compose +- **Fuseau horaire**: Europe/Paris (configurable via `TZ`) +- **Montages**: + - `/project`: Projet complet (scripts, config, etc.) + - `/var/run/docker.sock`: Socket Docker pour exécuter docker-compose + - `/logs`: Répertoire des logs partagé avec l'hôte + +## Planning par défaut + +| Tâche | Fréquence | Heure | Description | +|-------|-----------|-------|-------------| +| Backup | Quotidien | 5h00 | Backup complet (DB + fichiers) | +| Health check | Quotidien | 6h00 | Vérification après backup | +| Nettoyage | Hebdomadaire | Dimanche 3h00 | Suppression logs > 30 jours | + +## Utilisation + +### Démarrer le service + +```bash +# Build et démarrage +docker-compose up -d backup-cron + +# Ou reconstruire si modifié +docker-compose up -d --build backup-cron +``` + +### Vérifier le statut + +```bash +# Via Makefile +make cron-status + +# Ou directement +docker-compose ps backup-cron +docker-compose exec backup-cron cat /etc/crontabs/root +``` + +### Consulter les logs + +```bash +# Via Makefile +make cron-logs + +# Ou directement +tail -f logs/cron_backup.log +tail -f logs/cron_health.log +tail -f logs/cron_clean.log +``` + +### Tester manuellement + +```bash +# Exécuter un backup immédiatement +docker-compose exec backup-cron /bin/bash -c "cd /project && bash scripts/backup.sh" + +# Vérifier l'heure du container +docker-compose exec backup-cron date +``` + +## Personnalisation + +### Modifier le planning + +Éditez `cron/crontab` puis reconstruisez: + +```bash +# Format cron: minute hour day month weekday command +# Exemple: backup toutes les 6 heures +0 */6 * * * cd /project && bash scripts/backup.sh >> /logs/cron_backup.log 2>&1 + +# Reconstruire +docker-compose up -d --build backup-cron +``` + +### Changer le fuseau horaire + +Modifiez `docker-compose.yml`: + +```yaml +environment: + - TZ=America/New_York # ou autre fuseau +``` + +## Sécurité + +⚠️ **Important**: Le container a accès au socket Docker (`/var/run/docker.sock`), ce qui lui permet d'exécuter des commandes docker-compose. Cela est nécessaire pour les backups mais donne des privilèges élevés. + +**Bonnes pratiques**: +- N'exposez pas ce service sur le réseau externe +- Gardez les scripts de backup en lecture seule si possible +- Surveillez les logs régulièrement +- Limitez les ressources du container si nécessaire + +## Dépannage + +### Le container ne démarre pas + +```bash +# Vérifier les logs +docker-compose logs backup-cron + +# Reconstruire from scratch +docker-compose build --no-cache backup-cron +docker-compose up -d backup-cron +``` + +### Les tâches ne s'exécutent pas + +```bash +# Vérifier que crond tourne +docker-compose exec backup-cron ps aux | grep crond + +# Vérifier le crontab +docker-compose exec backup-cron cat /etc/crontabs/root + +# Vérifier l'heure du container +docker-compose exec backup-cron date +``` + +### Problèmes de permissions + +```bash +# Le container doit pouvoir écrire dans ./backups et ./logs +chmod 755 backups logs + +# Vérifier les montages +docker-compose exec backup-cron ls -la /project/backups +``` + +## Logs + +Tous les logs sont stockés dans `./logs/`: + +- `cron_backup.log`: Sorties des backups quotidiens +- `cron_health.log`: Résultats des health checks +- `cron_clean.log`: Logs de nettoyage hebdomadaire + +Les logs sont automatiquement nettoyés après 30 jours. diff --git a/cron/crontab b/cron/crontab new file mode 100644 index 0000000..ae99ba5 --- /dev/null +++ b/cron/crontab @@ -0,0 +1,11 @@ +# Nextcloud Docker - Tâches automatisées +# Format: minute hour day month weekday command + +# Backup quotidien à 5h00 du matin (heure de Paris) +0 5 * * * cd /project && bash scripts/backup.sh >> /logs/cron_backup.log 2>&1 + +# Health check quotidien à 6h00 (après le backup) +0 6 * * * cd /project && bash scripts/check-health.sh >> /logs/cron_health.log 2>&1 + +# Nettoyage hebdomadaire le dimanche à 3h00 +0 3 * * 0 cd /project && bash scripts/clean-old-logs.sh >> /logs/cron_clean.log 2>&1 diff --git a/cron/entrypoint.sh b/cron/entrypoint.sh new file mode 100755 index 0000000..8ee057e --- /dev/null +++ b/cron/entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -e + +echo "=========================================" +echo "Nextcloud Backup Cron Container" +echo "=========================================" +echo "Fuseau horaire: ${TZ:-UTC}" +echo "Heure actuelle: $(date)" +echo "" +echo "Tâches programmées:" +cat /etc/crontabs/root | grep -v "^#" | grep -v "^$" +echo "" +echo "Logs disponibles dans /logs/" +echo "=========================================" +echo "" + +# Démarrer crond en mode foreground +exec crond -f -l 2 diff --git a/docker-compose.yml b/docker-compose.yml index 3fa210e..1810bea 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,6 +63,28 @@ services: networks: - nextcloud-net + backup-cron: + build: ./cron + restart: unless-stopped + volumes: + # Monter le projet complet pour accéder aux scripts + - .:/project + # Monter Docker socket pour exécuter les commandes docker-compose + - /var/run/docker.sock:/var/run/docker.sock + # Partager les volumes avec nextcloud pour les backups + - ./data:/var/www/html + - ./db:/var/lib/mysql + - ./backups:/project/backups + - ./logs:/logs + environment: + - TZ=Europe/Paris + - COMPOSE_PROJECT_NAME + depends_on: + - nextcloud + - db + networks: + - nextcloud-net + db: image: mariadb:10.11 restart: unless-stopped diff --git a/scripts/backup.sh b/scripts/backup.sh index 1d94b1a..f25e699 100755 --- a/scripts/backup.sh +++ b/scripts/backup.sh @@ -114,7 +114,8 @@ if [ -z "$REQUIRED_SPACE" ] || [ "$REQUIRED_SPACE" = "0" ]; then fi # Obtenir l'espace disponible (enlever les espaces/newlines) -AVAILABLE_SPACE=$(df -B1 "$BACKUP_DIR" | awk 'NR==2 {print $4}' | tr -d '[:space:]') +# Utiliser -P pour format POSIX (garantit une ligne par système de fichiers) +AVAILABLE_SPACE=$(df -P -B1 "$BACKUP_DIR" | awk 'NR==2 {print $4}' | tr -d '[:space:]') if [ -z "$AVAILABLE_SPACE" ]; then log "ERROR" "Impossible de déterminer l'espace disque disponible" exit 1 diff --git a/scripts/clean-old-logs.sh b/scripts/clean-old-logs.sh new file mode 100755 index 0000000..5435160 --- /dev/null +++ b/scripts/clean-old-logs.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# scripts/clean-old-logs.sh - Nettoyage automatique des vieux logs + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$PROJECT_ROOT" + +LOG_DIR="./logs" +RETENTION_DAYS=30 + +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Nettoyage des logs > ${RETENTION_DAYS} jours..." + +# Compter les fichiers avant nettoyage +BEFORE=$(find "$LOG_DIR" -type f -name "*.log" 2>/dev/null | wc -l) + +# Supprimer les logs plus vieux que RETENTION_DAYS jours +DELETED=$(find "$LOG_DIR" -type f -name "*.log" -mtime +${RETENTION_DAYS} -delete -print 2>/dev/null | wc -l) + +# Compter les fichiers après nettoyage +AFTER=$(find "$LOG_DIR" -type f -name "*.log" 2>/dev/null | wc -l) + +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Fichiers supprimés: $DELETED" +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Fichiers restants: $AFTER" +echo "[$(date '+%Y-%m-%d %H:%M:%S')] Nettoyage terminé"