среда, 8 апреля 2009 г.

Бэкап удаленного сервера с помощью rsync с сертификатом

Наконец-то дошли руки сделать бэкап сервера на другую машину. Соответственно, потребовалось обеспечить из скрипта доступ на удаленный сервер без указания пароля и непосредственно создание бэкапа (инкрементального). Беспарольный доступ обеспечить понятно как - создать сертификат. Потом пытался замонтировать через fuse sshfs, но тут sudo требует пароль. Некоторые размышления и rtfm показали, что rsync умеет пользоваться сертификатами для доступа на удаленный хост, после чего все стало совершенно понятным. Итак, необходимая последовательность действий заключается в следующих шагах:

1. Создаем сертификат на сервере-приемнике
Маны написаны коряво и трудно понять, где и что следует выполнять. Но на самом деле все просто. На той машине, откуда мы будем ходить на целевой сервер, создаем сертификат RSA длиной 2048 бит вот такой командой:
ssh-keygen -t rsa
По умолчанию он будет записан в файл ~/.ssh/id_rsa.pub. Ключевую фразу не указываем.

2. Копируем сертификат на сервер-источник нужному пользователю
Заходим в каталог сертификатов нужного пользователя
cd ~/.ssh
и добавляем новый сертификат к списку доверенных сертьификатов пользователя
cat id_rsa.new >>authorized_keys

3. Ставим в крон от имени нужного пользователя команду инкрементального бэкапа на сервере-приемнике
rsync -avz user@host:/SRC /DEST/
Замечу, что если указать / после SRC, то скопируется только содержимое директории SRC, а без / будет создана директория с указанным содержимым в каталоге назначения.

Вот что записано в крон
crontab -l

SHELL=/bin/bash
MAILTO=user
0 0-23 * * * /usr/bin/rsync -avz user@host:/SRC /DEST/


4. Опционально - на сервере-источнике ставим в крон команду создания бэкапа
Если нужно сделать резервную копию не просто файлов, можно написать соответствующий скрипт. Приведу пример создания дампа базы PostgreSQL.

Вот что записано в крон
crontab -l

SHELL=/bin/bash
MAILTO=user
0 6 * * * /home/user/backup/site.tcl


cat /home/user/backup/site.tcl

#!/usr/bin/tclsh

set pglib_path "/usr/lib/libpgtcl1.5/libpgtcl1.5.so"
load $pglib_path

set pg_host ...
set pg_dbname ...
set pg_user ..
set pg_port ...
set pg_cluster ...

set path /home/user/backup/site/
set tm [clock format [clock seconds] -format "%Y-%m-%d_%H:%M:%S"]

if { [catch { exec /usr/bin/pg_dump -E win --cluster $pg_cluster \
-h $pg_host -p $pg_port -U postgres -F p -a --disable-triggers -f \
$path/$tm\_restore.sql $pg_dbname >/dev/null} msg] } {
puts "Information about it: $::errorInfo"
}

if { [catch { exec /usr/bin/pg_dump -E win --cluster $pg_cluster \
-h $pg_host -p $pg_port -U postgres -F p -s --disable-triggers -f \
$path/$tm\_schema.sql $pg_dbname >/dev/null} msg] } {
puts "Information about it: $::errorInfo"
}

if { [catch { exec /bin/tar -cjf $path/$tm.tar.bz2 \
$path/$tm\_restore.sql $path/$tm\_schema.sql >/dev/null} msg] } {
puts "Information about it: $::errorInfo"
}

file delete $path/$tm\_restore.sql
file delete $path/$tm\_schema.sql


Вот и все, теперь сервер приемник ежечасно будет проверять наличие новых файлов на сервере-источнике и при их обнаружении копировать эти файлы. rsync использует эффективное сжатие, что экономит трафик и время. Приведенные выше рекомендации несложно повторить для необходимого количества сайтов.

