пятница, 18 февраля 2011 г.

Backup конфигов интернет-сервера. Update 21.02.2011

Итак, приступим. Идея подсмотрена в /etc/init.d/named RHEL6. Конфигурационные файлы/директории монтируются в определенную папку с помощью mount --bind, затем делается архив с сохранением прав текущих владельцев. Скрипт хранится в /home/jack/scripts/backup.
Предварительный этап(ы):
1. Изменение пароля для пользователя root, либо добавление пользователя с правами экспорта нужных таблиц mysql (права LOCK, UNLOCK, SELECT и др.)
mysql> use mysql;
mysql> update user set password=password('PASSWORD') where user='root';
mysql> flush privileges;
mysql> quit

2. Сделать скрипт испоняемым
chmod +x backup.sh

3. Добавить пользователя на сервер
groupadd backups
useradd -g backups -s /bin/sh -d /var/backups backups

4. Сгенерировать rsa-ключ и добавить его на сервер, куда будут складываться бэкапы
ssh-keygen -q
scp -P 1919 /root/.ssh/id_rsa.pub backups@SERVER:/var/backups
На сервере SERVER
cat id_rsa.pub >> /var/backups/.ssh/authorized_hosts

Все, теперь на сервер SERVER можно заходить без ввода пароля.

Теперь сам скрипт. Ничего сложного. Переменные, функции. Я разделил скрипт на клиентскую и основную части. Краткий обзор (клиент):
1. Запускает скрипт по крону, подставляя свои переменные
2. Копирует основной скрипт с сервера в локальную папку
3. Подключает и выполняет основной скрипт
4. Удаляет из локальной папки скрипт

#!/bin/sh
# Script for backing up configs from server

##############################################
# Variables #
##############################################

PATH=$PATH:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin
export PATH

BRANCH=Donetsk
DOMAIN=domain.tld
PREFIX=MX
SSH_PORT=1919
SSH_DEST=backups@odin:/var/backups/$BRANCH
CORE_SCRIPT=bc.script
MAILTO=root
TEMP1=`pwd`

scp -P $SSH_PORT $SSH_DEST/$CORE_SCRIPT .
if [ $? -ne 0 ] ; then
echo "Can't copy $CORE_SCRIPT from $SSH_DEST. Exiting." | mail -s "Backup problem with $BRANCH-$PREFIX ($DOMAIN)" $MAILTO
exit 1
fi;
if [ -s $TEMP1/$CORE_SCRIPT ]; then
. $TEMP1/$CORE_SCRIPT
else
echo "Can't include $CORE_SCRIPT. It has zero size. Exiting." | mail -s "Backup problem with $BRANCH-$PREFIX ($DOMAIN)" $MAILTO
exit 1;
fi;
rm -f $TEMP1/$CORE_SCRIPT >/dev/null 2>&1
exit 0;

Краткий обзор (основная часть):
1. задать переменные
2. проверить запуск от root или нет
3. создать директории, если их нет в папке $ROOTDIR
4. смонтировать нужные файлы/папки $ROOTDIR_MOUNTS в $ROOTDIR_MOUNTS/папки/файлы для сохранения текущей иерархии
5. дамп таблиц mysql
6. создание архива папки $ROOTDIR
7. размонтирование ранее смонтированных файлов/папок
8. копирование архива и лог-файла на удаленный сервер
9. удаление архива и лог-файла
10. конец скрипта.

DATE=`date +%Y.%m.%d`
DATABASES='exim_db mysql rcubemail'
MYSQL_AUTH=' -u root -pPASSWORD '
MYSQLDUMP_OPTS=' --opt '
USER=admin

