Dump de base automatisé

Description

Chaque nuit, les services en cours d'exécution sur ConteneursFaciles et exposant sur le port 5432 (PostgreSql) ou 3306 (MySql/MariaDb) bénéficie d'un lancement d'un dump de leur base et de leur stockage sur B3, sur la bucket dont le nom et le nom de la pile de service (stack), sur le répertoire /dumpsql, et dans le fichier base-X.sql.gz, où X est le jour de la semaine. Pour bénéficier de ce traitement, il faut que l'image dispose d'un répertoire /dumpsql, avec un script sauvegarde.sh pour l'export et un autre nommé restaure.sh, tout deux avec les droits d'exécution.

Script sauvegarde.sh

#!/bin/sh
############################################################################################
## export dump la base passée en paramètre sur le bucket de la stack sur l'objet  
##  dumpsql/base{jour de la semaine}.sql.gz ou fichier passé en paramètre
## Par défaut, le stockage objet de la PROD est utilisé, sauf option -p pour la PREPROD
## paramètres
## -d database: (obligatoire) nom de la base de données à restaurer
## -f fichier: nom du fichier (facultatif)
## -s stack: nom de la stack et donc du bucket à utiliser
## -c : url de caas-console (PROD ou PREPROD)
############################################################################################
# Variable à initialiser en dur ou avec une variable d'envirionnement du docker-compse.yml
user=root
database=$MYSQL_DATABASE 
## Fin paramétrage

usage() {
    msg=$1
    sortie=$2
    echo "Usage: $0 [-s <stack>] [-d <database>] [-f <dump.sql>] -c <caas>" 1>&2
    [ -z "$msg" ] || echo $msg  1>&2
    [ -z "$sortie" ] && sortie=1
    [ $sortie -ne 0 ] && sortie=1
        exit $sortie
}

cd /dumpsql
fichier=/dumpsql/base`date '+%w'`.sql.gz
while getopts "hpd:s:c:" o ; do
  case "${o}" in
    h)
        usage "" 5
        ;;
    c)
    caas=${OPTARG}
    ;;
    f)
    fichier=${OPTARG}
        [ `dirname $fichier` != "/dumpsql" ] && usage "Le fichier spécifié doit être sur /dumpsql/ !" 8
    ;;
    s)
    stack=${OPTARG}
    ;;

    d)
    database=${OPTARG}
    ;;
    *)
    usage "Option inconnue!" 2
    ;;
  esac
done
if [ -z "$stack" ]; then
    if [ -z "$$STACK" ]; then
        usage "Option -s <stack> obligatoire!" 3
    else
        stack=$STACK
    fi
fi
if [ -z "$caas" ]; then
    if [ -z "$CAAS_PROD" ]; then
        usage "Option -c <caas-console> obligatoire!" 4
    else
        caas=$CAAS_PROD
    fi
fi

# récupère un token pour B3
[ -z "$OS_APPLICATION_CREDENTIAL_ID" ] && OS_APPLICATION_CREDENTIAL_ID=`curl $caas/api/os_id`
[ -z "$OS_APPLICATION_CREDENTIAL_SECRET" ] && OS_APPLICATION_CREDENTIAL_SECRET=`curl $caas/api/os_secret`
data='{"auth": {"identity": {"methods": ["application_credential"],"application_credential": {"id": "'$OS_APPLICATION_CREDENTIAL_ID'","secret": "'$OS_APPLICATION_CREDENTIAL_SECRET'","regions": {"name": "RegionTwo"}}}}}'
curl -X POST -H "Content-Type: application/json" -D auth.txt -o  auth.json -d "$data" "https://eco4.cloud.e2.rie.gouv.fr:5000/v3/auth/tokens" 
token=` grep 'x-subject-token' auth.txt| sed -e 's/x-subject-token/X-Auth-Token/'`
url=` cat auth.json | tr "[{" "\n\n" | grep '"region_id": "RegionTwo"' | grep 'store4-r2.cloud.e2.rie.gouv.fr:8080/swift/v1/AUTH_'| tr '",' "\n\n"| sort -u | grep https`
# vérification de l'existence de la bucket $stack sur le stockage objet sinon création du bucket $satck
curl -X GET -H "$token" -i "$url"|grep "$stack" || curl -X PUT -H "$token" -i "$url/$stack"

# export dump de la base gzippé
mysqldump -u root -p$MYSQL_ROOT_PASSWORD $database | gzip > $fichier

# copie sur B3 bucket $stack objet dumpsql
curl  -T $fichier  -X PUT -H "$token" -i "$url/$stack/dumpsql/base`date '+%w'`.sql.gz"
Recommandations
  • le script en l'état fonctionne pour Mysql
  • pensez à initialiser les variable d'environnement utilisé dans le script avec vos données dans le docker-compose.yml
  • c'est fait automatiquement pour OS_APPLICATION_CREDENTIAL_SECRET et OS_APPLICATION_CREDENTIAL_ID

Script restaure.sh