P.S. Есть еще мысль воспользоваться локальной системой контроля версий для отслеживания изменений на удаленном сервере, но это когда время будет. Идея именно в том, чтобы иметь возможность локально отслеживать изменения, что позволит обнаружить как различные технические проблемы, так и злонамеренную модификацию файлов.

Зеркалирование блога из ЖЖ

Один из однокурсников матушки возымел желание опубликовать фотки после встречи в Пустыни в интернет и воспользовался для этой цели аккаунтом на Живом Журнале (LiveJornal, сокращенно ЖЖ). Как и следовало ожидать, матушка пожелала получить "это" в виде оффлайн-версии, что привело меня к печальному осознанию всей кривизны реализации этого самого ЖЖ и некоторых размышлений на тему, как же сделать эту самую офлайн версию. Что получилось, решил опубликовать, второй раз экспериментировать с ключами wget будет лень.

wget maxozhar.livejournal.com -r -l inf -X data,res,friends,calendar,2007 -D pics.livejournal.com,maxozhar.livejournal.com -p -H -E -k

Для остальных однокурсников и прочих лиц пожелание от всей души: выкладывайте фотки отдельно, не засовывайте их во всякие живые и дохлые журналы! Куда-нибудь на http-сервер, чтобы не надо было потом мучительно думать, как их оттуда выколупывать.

Искренне Ваш и так далее.

Ручная доводка AolServer4

Веб-сервер AolServer4 является платформой промышленного уровня для создания мощных, надежных и высокоэффективных веб-приложений. В нем предусмотрены возможности управления огромными множествами виртуальных хостов, пулы соединений с базой данных, пулы клиентских подключений, эффективные схемы кэширования статического и динамического содержимого, встроенная поддержка языка tcl и многое другое. Однако нередко встает задача воспользоваться мощью этого продукта в очень ограниченном окружении - на хостинге с ограниченным местом, с необходимостью запуска от нестандартного пользователя (если от пользователя www-data запущено некоторое количество php-ных сайтов, то для защиты своих данных явно лучше указать другого владельца). Также может потребоваться размещение данных, конфигурационных файлов и библиотек кода в нестандартном месте - по умолчанию все очень хорошо продумано, но на хостеры по-прежнему обожают создавать невообразимую кашу из разделов и их точек монтирования, притом зачастую доступное место находится только в "хомятнике" (/home/). Плюс к этому следует предусмотреть простоту переноса проекта на другой хостинг и возможность управления всеми файлами (конфигурационными, данными, скриптами) от одной учетной записи.

Одним из путей решения вышеназванных задач является создание отдельного скрипта управления сервисом в /etc/init.d/ и размещение всех данных веб-проекта в одном месте, создав определенную структуру каталогов. Пусть имя пользователя и группы будет acs:acs и порт, на котором работает веб-сервер, будет 8006 на localhost (для обеспечения внешнего доступа воспользуемся реверс-прокси pound или nginx).

1. Скрипт запуска

/etc/init.d/aolserver4-acs

#!/bin/sh
#
# Start the AOLServer HTTP server.
#
# Copyright (C) 2003-2006 Francesco P. Lovergine
#

# Include acs config if available
if [ -f /home/acs/acs.mount ] ; then
. /home/acs/acs.mount
fi

export LANG="ru_RU.UTF8"

NAME=acs.ru
SERVICE=acs
USER=acs
GROUP=acs
ADDRESS=127.0.0.1
PORT=8006
PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/usr/sbin/aolserver4-nsd
PIDFILE=/var/run/aolserver4/$NAME.pid
CONF=/home/veter/acs/www/etc/aolserver4.tcl

trap "" 1

[ -f $DAEMON ] || exit 0

log_daemon_msg() {
echo -n "$1: $2"
}

log_end_msg() {
if [ $1 -ne 0 ]; then
echo " failed!"
else
echo "."
fi
}

[ -f /lib/lsb/init-functions ] && source /lib/lsb/init-functions