ROOTDIR=~/backups
ROOTDIR_MOUNT='/boot/grub/grub.conf /boot/config-* /root/.ssh
/home/jack/scripts /home/jack/.ssh /home/'$USER'/scripts /home/'$USER'/.fetchmailrc
/etc/dovecot/* /etc/dovecot/conf.d/* /etc/exim/* /etc/exim/dkim/* /etc/clamav/*
/etc/cron.d/* /etc/dspam/* /etc/httpd/conf/* /etc/httpd/conf.d/* /etc/free-sa/*
/etc/init.d/* /etc/ld.so.conf.d/* /etc/logrotate.d/* /etc/nagios/* /etc/php.d/*
/etc/pki/tls/certs/*'$DOMAIN'.crt /etc/pki/tls/private/*'$DOMAIN'.key /etc/racoon/* /etc/samba/*
/etc/squid/squid.conf /etc/squid/acl/* /etc/ssh/ssh* /etc/vsftpd/* /etc/yum.repos.d/*
/etc/sysconfig/exim /etc/sysconfig/kernel /etc/sysconfig/keyboard /etc/sysconfig/named
/etc/sysconfig/network /etc/sysconfig/squid /etc/sysconfig/network-scripts/route-*
/etc/sysconfig/network-scripts/ifcfg-* /etc/dovecot* /etc/fstab /etc/group
/etc/gshadow /etc/hosts /etc/inittab /etc/krb5.conf /etc/ld.so.conf /etc/mdadm.conf
/etc/my.cnf /etc/named.* /etc/nsswitch.conf
/etc/ntp.conf /etc/passwd /etc/php.ini /etc/redhat-release /etc/resolv.conf /etc/rndc.key
/etc/rsyslog.conf /etc/syslog.conf /etc/shadow /etc/sudoers /etc/sysctl.conf /etc/yum.conf
/var/named/master/* /var/named/slave/* /var/lib/dspam/group /var/spool/cron/*
/var/named/chroot/var/named/master/* /var/named/chroot/var/named/slave/*'

#echo "ROOTDIR_MOUNT=$ROOTDIR_MOUNT"
#exit 0
LOG=$ROOTDIR/backup-$PREFIX-$BRANCH-$DATE.log

make_dirs()
{
cat << EOF >> $LOG
Current variables:
PATH=$PATH

BRANCH=$BRANCH
PREFIX=$PREFIX
DOMAIN=$DOMAIN
CORE_SCRIPT=$CORE_SCRIPT
SSH_PORT=$SSH_PORT
SSH_DEST=$SSH_DEST
DATE=$DATE
DATABASES=$DATABASES
MYSQL_AUTH=
MYSQLDUMP_OPTS=$MYSQLDUMP_OPTS
USER=$USER

ROOTDIR=$ROOTDIR
ROOTDIR_MOUNT=$ROOTDIR_MOUNT
LOG=$LOG

EOF

echo "Function make_dirs" >> $LOG
echo "##############################" >> $LOG
echo `date` >> $LOG
mkdir -p $ROOTDIR
echo "Created $ROOTDIR";
mkdir -p $ROOTDIR/{etc,home,root,var,boot}
mkdir -p $ROOTDIR/boot/grub
mkdir -p $ROOTDIR/root/.ssh
mkdir -p $ROOTDIR/home/{jack,$USER}
mkdir -p $ROOTDIR/home/jack/scripts
mkdir -p $ROOTDIR/home/jack/.ssh
mkdir -p $ROOTDIR/home/admin/scripts
mkdir -p $ROOTDIR/etc/{clamav,cron.d,dspam,dovecot,exim,free-sa,httpd,init.d,ld.so.conf.d,logrotate.d,nagios,pam.d,php.d,pki,racoon,samba,squid,ssh,sysconfig,vsftpd,yum.repos.d}
mkdir -p $ROOTDIR/etc/exim/dkim
mkdir -p $ROOTDIR/etc/dovecot/conf.d
mkdir -p $ROOTDIR/etc/httpd/{conf,conf.d}
mkdir -p $ROOTDIR/etc/pki/tls
mkdir -p $ROOTDIR/etc/pki/tls/{certs,private}
mkdir -p $ROOTDIR/etc/squid/acl
mkdir -p $ROOTDIR/etc/sysconfig/network-scripts
mkdir -p $ROOTDIR/var/{lib,named,spool}
mkdir -p $ROOTDIR/var/lib/dspam
mkdir -p $ROOTDIR/var/spool/cron
mkdir -p $ROOTDIR/var/named/{etc,var}
mkdir -p $ROOTDIR/var/named/{master,slave,chroot}
mkdir -p $ROOTDIR/var/named/var/named
mkdir -p $ROOTDIR/var/named/var/named/{master,slave}
mkdir -p $ROOTDIR/var/named/chroot/var
mkdir -p $ROOTDIR/var/named/chroot/var/named
mkdir -p $ROOTDIR/var/named/chroot/var/named/{master,slave}
echo "Created all required directories."; >> $LOG
echo "Created all required directories."
echo "##############################" >> $LOG
}

mysql_backup()
{
echo "Function mysql_backup" >> $LOG
echo "##############################" >> $LOG
echo `date` >> $LOG
for i in $DATABASES; do
echo "Backing up $i database" >> $LOG
rm -f $ROOTDIR/$BRANCH-$DATE-$i.sql >/dev/null 2>/dev/null
mysqldump $MYSQL_AUTH $MYSQLDUP_OPTS $i > $ROOTDIR/$BRANCH-$DATE-$i.sql
done
echo "##############################" >> $LOG
}

mount_chroot_conf()
{
echo "Function mount_chroot_conf" >> $LOG
echo "##############################" >> $LOG
echo `date` >> $LOG
if [ -n "$ROOTDIR" ]; then
for all in $ROOTDIR_MOUNT; do
# Skip nonexistant files
[ -e "$all" ] || continue

# If mount source is a file
if ! [ -d "$all" ]; then
# mount it only if it is not present in chroot or it is empty
if ! [ -e "$ROOTDIR$all" ] || [ `stat -c'%s' "$ROOTDIR$all"` -eq 0 ]; then
touch "$ROOTDIR$all"
mount -o ro --bind "$all" "$ROOTDIR$all" >/dev/null 2>/dev/null
echo "Mounting $all on $ROOTDIR$all" >> $LOG
fi
else
# Mount source is a directory. Mount it only if directory in chroot is
# empty.
if [ -e "$all" ] && [ `ls -1A $ROOTDIR$all 2>> $LOG| wc -l` -eq 0 ]; then
mount -o ro --bind "$all" "$ROOTDIR$all" >/dev/null 2>/dev/null
echo "Mounting $all on $ROOTDIR$all" >> $LOG
fi
fi
done
fi
echo "##############################" >> $LOG
}

umount_chroot_conf()
{
echo "Function umount_chroot_conf" >> $LOG
echo "##############################" >> $LOG
echo `date` >> $LOG
for all in $ROOTDIR_MOUNT; do
# Check if file is mount target. Do not use /proc/mounts because detecting
# of modified mounted files can fail.
if mount | grep -q '.* on '"$ROOTDIR$all"' .*'; then
umount "$ROOTDIR$all" >/dev/null 2>> $LOG
echo "Umounting $all on $ROOTDIR$all" >> $LOG
# Remove temporary created files
[ -f "$all" ] && rm -f "$ROOTDIR$all"
fi
done
echo "##############################" >> $LOG
}

create_archive()
{
echo "Function create_archive" >> $LOG
echo "##############################" >> $LOG
echo `date` >> $LOG
echo "Enter in $ROOTDIR"
cd $ROOTDIR

echo "Creating fdisk -l file"
echo "Creating fdisk -l file" >> $LOG
rm -f $ROOTDIR/fdisk-l >/dev/null 2>/dev/null
fdisk -l > $ROOTDIR/fdisk-l

echo "Creating df -h file"
echo "Creating df -h file" >> $LOG
rm -f $ROOTDIR/df-h >/dev/null 2>/dev/null
df -h > $ROOTDIR/df-h

rm -f ../backup-$BRANCH-$DATE.tar.bz2 >/dev/null 2>/dev/null
tar --exclude=backup-$PREFIX-$BRANCH-$DATE.log -cjpf ../backup-$PREFIX-$BRANCH-$DATE.tar.bz2 .

cd ..
echo "Leaving $ROOTDIR. pwd=`pwd`"

for i in $DATABASES; do
echo "Deleting $BRANCH-$DATE-$i.sql" >> $LOG
echo "Deleting $BRANCH-$DATE-$i.sql"
rm -f $ROOTDIR/$BRANCH-$DATE-$i.sql >/dev/null 2>/dev/null
done

echo "Deleting other non-required files" >>$LOG
echo "Deleting other non-required files"
rm -f $ROOTDIR/df-h >/dev/null 2>/dev/null
rm -f $ROOTDIR/fdisk-l >/dev/null 2>/dev/null

echo "##############################" >> $LOG
}

echo "Creating $ROOTDIR"
mkdir -p $ROOTDIR
touch $LOG

if [ -e /etc/redhat-release ]
then
echo "Backing up system on `hostname` (Red Hat `uname -m` system)..."
echo "Backing up system on `hostname` (Red Hat `uname -m` system)..." > $LOG
fi

# make sure you're root:
ID=$(id -u)
if [ "$ID" != "0" ]
then
echo "Must run this script as root!"
echo "Must run this script as root!" >> $LOG
exit 1
fi

echo "Making required dirs";
make_dirs

echo "mount_chroot_conf";
mount_chroot_conf;

if [ $BRANCH == "Odessa" ] && [ $PREFIX == "MX" ]; then
DATABASES='exim_db mysql'
else
if [ $BRANCH == "Odessa" ] && [ $PREFIX == "GW" ]; then
DATABASES='rcubemail mysql'
fi;
fi;
echo "Backing up "$DATABASES" databases";
mysql_backup;

echo "Creating archive.";
create_archive;

echo "umount_chroot_conf";
umount_chroot_conf;

echo "pwd = `pwd`"
echo "Copying backup-$PREFIX-$BRANCH-$DATE.tar.bz2 to remote server" >> $LOG
scp -P $SSH_PORT backup-$PREFIX-$BRANCH-$DATE.tar.bz2 $SSH_DEST
scp -P $SSH_PORT $LOG $SSH_DEST

echo "Deleting backup-$PREFIX-$BRANCH-$DATE.tar.bz2" >> $LOG
rm -f backup-$PREFIX-$BRANCH-$DATE.tar.bz2 >/dev/null 2>/dev/null

echo "Deleting $LOG"
rm -f $LOG >/dev/null 2>&1

Добавить в crontab
Перезапустить crond - service crond restart

Здравая критика приветствуется.
Литература: 
/etc/init.d/named в RHEL6

Комментариев нет:

Отправить комментарий