Accueil » Tous les articles » Sauvegarder ses containers Docker automatiquement avec Rclone

Sauvegarder ses containers Docker automatiquement avec Rclone

par | Mai 3, 2026 | ubuntu | 0 commentaires

| Mis à jour le 5 mai 2026

Article de la série « Mon ordinateur Ubuntu ». À lire après : Docker (et Portainer) – regrouper les données

Pour information, je me suis aidée de Claude.ai pour réaliser ces actions et rédiger l’article.


Maintenant que tous les fichiers importants de mes containers Docker sont regroupés dans /home/USER/docker/, je peux mettre en place une sauvegarde automatique vers Google Drive. C’est l’objectif de cet article.

J’utilise Rclone, un outil en ligne de commande qui synchronise des dossiers locaux vers des dizaines de services cloud. Couplé à un script bash et au planificateur cron, il permet d’automatiser complètement les sauvegardes, sans intervention manuelle.


La stratégie de rétention Grand-Père / Père / Fils

Plutôt qu’une simple copie quotidienne qui s’écrase, j’ai mis en place une stratégie de rétention appelée Grand-Père / Père / Fils (GFF) :

  • les sauvegardes quotidiennes sont conservées 7 jours
  • une sauvegarde hebdomadaire est créée chaque dimanche et conservée 4 semaines
  • une sauvegarde mensuelle est créée le 1er de chaque mois et conservée 12 mois
  • une sauvegarde annuelle est créée le 1er janvier et conservée indéfiniment

Rclone ne gère pas cette logique nativement. C’est le script bash qui s’en charge.


Ce que tu auras dans Google Drive au bout de quelques semaines

sauvegardes-beelink/
├── daily/
│   ├── 2026-05-01/
│   │   ├── stirling-pdf/
│   │   ├── nginx-proxy-manager/
│   │   └── portainer/
│   ├── 2026-05-02/
│   └── ...  (7 jours maximum)
├── weekly/
│   ├── 2026-W18/
│   └── ...  (4 semaines maximum)
├── monthly/
│   ├── 2026-05/
│   └── ...  (12 mois maximum)
└── yearly/
    └── 2026/  (conservé indéfiniment)

Nota : dans tout ce qui suit, il faut remplacer USER par ton nom d’utilisateur Linux


Étape 1 – Préparer un dossier dédié dans Google Drive

Depuis ton navigateur, va dans Google Drive et crée un dossier appelé sauvegardes-beelink. Ouvre ce dossier et regarde l’URL :

https://drive.google.com/drive/folders/1ABC123xyz456DEF789

La partie après /folders/ est l’ID du dossier. Copie-la et garde-la de côté.

En indiquant cet ID à Rclone, il ne verra que ce dossier et rien d’autre de ton Drive – c’est plus propre et plus sûr.


Étape 2 – Installer Rclone

Sur le Beelink, ouvre un terminal :

sudo apt install rclone

Vérifie l’installation :

rclone version

Tu dois voir quelque chose comme rclone v1.xx.x.


Étape 3 – Connecter Rclone à Google Drive

Lance la configuration interactive :

rclone config

Suis ces étapes dans le menu :

n                        → nouveau remote
Nom : gdrive
Type : drive             → tape le numéro correspondant à "Google Drive"
client_id :              → laisse vide, Entrée
client_secret :          → laisse vide, Entrée
scope : 1                → accès complet à Drive
Edit advanced config : y → on répond oui pour pouvoir renseigner root_folder_id
                           laisser tout vide sauf :
   root_folder_id :      → colle ici l'ID copié à l'étape 1
                           laisser tout le reste vide, Entrée à chaque fois
Edit advanced config : n → la question est reposée, on répond non cette fois
Use auto config : y      → ou n si tu es en SSH depuis Windows

Si tu travailles directement sur le Beelink (avec écran et clavier) :

Use auto config : y

Un navigateur s’ouvre – connecte-toi à Google et autorise Rclone.

Si tu travailles depuis ton PC Windows en SSH :

Use auto config : n

Rclone te donne une URL. Ouvre-la dans ton navigateur Windows, autorise l’accès, et colle le code retourné dans le terminal.

Puis dans les deux cas :

Configure this as a Shared Drive : n
OK → y

Vérifier la connexion

sudo rclone --config /home/USER/.config/rclone/rclone.conf lsd gdrive:

Si la commande retourne le contenu de ton dossier Drive (ou rien si le dossier est vide), la connexion est établie. Rclone ne voit que ce dossier – rien d’autre de ton Drive.


Étape 4 – Configurer sudo sans mot de passe pour Rclone