start()
{
log_daemon_msg "Starting web server" "$NAME"

start-stop-daemon --start --quiet --exec $DAEMON --pidfile $PIDFILE --oknodo -- \
-u $USER -g $GROUP -b $ADDRESS:$PORT -s $SERVICE -t $CONF >/dev/null 2>&1

if [ $? != 0 ]; then
log_end_msg 1
exit 1
else
log_end_msg 0
fi
}

stop()
{
log_daemon_msg "Stopping web server" "$NAME"
start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo >/dev/null 2>&1
if [ $? != 0 ]; then
log_end_msg 1
exit 2
else
log_end_msg 0
fi
}


case "$1" in
start)
start
;;

stop)
stop
;;

reload|force-reload|restart)
stop
sleep 4
start
;;

*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|reload|force-reload}"
exit 1
;;
esac

exit 0




Вначале мы подключаем конфиг, который примонтирует нужную файловую систему
/home/acs/acs.mount

FS="/home/acs/acs.fs"
MNT="/home/acs/acs"

if ! [ -d "$MNT/lost+found/" ]; then
mount -o loop $FS $MNT
fi

Если этого не требуется, достаточно просто удалить (или не создавать) файл /home/acs/acs.mount

Поскольку неизвестно, какая локаль будет стоять на сервере (а если и известно заранее, все одна мало шансов, что нам эта локаль подойдет), явно укажем нужную локаль перед запуском сервера
export LANG="ru_RU.UTF8"
Теперь AolServer запустится с локалью UTF-8, независимо от локали сервера.

Обратим внимание на то, что следует писать непременно "NAME=acs.ru" (так же, как "set hostname acs.ru" в конфиге) - если написать "NAME=acs", то имя созданного pid-файла все равно будет acs.ru.pid, но при останове сервиса будет искаться pid-файл с именем acs.pid, в итоге сервер будет запускаться, но не будет останавливаться. Также отметим, что пришлось добавить переменную "SERVICE=acs", поскольку по умолчанию в качестве имени сервиса указан идентификатор main, что обусловлено рекомендованным методом разворачивания виртуального хостинга, который в силу вышеобозначенных причин нам не подходит.

Чтобы pid-файл удалось создать, следует настроить вхождение пользователя acs в нужную группу, а на время отладки можно сделать вот так
chmod a+rwx /var/run/aolserver4/

При необходимости с помощью утилиты rcconf включаем наш скрипт в число скриптов, автоматически запускаемых при старте сервера.

2. Структура каталогов

Структура каталогов может быть спланирована например следующим образом
postgresql (права postgres:postgres)
www (права acs:acs)
...dat
...etc
...log (права acs:acs)
...res (права acs:acs)
...sys
...tcl
...www

Здесь
postgresql - кластер базы данных;

www/dat - различные данные (например, карты);
www/etc - конфигурационный файл AolServer;
www/log - логи;
www/res - загруженные пользователем файлы;
www/sys - скрипты обновления системы, патчи, утилиты (например, на питоне, шелле и т.п);
www/tcl - библиотека tcl скриптов;
www/www - adp-скрипты, html-страницы, javascript, графика и проч.

Разумеется, структура может быть любой другой, я просто привел свой вариант в качестве примера. Права на каталоги назначаются в зависимости от необходимого к ним доступа - для www/www разумно установить права root:root, чтобы предотвратить их модификацию, если же их часто нужно изменять, можно устанавить владельцем нужную учетную запись.

Заключение

Мы рассмотрели путь, позволяющий запустить AolServer практически на любом сервере с произвольной структурой разделов и их точек монтирования, предусмотрели возможность дальнейшего администрирования без прав root. Работа AolServer на серверах масштаба предприятия, включая кластеры, хорошо изложена в документации, а мы с Вами убедились в том, что решения малого масштаба также могут воспользоваться всеми преимуществами корпоративной платформы.

(C) Alexey Pechnikov aka MBG, mobigroup.ru