11.08.2010

Апгрейд сервера до Squeeze

Очередной тестинг на днях заморозили и я решил, что пришло время по крайней мере личные сервера апнуть. Расскажу о тех проблемах с которыми столкнулся при апгрейде своего основного web-хоста и как их победил.

Проблема первая. Переход на python 2.6.

Это вообще для меня одна из самых ожидаемых фич Squeeze. Было бы вообще здорово перейти с 2.5 сразу на 2.7, но так уж сложилось, что основная работа по миграции на 2.6 была завершена до релиза 2.7. Печально, но это цена за стабильность.

Так или иначе, в связи с изменением версии python, пришлось изменять конфигурацию WSGI-приложений. Тут выяснилась одна тонкость. Приложения у меня публикуются через mod_wsgi + и давно-давно я имел привычку добавлять нужные пути в PYTHONPATH через обработчик WSGI. Потом, с развитием mod_wsgi, в нём появились опции расширения PYTHONPATH и я стал обработчик писать совсем простым, а пути добавлять в конфиге Apache. Сейчас это вышло боком. Дело в том, что в обработчике пути вычисляются программно с учётом текущей версии Python, а в конфиге Апача — прописываются жёстко. В результате для старых приложений пришлось все только пересоздать виртуальное окружение, а для более новых — ещё править конфиги. Поставил в голове галку на будущее.

Проблема вторая. Война с Apache.

Я был бы несказанно рад и счастлив, если бы всё у меня было идеологически верно, но есть одно приложение, от которого я никак не могу избавиться. Это форум на базе SMF. Через это безобразие я вынужден заставлять Апач парсить PHP и держать на хосте MySQL.

В логах Апача после апгрейда стали появляться вот такие записи:

[Tue Aug 10 23:23:28 2010] [error] [client 95.108.158.134] sh: host: command not found
[Tue Aug 10 23:23:43 2010] [error] [client 95.108.158.134] sh: host: command not found
[Tue Aug 10 23:23:54 2010] [error] [client 95.108.158.134] sh: host: command not found

Оказалось, что SMF для обратного резольвинга имён сначала пытается использовать команду /usr/bin/host, и только потом, если не получается, откатывается к родному пехапешному gethostbyaddr. Разработчики в комментариях мотивируют это тем, что для запуска команды в оболочке можно задать таймаут, а для gethostbyaddr нельязя. Чудны дела твои, Господи! Благослови Королеву и Open Source. В общем выкинул из SMF этот чудесный кусок кода. А этот форум давно собирался переписать, он во многом не устраивает.

Проблема третья. Война с MySQL.

Как я уже сказал, MySQL приходится на хосте держать исключительно ради прихоти SMF, который научился работать с Postgres лишь в версии 2.0, которая пока ещё до состояния релиза не дошла. Ещё разработчики затрудняются ответить на вопрос когда же будет реализована возможность миграции с MySQL на Postgres и будет ли она вообще.

Так или иначе, есть MySQL — нужно его бэкапить. Для резервного копирования и на серверах и на настольных машинах я уже давно применяю Duplicity, который умеет наборы данных выливать на Amazon S3. Невероятно удобно, невероятно надёжно, невероятно дёшево, с учётом того, что Amazon уже что-то около года держит цены на входящий трафик равными нулю. Но сам Duplicity резервировать умеет только файловую систему, что для БД не подходит. Поэтому я настроил ежедневный дамп всех баз данных MySQL. Всех, потому, что когда-то она была не одна и ещё здорово резервировать информацию о пользователях тоже, а она хранится в отдельной БД. И выглядело это вот так:

#!/bin/sh
for DB in `echo 'show databases;' | mysql --silent --batch --disable-pager`; do
  mysqldump --create-options --quote-names "${DB}" | gzip > "${DUMP}"
done

После апгрейда стало валить вот такое сообщение:

mysqldump: Got error: 1044: Access denied for user 'root'@'localhost' to database 'information_schema' when using LOCK TABLES

Полез в man, там нашёл разгадку:

mysqldump does not dump the INFORMATION_SCHEMA database by default. As of MySQL 5.1.38, mysqldump dumps INFORMATION_SCHEMA if you name it explicitly on the command line, although currently you must also use the –skip-lock-tables option. Before 5.1.38, mysqldump silently ignores INFORMATION_SCHEMA even if you name it explicitly on the command line.

Т.е. раньше он INFORMATION_SCHEMA не дампил и было ему счастье. Теперь хочет и счастья нет. Пришлось скрипт усложнить:

#!/bin/bash
for DB in `echo 'show databases;' | mysql --silent --batch --disable-pager`; do
        DUMP="/var/backups/mysql/${DB}-$(date +%y%m%d%H%M).sql.gz"
        OPTS="--create-options --quote-names"
        if [[ $DB == information_schema ]]; then
            OPTS="${OPTS} --skip-lock-tables"
        fi
        mysqldump $OPTS "${DB}" | gzip > "${DUMP}"
done

Проблема четвёртая, последняя. Снова дампы.

Забавно, что все проблемы связаны не с самим Debian, а с тем что под него написано своими (или чужими в случае с SMF) кривыми ручонками. Последний сюрприз приподнёс pg_dump, который используется таким же точно способом, как mysqldump. Было вот так:

for DB in $(psql -lt|grep -v template|cut -d'|' -f1); do
    pg_dump -Fc $DB | gzip -9 > /var/backups/postgres/${DB}_$(date +%Y%m%d).pgdump.gz
done

Ошибка после апгрейда какая-то уж совсем неприличная:

connection to database ":" failed: FATAL:  database ":" does not exist
/var/backups/postgres/postgres=CTc/postgres_20100811.pgdump.gz: No such file or directory
pg_dump: [archiver (db)] connection to database "(null)" failed: invalid connection option "postgres"
pg_dump: [archiver (db)] connection to database ":" failed: FATAL:  database ":" does not exist
/var/backups/postgres/=c/postgres_20100811.pgdump.gz: No such file or directory
pg_dump: [archiver (db)] connection to database "(null)" failed: invalid connection option ""

Оказалось всё предельно просто, pgsql -lt стал выводить некоторые записи в две строки. Пришлось пошуршать мозгом и подключить суперсилу AWK:

#!/bin/sh
for DB in $(psql -lt|awk 'NF>2 {print $1}'); do
    if [[ ! $DB =~ template ]]; then
        pg_dump -Fc $DB | gzip -9 > /var/backups/postgres/${DB}_$(date +%Y%m%d).pgdump.gz
    fi
done

Заключение

На всё ушло около четырёх часов. Дольше всего разбирался с этим чудо-форумом SMF. Я им пользуюсь уже наверное лет 7 или 8, а он всё ещё полон сюрпризов. Сказать что это любовь — не могу, но определённо у меня с ним какая-то связь.

Комментарии

15.08.10 22:56 kostix.myopenid.com комментирует:

В скрипте бэкапа баз MySQL два типичных башизма: нужно либо в шебанг написать /bin/bash, либо переправить
if [[ $DB == information_schema ]]; then
на
if [ $DB = information_schema ]; then

Подробнее, например, тут: https://wiki.ubuntu.com/DashAsBinSh#[[

А то поставите себе dash в качестве шелла по умолчанию (что вполне логично для скорости работы) и этот скрипт работать перестанет.

17.08.10 10:48 uptimebox комментирует:

Верно. Спасибо.