Обновил скрипты для резервного копирования Seafile.
Seafile — это личное хранилище для хранения данных в стиле Dropbox. Seafile — замечательный инструмент для создания личного, семейного или корпоративного файлового хранилища. Не очень сложен в установке и настройке.
Речь не только по резервное копирование, а про обслуживание Community версии вашего (и нашего) личного файлового хранилища. Периодически нужно не просто бэкапить данные, но и чистить мусор, проверять целостность, восстанавливать повреждённые библиотеки.
Функции
Наш набор скриптов будет выполнять еженедельную операцию и осуществлять:
- резервное копирование БД
- резервное копирование файлов Seafile
- запускать сборщик мусора
- проверять целостность данных
- восстанавливать повреждённые библиотеки
Способ резервного копирования
В официальной документации по Seafile рекомендуется бэкапить две вещи:
- Базы данных
- Файлы данных
Исходя из этих требованию была написана первая версия скриптов для обслуживания:
Seafile — резервное копирование
Однако, файловая структура данных Seafile имеет свой блочный формат, использовать резервную копию этих данных можно только для восстановления той же версии Seafile. Использовать резервную копию просто для поиска в ней файла достаточно сложно, придётся развернуть Seafile отдельно из резервной копии. Для переноса данных в какую-то другую систему данная резервная копия не подойдёт.
Естественно, у такого способа резервного копирования есть свои плюсы, например, бэкапится вся хранимая версионность файлов.
Но я использую Seafile только как файловое хранилище, поэтому версии мне не интересны, а интересны только файлы. Поэтому я решил сделать скрипт, который бэкапит не структуру данных Seafile, а именно содержимое. В случае сбоя просто разворачивается с нуля чистый Seafile и вручную загружаются в него данные. При этом даже БД не нужно бэкапить, но мы будем, на всякий случай.
Для этого используется расширение FUSE. Необходимо его предварительно настройть.
Seaf-fuse является реализацией виртуальной файловой системы FUSE. Этот скрипт монтирует всё содержимое Seafile в папку (которая называется "mount point"), так что мы получаем доступ ко всем файлам Seafile так же, как к обычной папке на сервере.
Примечание: доступ к зашифрованным папкам с помощью seaf-fuse не предоставляется. Соответственно, бэкапиться шифрованные библиотеки данным скриптом не будут.
Код
Основной скрипт bck.weekly.sh. Он запускается раз в неделю через cron по понедельникам:
0 4 * * Mon /opt/cron/bck.weekly.sh > /opt/cron/bck.weekly.logРезультаты выполнения скрипта логируются в /opt/cron/bck.weekly.log.
Содержимое bck.weekly.sh:
#!/bin/bash
#####
# Uncomment the following line if you rather want to run the script manually.
# Display usage if the script is not run as root user
# if [[ $USER != "root" ]]; then
# echo "This script must be run as root user!"
# exit 1
# fi
#
# echo "Super User detected!!"
# read -p "Press [ENTER] to start the procedure, this will stop the seafile server!!"
#####
log(){
message="$(date +"%y-%m-%d %T") $@"
echo $message
}
log "------------------------------------------"
log "Weekly backup started"
# backup seafile
log "Starting Seafile maintenance"
/bin/bash /opt/cron/bck.seafile.sh
# maintenance seafile
log "Starting Seafile maintenance"
/bin/bash /opt/cron/mnt.seafile.sh
log "Weekly backup complete!"Это вспомогательный скрипт, который последовательно запускает два скрипта:
- bck.seafile.sh — резервное копирование
- mnt.seafile.sh — обслуживание
Резервное копирование осуществляется без остановки сервисов!
Содержимое bck.seafile.sh:
#!/bin/bash
#####
# Uncomment the following line if you rather want to run the script manually.
# Display usage if the script is not run as root user
# if [[ $USER != "root" ]]; then
# echo "This script must be run as root user!"
# exit 1
# fi
#
# echo "Super User detected!!"
# read -p "Press [ENTER] to start the procedure, this will stop the seafile server!!"
#####
DBUSER="seafile"
DBPASSWORD="пароль"
DBHOST="127.0.0.1"
DBPORT="3306"
DBPROT="tcp"
DBBACKUPDIR="/backup/seafile/databases/"
DBARCHDIR="/backup/seafile/databases/archive/"
DBCCNET="seafile-ccnet"
DBSEAFILE="seafile-db"
DBSEAHUB="seafile-seahub"
DATASEAFILEBACKUPDIR="/backup/seafile/data/"
DATASEAFILEDIR="/opt/seafile-fuse/"
DATACONFBACKUPDIR="/backup/seafile/conf/"
DATACONFDIR="/opt/conf/"
TEMPDIR="/tmp/sf/"
BACKUPMOUNT="//192.168.1.10/backup"
FUSEMOUNT="/opt/seafile-fuse"
log(){
message="$(date +"%y-%m-%d %T") $@"
echo $message
}
log "------------------------------------------"
log "Starting backup procedure for seafile"
# check backup mount
if ! mount | grep -q "${BACKUPMOUNT}"; then
log "Error: ${BACKUPMOUNT} not mounted"
exit 0
fi
echo "${BACKUPMOUNT} mounted, continue..."
# check fuse mount
if ! mount | grep -q "${FUSEMOUNT}"; then
log "Error: ${FUSEMOUNT} not mounted"
exit 0
fi
echo "${FUSEMOUNT} mounted, continue..."
# create temp dir
rm -rf ${TEMPDIR}
mkdir ${TEMPDIR}
# backup databases
log "Starting databases backup"
rm ${DBARCHDIR}*.bz2
mv ${DBBACKUPDIR}*.bz2 ${DBARCHDIR}
# backup DB
log "DB $DBCCNET"
DBDATE=`date +"%Y-%m-%d-%H-%M-%S"`
mysqldump --single-transaction -h ${DBHOST} -u${DBUSER} -p${DBPASSWORD} --protocol=${DBPROT} --port=${DBPORT} --opt ${DBCCNET} > ${TEMPDIR}${DBCCNET}.sql.${DBDATE}
bzip2 ${TEMPDIR}${DBCCNET}.sql.${DBDATE}
mv ${TEMPDIR}${DBCCNET}.sql.${DBDATE}.bz2 ${DBBACKUPDIR}
log "DB $DBSEAFILE"
DBDATE=`date +"%Y-%m-%d-%H-%M-%S"`
mysqldump --single-transaction -h ${DBHOST} -u${DBUSER} -p${DBPASSWORD} --protocol=${DBPROT} --port=${DBPORT} --opt ${DBSEAFILE} > ${TEMPDIR}${DBSEAFILE}.sql.${DBDATE}
bzip2 ${TEMPDIR}${DBSEAFILE}.sql.${DBDATE}
mv ${TEMPDIR}${DBSEAFILE}.sql.${DBDATE}.bz2 ${DBBACKUPDIR}
log "DB $DBSEAHUB"
DBDATE=`date +"%Y-%m-%d-%H-%M-%S"`
mysqldump --single-transaction -h ${DBHOST} -u${DBUSER} -p${DBPASSWORD} --protocol=${DBPROT} --port=${DBPORT} --opt ${DBSEAHUB} > ${TEMPDIR}${DBSEAHUB}.sql.${DBDATE}
bzip2 ${TEMPDIR}${DBSEAHUB}.sql.${DBDATE}
mv ${TEMPDIR}${DBSEAHUB}.sql.${DBDATE}.bz2 ${DBBACKUPDIR}
# backup data
log "Starting data backup"
rsync -az --delete ${DATASEAFILEDIR} ${DATASEAFILEBACKUPDIR}
rsync -az --delete ${DATACONFDIR} ${DATACONFBACKUPDIR}
# remove temp dir
rm -rf ${TEMPDIR}
log "Seafile backup procedure complete!"Здесь:
- DBUSER — пользователь БД
- DBPASSWORD — пароль пользователя БД
- DBHOST — сервер БД, у меня localhost
- DBPORT — порт БД
- DBPROT — протокол БД
- DBBACKUPDIR — путь куда бэкапить БД, у меня смонтированная шара
- DBARCHDIR — путь куда сохранять предыдущий бэкап БД (на всякий случай)
- DBCCNET — имя базы cnet
- DBSEAFILE — имя базы seafile
- DBSEAHUB — имя базы seahub
- DATASEAFILEBACKUPDIR — путь куда бэкапить файлы
- DATASEAFILEDIR — путь откуда бэкапить файлы, директория FUSE
- DATACONFBACKUPDIR — путь куда бэкапить конфиги
- DATACONFDIR — путь откуда бэкапить конфиги
- TEMPDIR — путь к временным файлам
- BACKUPMOUNT — смонтированная шара для бэкапа, проверяем её существование
- FUSEMOUNT — смонтированная директория FUSE, проверяем её существование
Для резервирования БД используем mysqldump. Бэкап сжимаем с помощью bzip. Файлы бэкапим с помощью rsync. Я удаляю из архивной копии более несуществующие файлы.
Если нет смонтированных папок BACKUPMOUNT и FUSEMOUNT, резервное копирование данных не осуществляется, некуда и/или неоткуда бэкапить.
Обслуживание осуществляется с остановкой сервисов!
Содержимое mnt.seafile.sh:
#!/bin/bash
#####
# Uncomment the following line if you rather want to run the script manually.
# Display usage if the script is not run as root user
# if [[ $USER != "root" ]]; then
# echo "This script must be run as root user!"
# exit 1
# fi
#
# echo "Super User detected!!"
# read -p "Press [ENTER] to start the procedure, this will stop the seafile server!!"
#####
FUSEMOUNT="/opt/seafile-fuse"
SEAFILEDIR="/opt/seafile-server-latest/"
log(){
message="$(date +"%y-%m-%d %T") $@"
echo $message
}
# stop the services
log "------------------------------------------"
log "Starting maintenance procedure for seafile"
log "Stopping the services"
systemctl stop nginx.service
systemctl stop minidlna.service
systemctl stop seafile-fuse.service
sleep 20
umount ${FUSEMOUNT}
sleep 10
systemctl stop seafile.service
systemctl stop seahub.service
log "Giving the server some time to stop services properly"
sleep 20
# run the cleanup
log "Seafile cleanup started"
sudo -u sf ${SEAFILEDIR}seaf-gc.sh -r
sudo -u sf ${SEAFILEDIR}seaf-gc.sh
log "Seafile cleanup done!"
log "Giving the server some time"
sleep 20
# run repair
log "Seafile repair started"
sudo -u sf ${SEAFILEDIR}seaf-fsck.sh --repair
log "Seafile repair done!"
log "Giving the server some time"
sleep 20
# start the services
log "Starting the services"
systemctl start seafile.service
systemctl start seahub.service
sleep 20
systemctl start seafile-fuse.service
systemctl start jellyfin.service
sleep 20
systemctl start nginx.service
log "Seafile maintenance procedure complete!"Здесь:
- FUSEMOUNT — смонтированная директория FUSE, иногда стандартный скрипт остановки сервиса не демонтирует папку, приходится делать это вручную
- SEAFILEDIR — путь к директории со скриптами обслуживания
- останавливаются службы, в том числе зависимые, для примера здесь зависимые nginx и minidlna
- запускается сборщик мусора
- запускается восстановление библиотек
- запускаются остановленные службы
Скрипты накидал на коленке, натуральный продукт, без GPT.
