最終更新 1 month ago

Full backup zip + all compose file ! Compose Docker + Report Html

修正履歴 b58140f0d5254a0200ce00a62214a61309a1b553

Backup-Home-docker.tar.gz.sh Raw
1#!/bin/bash
2
3#############################
4# CONFIG
5#############################
6
7# Répertoire contenant tes containers
8SOURCE_DIR="/home/docker"
9
10# Répertoire où stocker les sauvegardes
11BACKUP_DIR="/home/backup/docker"
12
13# Nombre max de backups à conserver
14MAX_BACKUPS=5
15
16# Date format
17DATE="$(date +'%Y%m%d_%H%M%S')"
18
19# Fichier TAR final
20BACKUP_FILE="$BACKUP_DIR/docker_backup_${DATE}.tar.gz"
21
22# Dossier de configs des compose à côté du TAR
23CONFIG_DIR="$BACKUP_DIR/config_${DATE}"
24
25# Dossiers à exclure (chemins relatifs à $SOURCE_DIR)
26EXCLUDE_DIRS=(
27 "casaos_data/*"
28 "nginx_proxy/data/logs/*"
29 "yt-dl/video/*"
30)
31
32# LOGS
33LOG_FILE="/var/log/docker_backup.log"
34
35#############################
36# COULEURS
37#############################
38NC="\e[0m"
39GREEN="\e[32m"
40YELLOW="\e[33m"
41CYAN="\e[36m"
42RED="\e[31m"
43
44#############################
45# FONCTIONS
46#############################
47
48log_message() {
49 local msg="$1"
50 local now
51 now="$(date +'%Y-%m-%d %H:%M:%S')"
52 echo "$now - $msg" >> "$LOG_FILE"
53 echo -e "$now - $msg"
54}
55
56format_time() {
57 local t=$1
58 ((h=t/3600))
59 ((m=(t%3600)/60))
60 ((s=t%60))
61 printf "%02d:%02d:%02d\n" $h $m $s
62}
63
64check_pigz() {
65 if ! command -v pigz >/dev/null 2>&1; then
66 echo -e "${YELLOW}pigz n'est pas installé. Voulez-vous l’installer ? (y/n)${NC}"
67 read rep
68 if [ "$rep" = "y" ]; then
69 sudo apt update && sudo apt install -y pigz || {
70 echo -e "${RED}Échec de l’installation de pigz. Abandon.${NC}"
71 exit 1
72 }
73 else
74 echo -e "${RED}pigz est requis pour ce script. Abandon.${NC}"
75 exit 1
76 fi
77 fi
78}
79
80rotate_backups() {
81 log_message "Nettoyage des anciens backups (conserver les $MAX_BACKUPS plus récents)..."
82
83 # TAR
84 mapfile -t backups_tar < <(ls -1t "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null || true)
85 if [ "${#backups_tar[@]}" -gt "$MAX_BACKUPS" ]; then
86 for f in "${backups_tar[@]:$MAX_BACKUPS}"; do
87 log_message "Suppression ancien backup tar : $f"
88 rm -f "$f"
89 done
90 fi
91
92 # Dossiers config_
93 mapfile -t backups_cfg < <(ls -1td "$BACKUP_DIR"/config_* 2>/dev/null || true)
94 if [ "${#backups_cfg[@]}" -gt "$MAX_BACKUPS" ]; then
95 for d in "${backups_cfg[@]:$MAX_BACKUPS}"; do
96 log_message "Suppression ancien dossier config : $d"
97 rm -rf "$d"
98 done
99 fi
100}
101
102#############################
103# DÉBUT SCRIPT
104#############################
105
106SECONDS=0
107
108check_pigz
109
110mkdir -p "$BACKUP_DIR" "$CONFIG_DIR"
111touch "$LOG_FILE"
112
113echo -e "${CYAN}=== Backup Docker + Configs (Portainer / CasaOS) ===${NC}"
114log_message "Début sauvegarde Docker + configs Portainer & CasaOS..."
115
116##############################################
117# 1) Sauvegarde TAR via pigz + exclusions
118##############################################
119log_message "Création de l’archive : $BACKUP_FILE"
120
121# Construction des arguments d'exclusion dynamiques
122EXCLUDE_ARGS=(
123 "--exclude=*.log"
124 "--exclude=.composer"
125 "--exclude=.aptitude"
126 "--exclude=.cache"
127 "--exclude=.cmake"
128 "--exclude=.yarn"
129 "--exclude=.w3m"
130 "--exclude=.pip"
131 "--exclude=.pm2"
132 "--exclude=.pm"
133 "--exclude=.bundle"
134 "--exclude=.gem"
135 "--exclude=.cpan"
136 "--exclude=.cpanm"
137 "--exclude=.git"
138 "--exclude=.local"
139 "--exclude=.npm"
140 "--exclude=.nvm"
141 "--exclude=.rvm"
142 "--exclude=node_modules"
143 "--exclude=lost+found"
144 "--exclude=casaos_data"
145)
146
147for d in "${EXCLUDE_DIRS[@]}"; do
148 EXCLUDE_ARGS+=( "--exclude=$d" )
149done
150
151tar -cf "$BACKUP_FILE" -I pigz \
152 --directory="$SOURCE_DIR" \
153 "${EXCLUDE_ARGS[@]}" \
154 . 2>> "$LOG_FILE"
155
156if [ $? -ne 0 ]; then
157 log_message "ERREUR lors de la création du tar."
158 echo -e "${RED}Erreur lors de la création de l’archive.${NC}"
159 exit 1
160fi
161
162##############################################
163# 2) Extraction des docker-compose
164# - CasaOS: config_<date>/casaos/<container>/
165# - Docker: config_<date>/docker/<container>/
166##############################################
167
168log_message "Extraction des docker-compose CasaOS..."
169if [ -d "$SOURCE_DIR/casaos_data" ]; then
170 find "$SOURCE_DIR/casaos_data" -maxdepth 3 -type f -name "docker-compose.y*ml" | while read file; do
171 container_name=$(basename "$(dirname "$file")")
172 dest_dir="$CONFIG_DIR/casaos/$container_name"
173 mkdir -p "$dest_dir"
174 cp "$file" "$dest_dir/"
175 log_message " [CasaOS] → Compose trouvé : $file"
176 done
177fi
178
179log_message "Extraction des docker-compose Docker (hors casaos_data)..."
180find "$SOURCE_DIR" -type f -name "docker-compose.y*ml" ! -path "$SOURCE_DIR/casaos_data/*" | while read file; do
181 container_name=$(basename "$(dirname "$file")")
182 dest_dir="$CONFIG_DIR/docker/$container_name"
183 mkdir -p "$dest_dir"
184 cp "$file" "$dest_dir/"
185 log_message " [Docker] → Compose trouvé : $file"
186done
187
188##############################################
189# 3) Config Portainer (full)
190##############################################
191PORTAINER_CONFIG_DIR="$CONFIG_DIR/portainer/full_config"
192PORTAINER_FILES=0
193
194if docker volume inspect portainer_data >/dev/null 2>&1; then
195 log_message "Sauvegarde config Portainer..."
196 mkdir -p "$PORTAINER_CONFIG_DIR"
197 cp -r /var/lib/docker/volumes/portainer_data/_data/* "$PORTAINER_CONFIG_DIR/" 2>>"$LOG_FILE"
198 PORTAINER_FILES=$(find "$PORTAINER_CONFIG_DIR" -type f 2>/dev/null | wc -l)
199else
200 log_message "Portainer non détecté (volume portainer_data absent)."
201fi
202
203##############################################
204# 4) Config CasaOS (full)
205##############################################
206CASAOS_CONFIG_DIR="$CONFIG_DIR/casaos/full_config"
207CASAOS_FILES=0
208
209if [ -d "/var/lib/casaos" ]; then
210 log_message "Sauvegarde config CasaOS (full)..."
211 mkdir -p "$CASAOS_CONFIG_DIR"
212 cp -r /var/lib/casaos/* "$CASAOS_CONFIG_DIR/" 2>>"$LOG_FILE"
213 CASAOS_FILES=$(find "$CONFIG_DIR/casaos" -type f -name "docker-compose.y*ml" ! -path "$CONFIG_DIR/casaos/full_config/*" 2>/dev/null | wc -l)
214else
215 log_message "CasaOS non détecté (/var/lib/casaos manquant)."
216fi
217
218##############################################
219# 5) Comptages finaux (sur le backup courant)
220##############################################
221
222# Compose dans le backup (docker + casaos compose seulement)
223CASAOS_COMPOSE_BACKUP=$(find "$CONFIG_DIR/casaos" -maxdepth 3 -type f -name "docker-compose.y*ml" ! -path "$CASAOS_CONFIG_DIR/*" 2>/dev/null | wc -l)
224DOCKER_COMPOSE_BACKUP=$(find "$CONFIG_DIR/docker" -type f -name "docker-compose.y*ml" 2>/dev/null | wc -l)
225TOTAL_COMPOSE_BACKUP=$((CASAOS_COMPOSE_BACKUP + DOCKER_COMPOSE_BACKUP))
226
227# Compose dans le dossier source (hors casaos_data)
228SOURCE_COMPOSE_COUNT=$(find "$SOURCE_DIR" -type f -name "docker-compose.y*ml" ! -path "$SOURCE_DIR/casaos_data/*" 2>/dev/null | wc -l)
229
230# Rotation des anciens backups
231rotate_backups
232
233# Nombre total de tar.gz
234TOTAL_TAR=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | wc -l)
235
236# Oldest / newest après rotation
237OLDEST_BACKUP=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | head -n1)
238NEWEST_BACKUP=$(ls -1 "$BACKUP_DIR"/docker_backup_*.tar.gz 2>/dev/null | tail -n1)
239
240DURATION="$(format_time $SECONDS)"
241
242##############################################
243# 6) RÉSUMÉS
244##############################################
245
246
247
248log_message "----- RÉSUMÉ GLOBAL -----"
249log_message "Nombre de .tar.gz : $TOTAL_TAR"
250log_message "Backup le plus ancien : ${OLDEST_BACKUP:-N/A}"
251log_message "Backup le plus récent : ${NEWEST_BACKUP:-N/A}"
252log_message "Archive courante : $BACKUP_FILE"
253log_message "Dossier config courant : $CONFIG_DIR"
254log_message "Durée totale : $DURATION"
255
256echo -e "${GREEN}===== BACKUP TERMINÉ =====${NC}"
257echo -e "${CYAN}----- DOCKER -----${NC}"
258echo -e "${CYAN}Compose source (hors CasaOS) : ${GREEN}$SOURCE_COMPOSE_COUNT${NC}"
259echo -e "${CYAN}Compose backup (Docker) : ${GREEN}$DOCKER_COMPOSE_BACKUP${NC}"
260echo -e "${CYAN}Dossier compose Docker : ${YELLOW}$CONFIG_DIR/docker${NC}"
261
262echo -e "${CYAN}----- CASAOS -----${NC}"
263echo -e "${CYAN}Compose CasaOS backup : ${GREEN}$CASAOS_COMPOSE_BACKUP${NC}"
264echo -e "${CYAN}Dossier CasaOS backup : ${YELLOW}$CONFIG_DIR/casaos${NC}"
265
266echo -e "${CYAN}----- PORTAINER -----${NC}"
267echo -e "${CYAN}Fichiers config Portainer : ${GREEN}$PORTAINER_FILES${NC}"
268echo -e "${CYAN}Dossier Portainer backup : ${YELLOW}$PORTAINER_CONFIG_DIR${NC}"
269
270echo -e "${CYAN}----- GLOBAL -----${NC}"
271echo -e "${CYAN}Nombre de .tar.gz : ${GREEN}$TOTAL_TAR${NC}"
272echo -e "${CYAN}Oldest backup : ${YELLOW}${OLDEST_BACKUP:-N/A}${NC}"
273echo -e "${CYAN}Newest backup : ${YELLOW}${NEWEST_BACKUP:-N/A}${NC}"
274echo -e "${CYAN}Archive courante : ${YELLOW}$BACKUP_FILE${NC}"
275echo -e "${CYAN}Dossier config courant : ${YELLOW}$CONFIG_DIR${NC}"
276echo -e "${CYAN}Durée totale : ${GREEN}$DURATION${NC}"
277