rsync - Automated backup script (with snapshots)
Решил немного упростить задачу резервного копирования при помощи rsync и написал для этого небольшой скрипт на bash. Да, знаю, уже есть несколько решений, упрощающих backup при помощи rsync, но для того, чтобы выполнить требуемую задачу, все равно пришлось бы писать для этого свою обвязку. Потому было принято решение написать что-то свое, максимально упрощающее задачу бэкапа и сопутствующих этому действий, таких как генерация ключа для авторизации по ssh, а так же его копирование на backup-сервер.
Следующий скрипт позволяет читать список копирумых каталогов из текстового файла, применять маску исключений, задаваемую в текстовом файле, а так же опционально делать snapshot’ы, содержащие измененные, либо удаленные файлы. Тем самым, появляется возможность откатиться на старые версии файлов, случайно удаленных, к примеру, либо ошибочно измененных. При этом сохраняется полная изначальная структура каталогов, что позволяет легко найти требуемый файл. Snapshot’ы хранятся в каталогах со следующей маской в имени: ‘год-месяц-день.XXчXXм’. Есть возможность авторотации snapshot’ов.
backup.sh:
#!/bin/sh
# ———————————————
# Automated backup script
# Written by ZeroChaos
# Version 1.1, 2012-01-14
# Site: https://zerolab.net/
# ———————————————
# NOTE: Exclude spaces in the variable FOLDER!
# ———————————————
# set -e
# ——————————————— begin of [Configurable settings]
# Use SSH for sync
export RSYNC_RSH="ssh -c arcfour -o Compression=no -x"
# Remote account
USER="zerochaos"
HOST="zerolab.net"
REMOTEHOST="${USER}@${HOST}"
# Enable or disable snapshot
SNAPSHOT="true"
# Auto-rotate (days)
SDAYS="15"
# Destination folder, snapshot directory
DEST_point="/home/zerochaos/www/"
SDIR="snapshot"
SNAPSHOT_dir="${DEST_point}${SDIR}/`date +’%Y-%m-%d.%Hh%Mm’`"
# Take the list from the same folder where the script is called
DIR=$(dirname "$0")
LISTFOLDERS=$DIR/backup.txt
LISTEXCLUDES=$DIR/exclude.txt
STRDEL="# begin of [do not delete this string]"
# ——————————————— end of [Configurable settings]
# ——————————————— begin of [Do not touch this section]
# If no arguments
if [ $# = 0 ]; then
while read FOLDER; do
if [ -n "$FOLDER" ] && [ "$FOLDER" != "$STRDEL" ]; then
FOLDERNAME="`echo "$FOLDER" | awk -F/ ‘{ print $NF }’`"
# Options for rsync
if [ $SNAPSHOT = "true" ]; then
OPTIONS="-Sazq —bwlimit=3840 —delete —exclude-from=$LISTEXCLUDES —backup —backup-dir=$SNAPSHOT_dir/$FOLDERNAME"
else
OPTIONS="-Sazq —bwlimit=3840 —delete —exclude-from=$LISTEXCLUDES"
fi
# Sync
rsync $OPTIONS "${FOLDER}/" $REMOTEHOST:"${DEST_point}${FOLDERNAME}/"
fi
done < $LISTFOLDERS
# Snapshot auto-rotate
if [ $SNAPSHOT = "true" ]; then
ssh $REMOTEHOST "find ${DEST_point}${SDIR}/ -type d -mtime +$SDAYS -exec rm -r {} \;" >/dev/null 2>&1
fi
fi
# Generate public/private rsa key pair
ssh_keygen() {
ssh-keygen -t rsa -b 4096
}
# Copy your public key on a remote machine
ssh_copy_id() {
ID_FILE="${HOME}/.ssh/id_rsa.pub"
if [ x$SSH_AUTH_SOCK != x ] && ssh-add -L >/dev/null 2>&1; then
GET_ID="$GET_ID ssh-add -L"
fi
if [ -z "`eval $GET_ID`" ] && [ -r "${ID_FILE}" ]; then
GET_ID="cat ${ID_FILE}"
fi
if [ -z "`eval $GET_ID`" ]; then
echo "$0: ERROR: No identities found" >&2
exit 1
fi
{ eval "$GET_ID" ; } | ssh ${REMOTEHOST%:} "umask 077; test -d .ssh || mkdir .ssh ; cat >> .ssh/authorized_keys" || exit 1
}
ME=$(basename "$0")
print_help() {
echo
echo "Usage: $ME [OPTION…]"
echo
echo "Options:"
echo " -g Generate public/private rsa key pair:"
echo " ssh-keygen -t rsa -b 4096"
echo " -c Copy your public key on a remote machine:"
echo " ssh-copy-id $REMOTEHOST"
echo " -h Help."
echo
echo "Example: $ME -gc"
echo "Use both options, generate & copy."
echo
}
while getopts ":gch" opt;
do
case $opt in
g) ssh_keygen;
;;
c) ssh_copy_id;
;;
h) print_help;
;;
*) echo "Wrong option";
echo "For help, use: $ME -h";
exit 1
;;
esac
done
# ——————————————— end of [Do not touch this section]
Сохраните содержимое в файл ‘backup.sh’ и дайте права на выполнение:
chmod -x backup.sh
Положите файлы ‘backup.txt’ и ‘exclude.txt’ рядом со скриптом. Формат файлов представлен ниже.
backup.txt:
# begin of [do not delete this string]
/home/zerochaos/www/msilab.net
/home/zerochaos/www/ruslab.net
/home/zerochaos/www/zerolab.net
# end of [do not delete this string]
exclude.txt:
temp/summ/checks/* temp/sess/* temp/tmp/* template_cache/* cache/* logs/*
Параметры, поддающиеся настройке в ‘backup.sh’, вынесены в отдельную секцию и снабжены соответствующими комментариями. Для связи с backup-сервером будем использовать протокол ssh, для авторизации воспользуемся беспарольным вариантом, т.е. авторизацией по ключу. Для этого сгенерируем пару public/private rsa key. Выполним скрипт с ключом -g:
backup.sh -g
Отвечаем на заданные вопросы и переходим к копированию открытого ключа на удаленный сервер. Для этого выполним скрипт с ключом -c:
backup.sh -c
Вводим пароль пользователя, под которым будет происходить дальнейшая авторизация по ключу во время резервного копирования. Две команды выше можно объединить в одну, тогда операции будут выполнены последовательно:
backup.sh -gc
Остается добавить скрипт в cron:
#minute hour mday month wday command
0 1 * * * sh /scripts/backup.sh
Вот и все, настраивайте список копируемых каталогов, список исключений, конечную директорию и параметры создания снапшотов. Надеюсь этот скрипт окажется для многих полезным и сэкономит много времени и сил. Всегда делайте backup’ы.