diff --git a/README.md b/README.md index a4868ac..ab7b38d 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Backup multiple databases from the same host by setting the database names in `P Supports the following Docker architectures: `linux/amd64`, `linux/arm64`, `linux/arm/v7`, `linux/s390x`, `linux/ppc64le`. +Please consider reading detailed the [How the backups folder works?](#how-the-backups-folder-works). + ## Usage Docker: @@ -100,6 +102,37 @@ This variables are not intended to be used for normal deployment operations: | POSTGRES_PORT_5432_TCP_ADDR | Sets the POSTGRES_HOST when the latter is not set. | | POSTGRES_PORT_5432_TCP_PORT | Sets POSTGRES_PORT when POSTGRES_HOST is not set. | +### How the backups folder works? + +First a new backup is created in the `last` folder with the full time. + +Once this backup finish succefully then, it is hard linked (instead of coping to avoid use more space) to the rest of the folders (daily, weekly and monthly). This step replaces the old backups for that category storing always only the latest for each category (so the monthly backup for a month is always storing the latest for that month and not the first). + +So the backup folder are structured as follows: + +* `BACKUP_DIR/last/DB-YYYYMMDD-HHmmss.sql.gz`: all the backups are stored separatly in this folder. +* `BACKUP_DIR/daily/DB-YYYYMMDD.sql.gz`: always store (hard link) the **latest** backup of that day. +* `BACKUP_DIR/weekly/DB-YYYYww.sql.gz`: always store (hard link) the **latest** backup of that week (the last day of the week will be Sunday as it uses ISO week numbers). +* `BACKUP_DIR/monthly/DB-YYYYMM.sql.gz`: always store (hard link) the **latest** backup of that month (normally the ~31st). + +And the following symlinks are also updated after each successfull backup for simlicity: + +``` +BACKUP_DIR/last/DB-latest.sql.gz -> BACKUP_DIR/last/DB-YYYYMMDD-HHmmss.sql.gz +BACKUP_DIR/daily/DB-latest.sql.gz -> BACKUP_DIR/daily/DB-YYYYMMDD.sql.gz +BACKUP_DIR/weekly/DB-latest.sql.gz -> BACKUP_DIR/weekly/DB-YYYYww.sql.gz +BACKUP_DIR/monthly/DB-latest.sql.gz -> BACKUP_DIR/monthly/DB-YYYYMM.sql.gz +``` + +For **cleaning** the script removes the files for each category only if the new backup has been successfull. +To do so it is using the following independent variables: + +* BACKUP_KEEP_MINS: will remove files from the `last` folder that are older than its value in minutes after a new successfull backup without affecting the rest of the backups (because they are hard links). +* BACKUP_KEEP_DAYS: will remove files from the `daily` folder that are older than its value in days after a new successfull backup. +* BACKUP_KEEP_WEEKS: will remove files from the `weekly` folder that are older than its value in weeks after a new successfull backup (remember that it starts counting from the end of each week not the beggining). +* BACKUP_KEEP_MONTHS: will remove files from the `monthly` folder that are older than its value in months (of 31 days) after a new successfull backup (remember that it starts counting from the end of each month not the beggining). + + ### Manual Backups By default this container makes daily backups, but you can start a manual backup by running `/backup.sh`. @@ -137,4 +170,3 @@ Replace `$BACKUPFILE`, `$VERSION`, `$HOSTNAME`, `$PORT`, `$USERNAME` and `$DBNAM ```sh docker run --rm --tty --interactive -v $BACKUPFILE:/tmp/backupfile.sql.gz postgres:$VERSION /bin/sh -c "zcat /tmp/backupfile.sql.gz | psql --host=$HOSTNAME --port=$PORT --username=$USERNAME --dbname=$DBNAME -W" ``` - diff --git a/backup.sh b/backup.sh index 16ad501..007f4fe 100755 --- a/backup.sh +++ b/backup.sh @@ -93,25 +93,35 @@ for DB in ${POSTGRES_DBS}; do ln -f "${FILE}/"* "${WFILENEW}/" ln -f "${FILE}/"* "${MFILENEW}/" rm -rf "${DFILE}" "${WFILE}" "${MFILE}" - mv -v "${DFILENEW}" "${DFILE}" - mv -v "${WFILENEW}" "${WFILE}" - mv -v "${MFILENEW}" "${MFILE}" + echo "Replacing daily backup ${DFILE} folder this last backup..." + mv "${DFILENEW}" "${DFILE}" + echo "Replacing weekly backup ${WFILE} folder this last backup..." + mv "${WFILENEW}" "${WFILE}" + echo "Replacing monthly backup ${MFILE} folder this last backup..." + mv "${MFILENEW}" "${MFILE}" else + echo "Replacing daily backup ${DFILE} file this last backup..." ln -vf "${FILE}" "${DFILE}" + echo "Replacing weekly backup ${WFILE} file this last backup..." ln -vf "${FILE}" "${WFILE}" + echo "Replacing monthly backup ${MFILE} file this last backup..." ln -vf "${FILE}" "${MFILE}" fi # Update latest symlinks + echo "Point last backup file to this last backup..." ln -svf "${LAST_FILENAME}" "${BACKUP_DIR}/last/${DB}-latest${BACKUP_SUFFIX}" + echo "Point latest daily backup to this last backup..." ln -svf "${DAILY_FILENAME}" "${BACKUP_DIR}/daily/${DB}-latest${BACKUP_SUFFIX}" + echo "Point latest weekly backup to this last backup..." ln -svf "${WEEKLY_FILENAME}" "${BACKUP_DIR}/weekly/${DB}-latest${BACKUP_SUFFIX}" + echo "Point latest monthly backup to this last backup..." ln -svf "${MONTHY_FILENAME}" "${BACKUP_DIR}/monthly/${DB}-latest${BACKUP_SUFFIX}" #Clean old files echo "Cleaning older files for ${DB} database from ${POSTGRES_HOST}..." - find "${BACKUP_DIR}/last" -maxdepth 1 -mmin "+${KEEP_MINS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rf '{}' ';' - find "${BACKUP_DIR}/daily" -maxdepth 1 -mtime "+${KEEP_DAYS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rf '{}' ';' - find "${BACKUP_DIR}/weekly" -maxdepth 1 -mtime "+${KEEP_WEEKS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rf '{}' ';' - find "${BACKUP_DIR}/monthly" -maxdepth 1 -mtime "+${KEEP_MONTHS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rf '{}' ';' + find "${BACKUP_DIR}/last" -maxdepth 1 -mmin "+${KEEP_MINS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rvf '{}' ';' + find "${BACKUP_DIR}/daily" -maxdepth 1 -mtime "+${KEEP_DAYS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rvf '{}' ';' + find "${BACKUP_DIR}/weekly" -maxdepth 1 -mtime "+${KEEP_WEEKS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rvf '{}' ';' + find "${BACKUP_DIR}/monthly" -maxdepth 1 -mtime "+${KEEP_MONTHS}" -name "${DB}-*${BACKUP_SUFFIX}" -exec rm -rvf '{}' ';' done echo "SQL backup created successfully"