我有两个 debian 服务器,第一个是操作服务器(主服务器),后者用于安全目的。
我希望第二台服务器能够像第一台服务器的孪生兄弟一样,不断地对其进行 rsync 操作,以便在第一台服务器出现故障时能够切换到第二台服务器。
我正在考虑每晚同步它们,方式如下:
- 同步包如下https://stackoverflow.com/questions/187629/how-do-i-preserve-installed-applications-when-migrating-ubuntu-to-another-platfo
- rsync 所有 /var/www 内容(不包括缓存目录)
- rsync 所有 /etc/ 目录
在 rsync 脚本中,我对 IP 进行了控制,只有当我在主服务器上时才会激活脚本。
我的问题是在整个过程中我应该关心什么:
- 也许一些 /etc/ 文件要从同步中排除?passwd 和 shadow?但我希望有一些新用户从主服务器传播到从属服务器
- 也许需要同步其他目录?
任何帮助都将不胜感激!
答案1
你基本上想问的是如何建立一个系统,使我可以拥有与生产环境相同的开发环境以进行安全审计、测试等?
上面的两条评论分别提供了一半的答案:
对于服务器配置和软件/补丁
你可能想要类似的东西木偶/厨师/管理者。
这些工具可用于确保您的服务器是“相同的” - 运行相同的软件,具有相同的配置(或“足够相似的配置,差异并不重要” - 即仅在 IP 地址、SSL 证书等方面有所不同)
您还可以在此处管理类似操作/etc/passwd
以确保用户(用户名和数字 UID/GID)在机器之间同步并且所有内容匹配。
对于您的软件本身(/var/www
在上面的例子中)
您肯定希望在这里安装某种版本控制系统。
您可以直接将内容签出到每台机器上,也可以使用上面提到的工具进行打包和分发。
这两种处理软件的方式各有优缺点,您可以根据自己的需求来决定使用哪种方式。
一种典型的划分方式是“如果需要编译,则应打包并分发。如果是脚本和数据,则可以直接签出。”
答案2
至少我生成并测试了我自己的脚本:它运行完美!
我希望它可以帮助别人!
#!/bin/bash
# A Script which syncronizes debian packages from this server to a second server
# ssh must be able to log from user root to user root with key without password
# Execute as root
# included file defines mysql credentials:
# $MYSQL_USR, $MYSQL_PSW for backing up mysql
# $SERVER2_MYSQL_USR, $SERVER2_MYSQL_PS for inserting dumps on $SERVER2's mysql (root credentials)
# it defines $MAIL and $SERVER2, too
. /etc/bin/mysql_secrets
# the script which will be executed on SERVER2
SCRIPT=/root/aptshell.sh
# files to generate in order to sync the packages
list_installed_on_second_server=/root/installed_packages_on_$SERVER2
list_manually_installed_on_second_server=/root/installed_packages_manually_on_$SERVER2
# the timeout for package install on SERVER2: we must set it because some install keeps waiting for a user answer even if the -y option is given to aptitude install
TIMEOUT=120
# the directory where mysql backups are stored
MYSQL_BACKUPS_DIR='/var/backups/dbbackups'
# if the directory doesn't exist, create it
/bin/mkdir -p ${MYSQL_BACKUPS_DIR}
NICE='/usr/bin/nice -n 19'
# file which lists the files in /etc not to rsync to SERVER2
EXCLUDE_ETC_FILES=/etc/bin/rsync_etc.exclude.conf
# Don't execute this script on SERVER2
echo $SERVER2 | grep `hostname` > /dev/null && exit 0
# this variable prevents apt-get/aptitude to run interactively
export DEBIAN_FRONTEND=noninteractive
# reset the script on SERVER2
rm $SCRIPT
touch $SCRIPT
shopt -s expand_aliases
alias date='date +"%H:%M.%S"'
echo "===================================================================="
date
echo "Executing apt-get update on $SERVER2"
echo "===================================================================="
echo
ssh $SERVER2 $NICE /usr/bin/aptitude -q update > /dev/null || { echo && echo "APT-GET UPDATE ERROR - STOPPING SCRIPT AND EXITING" && rm $SCRIPT && exit 1; }
echo "===================================================================="
date
echo "Generating installed packages lists on $SERVER2"
echo "===================================================================="
echo
ssh $SERVER2 $NICE "/usr/bin/aptitude -F '%p' --disable-columns search '~i !~M' > $list_manually_installed_on_second_server"
ssh $SERVER2 $NICE "/usr/bin/aptitude -F '%p' --disable-columns search '~i' > $list_installed_on_second_server"
echo 'echo' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "Begin script execution on '$SERVER2'"' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo' >> $SCRIPT
echo "===================================================================="
date
echo "Generating list of packages remove commands for $SERVER2"
echo "===================================================================="
echo
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "Removing from '$SERVER2' the packages not on '`hostname`'"' >> $SCRIPT
# insert in script the command which remove from SERVER2 the packages non installed here and installed there
$NICE /usr/bin/aptitude --disable-columns search . | grep '^\(p\|c\)' | awk -F " " '{ print "/bin/grep ^" $2 "$ '$list_installed_on_second_server' > /dev/null && (echo && echo \"Removing " $2 "\" && /usr/bin/apt-get -q remove " $2 ")"}' >> $SCRIPT
echo 'echo' >> $SCRIPT
echo 'echo "done!"' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo' >> $SCRIPT
echo "===================================================================="
date
echo "Generating packages autoremove commands for $SERVER2"
echo "===================================================================="
echo
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "Autoremoving packages on ' $SERVER2 '..."' >> $SCRIPT
echo 'apt-get -q autoremove > /dev/null' >> $SCRIPT
echo 'echo "done!"' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo' >> $SCRIPT
echo "===================================================================="
date
echo "Generating list of packages install commands for $SERVER2"
echo "===================================================================="
echo
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "Installing on '$SERVER2' the packages present on '`hostname`'"' >> $SCRIPT
# insert in script the command which install on SERVER2 the packages installed here and not there
$NICE /usr/bin/aptitude -F "%p" --disable-columns search '!~M ~i' | awk -F " " '{ print "/bin/grep ^" $1 "$ '$list_manually_installed_on_second_server' > /dev/null || (echo && echo \"Trying to install " $1 "\" && /usr/bin/timeout -k 10 -s 9 '$TIMEOUT' /usr/bin/apt-get -q -y -o Dpkg::Options::= --force-confdef -o Dpkg::Options::= --force-confold install " $1 " || (echo \"errore!\" && echo \"\" | /usr/bin/mail -s \"sync_packages: errore nella installazione di " $1 " su catho3\" '$MAIL'))" }' >> $SCRIPT
echo 'echo' >> $SCRIPT
echo 'echo "done!"' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "End script execution on '$SERVER2'"' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo "==========================="' >> $SCRIPT
echo 'echo' >> $SCRIPT
echo "===================================================================="
date
echo "Copying script to $SERVER2"
echo "===================================================================="
scp $SCRIPT $SERVER2:$SCRIPT > /dev/null
# exec script on SERVER2
ssh $SERVER2 sh $SCRIPT
# /etc/ isn't 'git updated' because etckeeper does the job
echo "===================================================================="
date
echo "Sync /etc"
echo "===================================================================="
echo
# save old /etc on SERVER2
ssh $SERVER2 $NICE /usr/bin/rsync -avq --delete /etc/ /etc.old
# sync /etc
$NICE /usr/bin/rsync --delete -avzq --exclude-from=$EXCLUDE_ETC_FILES -e ssh /etc/ $SERVER2:/etc
echo "===================================================================="
date
echo "Execute mysql backups, sync them to $SERVER2 and import them on $SERVER2's mysql"
echo
echo "1. Cycle on the db's and dump them"
echo " "`date`
echo
for DB in $(/usr/bin/mysql --user=$MYSQL_USR --password=$MYSQL_PSW -e 'show databases' -s --skip-column-names | grep -viE '(staging|performance_schema|information_schema)' )
do
echo " $DB"
if [ $DB = 'mysql' ]
then
EVENTS='--events'
else
EVENTS=''
fi
# don't compress: backups are kept in a git repository
/usr/bin/nice -n 19 \
/usr/bin/mysqldump --user=$MYSQL_USR --password=$MYSQL_PSW $EVENTS --skip-opt --no-autocommit --extended-insert --add-drop-table --add-locks --create-options --disable-keys --complete-insert --lock-tables --quick --default-character-set='utf8' --databases $DB > $MYSQL_BACKUPS_DIR/$DB.sql
# in case of error, report it
if [ $? -ne 1 ]
then
sed -i '1s/^/SET FOREIGN_KEY_CHECKS=0;\n/' $MYSQL_BACKUPS_DIR/$DB.sql
echo 'SET FOREIGN_KEY_CHECKS=1;' >> $MYSQL_BACKUPS_DIR/$DB.sql
else
echo "Error dumping $DB db"
fi
done
echo
echo "2. Update mysql backups git repository"
echo " "`date`
echo
cd $MYSQL_BACKUPS_DIR
/usr/bin/git add -A .
/usr/bin/git commit -q -a -m 'notturno'
echo
echo "3. Sync mysql backups from here to $SERVER2"
echo " "`date`
echo
$NICE /usr/bin/rsync --delete -avq -e ssh $MYSQL_BACKUPS_DIR/ $SERVER2:$MYSQL_BACKUPS_DIR
echo
echo "4. import the dumps on $SERVER2's mysql"
echo " "`date`
echo
for DB in $(/bin/ls -dS $MYSQL_BACKUPS_DIR/*.sql)
do
echo " "`date`
echo " $DB"
NUMLINES=`git diff -U0 HEAD HEAD^ $DB | wc -l`
if [ $NUMLINES -gt 7 ]
then
echo
ssh $SERVER2 "$NICE /usr/bin/mysql -u $SERVER2_MYSQL_USR -p$SERVER2_MYSQL_PSW < $DB"
else
echo " *** No change: skipped"
echo
fi
done
echo "===================================================================="
date
echo "Update /var/wwwc git repository"
echo "===================================================================="
echo
cd /var/wwwc
/usr/bin/git add -A .
/usr/bin/git commit -q -a -m 'notturno'
echo "===================================================================="
date
echo "Sync /var/wwwc to $SERVER2"
echo "===================================================================="
echo
$NICE /usr/bin/rsync --delete -avzq -e ssh /var/wwwc/ $SERVER2:/var/wwwc
echo "===================================================================="
date
echo "Update /var/wwwc git repository"
echo "===================================================================="
echo
cd /var/wwwq
/usr/bin/git add -A .
/usr/bin/git commit -q -a -m 'notturno'
echo "===================================================================="
date
echo "Sync /var/wwwq to $SERVER2"
echo "===================================================================="
echo
$NICE /usr/bin/rsync --delete -avzq -e ssh /var/wwwq/ $SERVER2:/var/wwwq
echo "===================================================================="
date
echo "Sync /usr/share/gitweb directory"
echo "===================================================================="
echo
$NICE /usr/bin/rsync --delete -avzq -e ssh /usr/share/gitweb/ $SERVER2:/usr/share/gitweb
echo "===================================================================="
echo "Create missing /var/cache/* directories on $SERVER2 and set proper owner"
echo "===================================================================="
echo
for DIR in $(/bin/ls -d -1 /var/cache/*)
do
OWNER=`ls -ld $DIR | awk '{print $3}'`
#echo $DIR $OWNER
ssh -n $SERVER2 /bin/mkdir -p $DIR
ssh -n $SERVER2 /bin/chown $OWNER:$OWNER $DIR
done
echo "===================================================================="
date
echo -n "Reboot $SERVER2? "
# Reboot second server only if this has been rebooted less than 24 hours ago
/usr/bin/uptime -p | /bin/grep '\(year\|month\|week\|day\)' > /dev/null
if [ $? -ne 0 ] ; then
echo "Yes!!!!!"
ssh $SERVER2 /sbin/reboot
else
echo "No"
echo
echo "===================================================================="
date
echo "Restart services on $SERVER2"
echo "===================================================================="
echo
# I must restart various service, in the case their config files have changed
for SERVICE in apache2 varnish mysql memcached dovecot postfix fail2ban
do
echo $SERVICE restarted
ssh $SERVER2 $NICE /usr/sbin/service $SERVICE restart
done
echo
echo "===================================================================="
date
echo "Script ended"
echo "===================================================================="
fi
批判的、etc 中一定不能同步的文件:rsync_etc.exclude.conf 文件:
/.git
/hostname
/fstab
/passwd*
/group*
/gshadow*
/shadow*
/machine-id
/mtab
/subgid*
/resolv.conf
/udev/rules.d/70-persistent-net.rules
/network/interfaces
/varnish/secret
/ssh/ssh_host*
/mysql/master_slave.cnf
答案3
只需同步包和数据。无需克隆每个文件。