Portainer et Nginx Proxy Manager écrivent leurs fichiers en root à l’intérieur du container. Pour que Rclone puisse les lire, il doit s’exécuter avec sudo – y compris quand cron lance le script automatiquement la nuit, sans session interactive.

Note : selon ta configuration Ubuntu, cette étape peut ne pas être nécessaire. Si tu viens de taper ton mot de passe sudo, il est en cache pour quelques minutes. Pour être sûr que cron fonctionnera la nuit sans session ouverte, configure cette règle dans tous les cas.

sudo visudo

Ajoute cette ligne tout en bas :

USER ALL=(ALL) NOPASSWD: /usr/bin/rclone

Sauvegarde avec Ctrl+O puis quitte avec Ctrl+X.

Attention avec visudo : ne ferme jamais le fichier directement avec Ctrl+X sans avoir d’abord sauvegardé avec Ctrl+O. visudo valide la syntaxe avant d’enregistrer – une faute de frappe dans ce fichier pourrait te bloquer hors de sudo.


Étape 5 – Créer le token API Portainer

Le script de sauvegarde interroge l’API Portainer avant chaque sauvegarde pour exporter automatiquement le docker-compose.yml de chaque stack dans son dossier. Ainsi la sauvegarde contient toujours le YAML exact et à jour.

Pour cela il faut créer un token d’accès dans Portainer :

  1. Ouvre Portainer dans ton navigateur
  2. Clique sur ton nom d’utilisateur en haut à droite
  3. Clique sur My account
  4. Descends jusqu’à la section Access tokens
  5. Clique sur Add access token
  6. Donne-lui un nom : backup-script
  7. Copie immédiatement le token affiché – il ne sera plus visible ensuite

Stocke ce token dans un fichier protégé :

echo "ptr_TONTOKEN" > /home/USER/scripts/.portainer-token
chmod 600 /home/USER/scripts/.portainer-token

Le chmod 600 garantit que seul USER peut lire ce fichier.


Étape 6 – Créer le script de sauvegarde

Crée d’abord le dossier scripts s’il n’existe pas :

mkdir -p /home/USER/scripts

Puis crée le script :

nano /home/USER/scripts/backup-docker.sh

Colle ce contenu (remplace USER par ton nom d’utilisateur Linux) :

#!/bin/bash

# ═══════════════════════════════════════════════════════════════
# backup-docker.sh - Sauvegarde Docker vers Google Drive
# Stratégie Grand-Père / Père / Fils
# ═══════════════════════════════════════════════════════════════

# -- Configuration ────────────────────────────────────────────────
SOURCE="/home/USER/docker"
REMOTE="gdrive:"
LOG="/home/USER/scripts/backup-docker.log"
RCLONE_CONF="/home/USER/.config/rclone/rclone.conf"
PORTAINER_URL="https://192.168.86.101:9443"
PORTAINER_TOKEN=$(cat /home/USER/scripts/.portainer-token)
DATE=$(date +%Y-%m-%d)
DAY=$(date +%u)     # 1=lundi ... 7=dimanche
DOM=$(date +%d)     # jour du mois (01-31)
MONTH=$(date +%m)   # mois (01-12)

# -- Fonction de log ──────────────────────────────────────────────
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG"
}

# -- Commande rclone de base ──────────────────────────────────────
# sudo : nécessaire pour lire les fichiers root (Portainer, NPM)
# --config : pointe vers la config de USER
# --log-file : écrit les détails dans le fichier log
# --links : copie les liens symboliques comme de vrais fichiers
#           indispensable pour les certificats Let's Encrypt de NPM
#           dont live/npm-1/ ne contient que des symlinks vers archive/
# Important : ne pas ajouter --log-level, incompatible avec --log-file
RCLONE="sudo rclone --config $RCLONE_CONF --log-file=$LOG --links"

log "=== Début sauvegarde ==="

# -- Export automatique des YAML depuis l'API Portainer ───────────
# Récupère le YAML de chaque stack et l'écrit dans le dossier du logiciel.
# Ainsi la sauvegarde contient toujours le YAML exact et à jour.
log "Export des YAML depuis Portainer..."

STACKS_JSON=$(curl -sk \
    -H "X-API-Key: $PORTAINER_TOKEN" \
    "$PORTAINER_URL/api/stacks")

if [ -z "$STACKS_JSON" ] || [ "$STACKS_JSON" = "null" ]; then
    log "ERREUR : impossible de contacter l'API Portainer - les YAML ne seront pas mis à jour."
