feat: add automated backup system with Docker-based cron
Implement a dedicated Docker container (backup-cron) for automated daily backups and maintenance tasks, eliminating the need for host cron configuration. New features: - backup-cron service: Alpine-based container with Docker CLI and cron - Automated daily backup at 5:00 AM (Europe/Paris timezone) - Automated health check at 6:00 AM (after backup) - Weekly log cleanup on Sundays at 3:00 AM (removes logs >30 days) Files added: - cron/Dockerfile: Alpine Linux with docker-cli, bash, and tzdata - cron/entrypoint.sh: Starts crond and displays configuration - cron/crontab: Scheduled tasks configuration - cron/README.md: Complete documentation for automated backups - scripts/clean-old-logs.sh: Automated log cleanup script Makefile enhancements: - make cron-status: Display backup automation status and schedule - make cron-logs: View logs from automated tasks Configuration improvements: - Auto-detect COMPOSE_PROJECT_NAME from directory name (portable) - Fix df command to use POSIX format (-P flag) for consistent output - Updated .env.example with COMPOSE_PROJECT_NAME documentation Benefits: - No host cron configuration required - Portable across different environments - Automatic timezone handling - Integrated with existing backup/health check scripts - Logs all automated tasks for monitoring 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,11 @@ REDIS_HOST_PASSWORD=CHANGEME_GENERATE_STRONG_PASSWORD
|
|||||||
BACKUP_DESTINATION=./backups
|
BACKUP_DESTINATION=./backups
|
||||||
BACKUP_RETENTION_DAYS=7
|
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)
|
# DÉVELOPPEMENT (localhost)
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|||||||
30
Makefile
30
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
|
include .env
|
||||||
export
|
export
|
||||||
@@ -47,6 +47,10 @@ help:
|
|||||||
@echo " → Docker, containers, Nextcloud, DB, Redis"
|
@echo " → Docker, containers, Nextcloud, DB, Redis"
|
||||||
@echo " → Espace disque, backups, logs"
|
@echo " → Espace disque, backups, logs"
|
||||||
@echo ""
|
@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 "Outils:"
|
||||||
@echo " make occ <cmd> - Exécuter une commande OCC Nextcloud"
|
@echo " make occ <cmd> - Exécuter une commande OCC Nextcloud"
|
||||||
@echo " make shell - Ouvrir un shell dans le container 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
|
@$(DOCKER_COMPOSE) exec -T nextcloud php occ files:cleanup 2>/dev/null && echo "✅ Fichiers orphelins nettoyés" || true
|
||||||
@echo "✅ Nettoyage terminé"
|
@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
|
# Catch-all target pour permettre les arguments aux commandes occ et restore
|
||||||
%:
|
%:
|
||||||
@:
|
@:
|
||||||
|
|||||||
24
cron/Dockerfile
Normal file
24
cron/Dockerfile
Normal file
@@ -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"]
|
||||||
147
cron/README.md
Normal file
147
cron/README.md
Normal file
@@ -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.
|
||||||
11
cron/crontab
Normal file
11
cron/crontab
Normal file
@@ -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
|
||||||
18
cron/entrypoint.sh
Executable file
18
cron/entrypoint.sh
Executable file
@@ -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
|
||||||
@@ -63,6 +63,28 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- nextcloud-net
|
- 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:
|
db:
|
||||||
image: mariadb:10.11
|
image: mariadb:10.11
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ if [ -z "$REQUIRED_SPACE" ] || [ "$REQUIRED_SPACE" = "0" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Obtenir l'espace disponible (enlever les espaces/newlines)
|
# 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
|
if [ -z "$AVAILABLE_SPACE" ]; then
|
||||||
log "ERROR" "Impossible de déterminer l'espace disque disponible"
|
log "ERROR" "Impossible de déterminer l'espace disque disponible"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
26
scripts/clean-old-logs.sh
Executable file
26
scripts/clean-old-logs.sh
Executable file
@@ -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é"
|
||||||
Reference in New Issue
Block a user