#!/bin/sh
############################################################################################
## Restaure le fichier fourni en paramétre avec le chemin complet sans / initial depuis le 
##  bucket en général dumpsql/base{jour de la semaine}.sql.gz
## ou récupère tous les fichiers de /dumpsql format base.*.sql.gz et chargera le plus récent
## dans tous les cas la base de données est recréée comme l'utilisateur si besoin
## Par défaut, le stockage objet de la PROD est utilisé, sauf option -p pour la PREPROD
## paramètres
## -u user :  user de la base de données
## -d database:  nom de la base de données à restaurer
## -f fichier: nom du fichier (facultatif)
## -s stack (obligatoire): nom de la stack et donc du bucket à utiliser
## -c url de caas-console (obligatoire): url de PROD ou PREPROD
############################################################################################
## Paramétrage pour Postgres
# Variable à initialiser en dur ou avec une variable d'envirionnement du docker-compose.yml
user=$DB_USER
database=$DB_DATABASE 
password=$DB_PASSWD
## Fin paramétrage
usage() {
    msg=$1
    sortie=$2
    echo "Usage: $0 -s <stack> [-u <user>] [-d <database>] [-f <dump.sql>] [-c <caas>]" 1>&2
    [ -z "$msg" ] || echo $msg  1>&2
    [ -z "$sortie" ] && sortie=1
    [ $sortie -ne 0 ] && sortie=1
        exit $sortie
}

cd /dumpsql
[ -d recup ] && rm -rf recup
mkdir recup
cd recup
fichier='dumpsql/base.*.sql.gz'
while getopts "hu:d:f:s:c:" o ; do
  case "${o}" in
    h)
        usage "" 5
        ;;
    c)
    caas=${OPTARG}
    ;;
    u)
    user=${OPTARG}
    ;;
    s)
    stack=${OPTARG}
    ;;
    f)
    fichier=${OPTARG}
    ;;
    d)
    database=${OPTARG}
    ;;
    *)
    usage "Option inconnue!" 2
    ;;
  esac
done
if [ -z "$stack" ]; then
    if [ -z "$$STACK" ]; then
        usage "Option -s <stack> obligatoire!" 3
    else
        stack=$STACK
    fi
fi
if [ -z "$caas" ]; then
    if [ -z "$CAAS_PROD" ]; then
        usage "Option -c <caas-console> obligatoire!" 4
    else
        caas=$CAAS_PROD
    fi
fi

cat <<EOF | PGPASSWORD="$POSTGRES_PASSWORD" psql -U postgres
DROP DATABASE IF EXISTS $database;
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM pg_roles WHERE rolname = '$user'
    ) THEN
        CREATE ROLE $user LOGIN PASSWORD '$password';
    END IF;
END
$$;
CREATE DATABASE  $database WITH OWNER "$user" ENCODING 'UTF8';
GRANT ALL PRIVILEGES ON DATABASE  $database TO $user;
EOF

# récupère un token pour stockage Objet B3
OS_APPLICATION_CREDENTIAL_ID=`curl $caas/api/os_id`
OS_APPLICATION_CREDENTIAL_SECRET=`curl $caas/api/os_secret`
data='{"auth": {"identity": {"methods": ["application_credential"],"application_credential": {"id": "'$OS_APPLICATION_CREDENTIAL_ID'","secret": "'$OS_APPLICATION_CREDENTIAL_SECRET'","regions": {"name": "RegionTwo"}}}}}'
curl -X POST -H "Content-Type: application/json" -D auth.txt -o  auth.json -d "$data" "https://eco4.cloud.e2.rie.gouv.fr:5000/v3/auth/tokens" 
token=` grep 'x-subject-token' auth.txt| sed -e 's/x-subject-token/X-Auth-Token/'`
url=` cat auth.json |tr "[{" "\n\n" | grep '"region_id": "RegionTwo"' |grep 'store4-r2.cloud.e2.rie.gouv.fr:8080/swift/v1/AUTH_'|tr '",' "\n\n"|sort -u |grep https`

# récupère sur B3 les fichiers correspondant à $fichier sur la bucket $stack avec leur date de dernière modification
liste=`curl  -X GET -H "$token" -i "$url/$stack" | grep -E -e "$fichier"`
for i in $liste
do
    curl  -H "Content-Type: text/html; charset=UTF-8" -X GET -H "$token" -D headers.txt -o `basename $i` "$url/$stack/$i?attributes"
    dd=`grep last-modified: headers.txt |cut -f2 -d:|sed -e 's/ //'`
    touch --date="$dd" `basename $i`
done

# prend le fichier le plus récent
prems=`ls -t |head -1`
# si le fichier n'existe pas, on sort
if [ -n "$prems" -a  -f "$prems"]; 
then
    # restore le fichier
    if gzip -c -d $prems | PGPASSWORD="$POSTGRES_PASSWORD" psql -U postgres  $database
    then
        exit 0
    else
        exit 1
    fi
else
    exit 2
fi
Recommandations
  • le script en l'état fonctionne pour PostgreSql
  • pensez à initialiser les variable d'environnement utilisé dans le script avec vos données dans le docker-compose.yml
  • c'est fait automatiquement pour OS_APPLICATION_CREDENTIAL_SECRET et OS_APPLICATION_CREDENTIAL_ID
  • si aucun nom de fichier n'est passé, le plus récent est utilisé
  • si aucune destination n'est passé (option -c), le dernier dump de la prodcution est restauré

Usage des Dumps

Les volumes persistants des bases de données sont sauvegardés par synchronisation des répertoire sur B3, sans arrêt des services. En cas de restauration, le service redémarre sur des fichier ne correspondant à un arrêt normal. Il procède à différent recovery, chacun plus destructifs à chaque échec. Dans le cas ou toutes les tentatives échouent, seul le dump de la base permet de repartir en supprimant totalement le contenu du volume persistant. On redemarre le service de base de données, qui recréer un espace propre. Il suffit de restaurer le dump.

Mieux, vous pouvez prévoir dans le script d'initialisation de la base de données, de lancer le script de restauration. Celui-ci retourne un code à 0 en cas de réussite, différent en cas d'échec.


Paramètres d’affichage

Choisissez un thème pour personnaliser l’apparence du site.