else
    STACK_COUNT=$(echo "$STACKS_JSON" | python3 -c "
import sys, json
stacks = json.load(sys.stdin)
print(len(stacks))
" 2>/dev/null)

    log "$STACK_COUNT stack(s) trouvée(s) dans Portainer."

    echo "$STACKS_JSON" | python3 -c "
import sys, json
stacks = json.load(sys.stdin)
for s in stacks:
    print(s['Id'], s['Name'])
" 2>/dev/null | while read stack_id stack_name; do

        YAML_CONTENT=$(curl -sk \
            -H "X-API-Key: $PORTAINER_TOKEN" \
            "$PORTAINER_URL/api/stacks/$stack_id/file" \
            | python3 -c "
import sys, json
data = json.load(sys.stdin)
print(data.get('StackFileContent', ''))
" 2>/dev/null)

        if [ -n "$YAML_CONTENT" ]; then
            DEST="$SOURCE/$stack_name/docker-compose.yml"
            mkdir -p "$SOURCE/$stack_name"
            echo "$YAML_CONTENT" > "$DEST"
            log "YAML exporté : $stack_name/docker-compose.yml"
        else
            log "ATTENTION : YAML vide ou inaccessible pour la stack $stack_name"
        fi
    done
fi

# -- Vérification des docker-compose.yml manquants ────────────────
# Portainer lui-même ne figure pas dans les stacks - son docker-compose.yml
# doit être créé manuellement une fois (voir article sur le regroupement).
# Le script signale dans le log tout dossier sans docker-compose.yml.
log "Vérification des docker-compose.yml..."
for dir in "$SOURCE"/*/; do
    logiciel=$(basename "$dir")
    compose="$dir/docker-compose.yml"
    if [ ! -f "$compose" ]; then
        log "ATTENTION : docker-compose.yml manquant dans $logiciel - à créer manuellement !"
    fi
done

# -- Sauvegarde quotidienne ───────────────────────────────────────
log "Copie vers daily/$DATE..."
$RCLONE copy "$SOURCE" "$REMOTE/daily/$DATE"

# -- Sauvegarde hebdomadaire (chaque dimanche) ────────────────────
if [ "$DAY" -eq 7 ]; then
    WEEK=$(date +%Y-W%V)
    log "Dimanche : création sauvegarde hebdomadaire $WEEK"
    $RCLONE copy "$REMOTE/daily/$DATE" "$REMOTE/weekly/$WEEK"
fi

# -- Sauvegarde mensuelle (le 1er de chaque mois) ─────────────────
if [ "$DOM" -eq 01 ]; then
    YEARMONTH=$(date +%Y-%m)
    log "1er du mois : création sauvegarde mensuelle $YEARMONTH"
    $RCLONE copy "$REMOTE/daily/$DATE" "$REMOTE/monthly/$YEARMONTH"
fi

# -- Sauvegarde annuelle (le 1er janvier) ─────────────────────────
if [ "$DOM" -eq 01 ] && [ "$MONTH" -eq 01 ]; then
    YEAR=$(date +%Y)
    log "1er janvier : création sauvegarde annuelle $YEAR"
    $RCLONE copy "$REMOTE/daily/$DATE" "$REMOTE/yearly/$YEAR"
fi

# -- Nettoyage des anciennes sauvegardes sur Drive ────────────────

# Quotidiennes : on garde 7 jours
log "Nettoyage daily > 7 jours..."
$RCLONE delete "$REMOTE/daily" --min-age 7d 2>/dev/null
$RCLONE rmdirs "$REMOTE/daily" 2>/dev/null

# Hebdomadaires : on garde 4 semaines
if sudo rclone --config "$RCLONE_CONF" lsd "$REMOTE/weekly" > /dev/null 2>&1; then
    log "Nettoyage weekly > 28 jours..."
    $RCLONE delete "$REMOTE/weekly" --min-age 28d
    $RCLONE rmdirs "$REMOTE/weekly"
else
    log "Dossier weekly inexistant sur Drive, nettoyage ignoré."
fi

# Mensuelles : on garde 12 mois
if sudo rclone --config "$RCLONE_CONF" lsd "$REMOTE/monthly" > /dev/null 2>&1; then
    log "Nettoyage monthly > 365 jours..."
    $RCLONE delete "$REMOTE/monthly" --min-age 365d
    $RCLONE rmdirs "$REMOTE/monthly"
else
    log "Dossier monthly inexistant sur Drive, nettoyage ignoré."
fi

# Annuelles : conservées indéfiniment, pas de nettoyage automatique

log "=== Sauvegarde terminée ==="

Sauvegarde avec Ctrl+O puis quitte avec Ctrl+X.

Rends le script exécutable :

chmod +x /home/USER/scripts/backup-docker.sh

Étape 7 – Tester manuellement

Avant d’automatiser, lance le script à la main :

/home/USER/scripts/backup-docker.sh

La copie prend plusieurs minutes selon la taille de tes données. C’est normal et rassurant – si ça se termine en moins de 5 secondes, c’est qu’il y a un problème (voir encart erreurs fréquentes ci-dessous).

Vérifie ensuite le log :

tail -30 /home/USER/scripts/backup-docker.log

Tu dois voir dans l’ordre :

  • les YAML exportés pour chaque stack
  • === Sauvegarde terminée === sans aucune ligne ERROR ou ATTENTION

Et dans Google Drive, le dossier daily/YYYY-MM-DD/ doit contenir les trois sous-dossiers stirling-pdf, nginx-proxy-manager et portainer.

Pour vérifier l’absence d’erreurs d’un coup :

grep -i error /home/USER/scripts/backup-docker.log

Si la commande ne retourne rien, tout est propre.


Étape 8 – Automatiser avec cron

cron est le planificateur de tâches de Linux. Ouvre-le :

crontab -e

Si c’est la première fois, choisis nano (option 1). Ajoute cette ligne tout en bas :

0 3 * * * /home/USER/scripts/backup-docker.sh

Cela lance le script tous les jours à 3h du matin. Assure-toi que le Beelink est allumé à cette heure. Sauvegarde avec Ctrl+O puis quitte avec Ctrl+X.

Vérifie que cron a bien enregistré :

crontab -l

Comment vérifier que la sauvegarde automatique a bien tourné

Le lendemain matin, consulte la fin du log :

tail -20 /home/USER/scripts/backup-docker.log

La dernière entrée doit être datée de cette nuit avec === Sauvegarde terminée ===.


Déboguer une sauvegarde qui ne fonctionne pas

Si le log montre une sauvegarde terminée en moins de 5 secondes sans aucune ligne de copie de fichiers, c’est le signe que rclone s’est lancé mais n’a rien fait – souvent à cause d’une erreur silencieuse au démarrage.

La méthode pour diagnostiquer : lance rclone directement en ligne de commande et observe ce qui se passe :

sudo rclone --config /home/USER/.config/rclone/rclone.conf lsd gdrive:

Si cette commande fonctionne, la connexion Drive est bonne. Si elle échoue, le problème est dans la config rclone ou le token Google.

Ensuite relance le script manuellement et surveille le log en temps réel dans un second terminal :

tail -f /home/USER/scripts/backup-docker.log

Erreurs fréquentes

La sauvegarde se termine en moins de 5 secondes Rclone a rencontré une erreur dès le départ et n’a rien copié, mais le script bash a continué jusqu’à la fin. Cause la plus fréquente : un conflit d’options ou un token Google Drive expiré. Diagnostique avec la commande lsd décrite ci-dessus.

« Can’t set -v and –log-level » Ce message apparaît si tu utilises à la fois --verbose et --log-level dans la même commande rclone. Les deux options sont incompatibles. Solution : n’utilise que --log-file sans --log-level – c’est ce que fait le script ci-dessus.

« Can’t follow symlink without -L/–copy-links » Ce message apparaît lors d’une restauration de Nginx Proxy Manager. Les certificats Let’s Encrypt dans letsencrypt/live/ sont des liens symboliques. Lors de la restauration, ajoute --copy-links à la commande rclone. La sauvegarde elle-même est correcte car le script utilise --links.

« Permission denied » sur les fichiers de Portainer ou NPM Ces containers écrivent leurs fichiers en root. Rclone doit s’exécuter avec sudo pour les lire. Vérifie que la ligne NOPASSWD est bien présente dans sudoers (étape 4), et que le chemin /usr/bin/rclone est correct sur ton système (which rclone pour le vérifier).

« Permission denied » lors de l’export du YAML Le fichier docker-compose.yml dans le dossier du logiciel appartient à root (créé avec sudo). Corrige les droits :

sudo chown USER:USER /home/USER/docker/nom-du-logiciel/docker-compose.yml

Le dossier weekly ou monthly n’apparaît pas C’est normal les premières semaines et les premiers mois. weekly se crée le premier dimanche après la mise en place, monthly le 1er du mois suivant. Le script vérifie leur existence avant de tenter un nettoyage – pas d’erreur à attendre.

Cron ne lance pas le script Vérifie que le service cron tourne : systemctl status cron. S’il est inactif : sudo systemctl enable cron && sudo systemctl start cron. Vérifie aussi que le script est bien exécutable : ls -la /home/USER/scripts/backup-docker.sh doit afficher -rwxr-xr-x.


Dans le prochain article

On verra comment restaurer un container depuis une sauvegarde Google Drive – c’est-à-dire utiliser concrètement tout ce qu’on vient de mettre en place.

0 0 votes
Évaluation de l'article
0
Nous aimerions avoir votre avis, veuillez laisser un commentaire.x