Бэкап Zimbra OSE без Zextras: холодный и горячий способы

Дистрибьютор из Мытищ платил за облачное хранилище четвёртый год и был уверен, что почта у него защищена. Копировался туда каталог с почтой — и всё. В марте 2020-го я развернул этот бэкап на тестовой машине, чтобы показать, что именно защищено. Получилось 43 папки с файлами и ни одной учётной записи.

«У нас бэкап настроен» — и что за этим обычно стоит

Фразу эту я слышу почти на каждом первом выезде. Дальше выясняется одно из трёх. Либо копируется виртуальная машина целиком силами гипервизора. Либо ночью улетает архив каталога с почтой. Либо кто-то когда-то настроил задание, и оно с тех пор выполняется — а куда и что кладёт, никто не помнит.

Все три варианта могут быть рабочими. Могут и не быть. Разница между ними не видна до дня, когда бэкап понадобится, и вот тогда узнать её будет дорого.

Начинать разговор придётся с неприятного факта. В бесплатной редакции Zimbra нет встроенного средства резервного копирования. Совсем. Команда, которая делает бэкап, есть только в коммерческой версии; в открытой её на сервере просто нет. Всё, что у вас работает, — это чей-то самописный скрипт или сторонний инструмент, и качество там ровно такое, каким его сделал автор.

Ниже — две схемы, которые я ставлю клиентам сам, с честным разбором того, что каждая из них не сохраняет. Второй пункт важнее первого.

Март 2020, Мытищи: разворачиваем то, что копировалось четыре года

Дистрибьютор бытовой техники, склад и офис в Мытищах, 43 рабочих места. Пришли ко мне по другому поводу — тормозил поиск, — но по ходу аудита я спросил про бэкап и получил уверенное «настроен, в облако».

Что было настроено на самом деле: ночное задание в 02:30, которое архивировало каталог /opt/zimbra/store и заливало архив в объектное хранилище. Работало исправно четвёртый год подряд. Место занимало 620 ГБ в последней копии, счёт за хранение — 4 700 рублей в месяц. Сервер — Zimbra 8.8.15 Open Source Edition на CentOS 7, 32 ГБ памяти, store на массиве из шести дисков.

Я предложил проверить. Взяли тестовую виртуалку, поставили Zimbra той же версии, распаковали архив. Результат:

  • 43 каталога с файлами писем — на месте, читаются;
  • учётных записей — ноль, каталог не копировался вовсе;
  • базы с метаданными — нет, а без неё папки, флаги и структура ящика не восстанавливаются;
  • алиасов, списков рассылки, фильтров, настроек домена — нет;
  • сертификатов и конфигурации — нет.

То есть в архиве лежала почта как набор файлов, но не почтовая система. Владелец слушал молча и потом сказал фразу, которую я запомнил: «Я четыре года платил за хранение папок». Именно так.

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

Из чего вообще состоит Zimbra, и что обязано попасть в копию

Прежде чем копировать, стоит понять, что копируешь. У сервера четыре независимые части, и потеря любой делает остальные бесполезными.

ЧастьГде лежитЧто потеряете без неё
Тела писем/opt/zimbra/storeСобственно почту
Метаданные/opt/zimbra/db/dataПапки, флаги, теги, структуру ящиков
Каталог учётных записей/opt/zimbra/data/ldapПользователей, пароли, домены, алиасы, списки рассылки
Конфигурация и ключи/opt/zimbra/conf, /opt/zimbra/sslНастройки служб и сертификаты

Индекс (/opt/zimbra/index) в этот список я намеренно не включил: он перестраивается из данных, копировать его можно, но не обязательно — зато он часто занимает десятки гигабайт и раздувает архив.

Главное тут вот что. Тела писем и метаданные должны быть согласованы между собой. База ссылается на конкретные файлы; если файлы сняли в одну минуту, а базу — через двадцать, часть ссылок укажет в пустоту. На живом сервере эта рассинхронизация происходит постоянно и незаметно.

Отсюда растёт разница между двумя схемами. Холодная берёт всё разом в остановленном состоянии и потому согласованна. Горячая работает без простоя, но берёт ящики по одному через интерфейс самого сервера — и там согласованность обеспечивается иначе.

Схема первая: холодная копия с остановкой служб

Идея прямая: останавливаем сервер, снимаем снимок тома, запускаем сервер обратно, а дальше уже спокойно копируем со снимка. Простой измеряется минутами, потому что в остановленном состоянии сервер проводит только время создания снимка.

Скрипт, который у меня работает у нескольких клиентов, в сокращении:

#!/bin/bash
set -euo pipefail
LV=/dev/vg0/zimbra
SNAP=zsnap
MNT=/mnt/zsnap
DEST=/mnt/nas/zimbra/$(date +%Y-%m-%d)

su - zimbra -c '/opt/zimbra/bin/zmcontrol stop'
sleep 20
[ "$(pgrep -u zimbra -c . || true)" = "0" ] || { echo 'процессы живы'; exit 1; }

lvcreate -L 40G -s -n "$SNAP" "$LV"
su - zimbra -c '/opt/zimbra/bin/zmcontrol start'

mkdir -p "$MNT" "$DEST"
mount -o ro "/dev/vg0/$SNAP" "$MNT"
rsync -aHAX --numeric-ids "$MNT/zimbra/" "$DEST/opt-zimbra/"
umount "$MNT"
lvremove -f "/dev/vg0/$SNAP"

Три места, на которых я настаиваю.

Проверка, что процессов действительно не осталось. Штатная остановка возвращает управление раньше, чем всё завершилось. Без этой проверки вы делаете снимок наполовину живой базы и получаете ровно ту рассинхронизацию, ради борьбы с которой всё затевалось.

Ключ --numeric-ids. Копирует числовые идентификаторы владельца, а не имена. При восстановлении на другой машине это сэкономит вам несколько часов разбирательств с правами.

Отдельная выгрузка каталога. Даже при холодной копии я снимаю каталог учётных записей ещё и текстом — он весит копейки, а читается и восстанавливается независимо от всего остального:

su - zimbra -c '/opt/zimbra/libexec/zmslapcat /mnt/nas/zimbra/ldap/'

Снимок тома я беру размером 40 ГБ — этого с многократным запасом хватает на те три часа, пока идёт копирование; если снимок переполнится, он развалится, и копия окажется мусором. На проде в Мытищах простой при таком порядке составил 4 минуты 40 секунд — от остановки до момента, когда службы снова принимали почту. Копирование со снимка на хранилище шло потом ещё 3 часа 10 минут, но уже на работающем сервере.

Официальный скрипт, который тихо клал пустоту

Начинал я не со своего скрипта. Взял тот, что ходит по сети как официальный вариант бэкапа через снимки тома, — зачем изобретать, если есть готовое.

Задание отработало. Ошибок не выдало. Архив появился. Размер архива меня и насторожил: 118 мегабайт вместо ожидаемых сотен гигабайт.

Проверял я это на копии от 12 марта 2020 года. Причина оказалась в одной строке — в подстановке команды через обратные кавычки, которая в этом месте разворачивалась не в путь к смонтированному снимку, а в пустоту. Дальше архиватор честно упаковывал пустой каталог и честно рапортовал об успехе. Ни одного сообщения об ошибке: с точки зрения скрипта всё прошло идеально.

Это и есть самая противная категория проблем с бэкапом. Не «не сработало» — тогда бы заметили. А «сработало, но не с тем». Я после этого случая проверяю не факт выполнения задания, а два числа:

# 1. Размер вчерашней копии против позавчерашней
du -sh /mnt/nas/zimbra/2020-03-1[12]

# 2. Есть ли внутри то, что должно быть
tar -tzf /mnt/nas/zimbra/2020-03-12/opt-zimbra.tar.gz | \
  awk -F/ '{print $2"/"$3}' | sort -u | head -20

Отклонение размера больше чем на 15% в любую сторону — повод посмотреть руками. Резкий рост часто означает, что в архив заехало что-то лишнее, резкое падение — что не заехало нужное.

Мой личный вывод из этой истории: чужой скрипт бэкапа — это не готовое решение, а черновик, который надо прочитать построчно. Особенно если он собирает пути из переменных.

Схема вторая: горячий поящичный экспорт через zmmailbox

Холодная копия хороша как основа, но у неё есть свойство: она восстанавливается целиком. Вернуть один ящик за прошлый вторник из неё тяжело. Для этого нужна вторая схема — поящичный экспорт, который работает на живом сервере без простоя.

Сервер сам отдаёт содержимое ящика архивом через собственный интерфейс:

su - zimbra
/opt/zimbra/bin/zmmailbox -z -m sklad@example.ru -t 0 \
    getRestURL "//?fmt=tgz" > /mnt/nas/mbox/sklad@example.ru.tgz

Разберу ключи, потому что каждый здесь важен. -z — работать от имени администратора, не спрашивая пароль пользователя. -m — чей ящик выгружаем. -t 0снять ограничение по времени операции.

Последний ключ пропускают чаще всего, и это стоит потом дороже всего. Без него на большом ящике команда упирается в таймаут и обрывается вот так:

ERROR: zclient.IO_ERROR (invoke Read timed out)

Причём файл при этом остаётся — обрезанный, но существующий. Задание отчитается об успехе.

Пакетный вариант по всем ящикам:

su - zimbra
zmprov -l gaa > /tmp/accounts.txt
while read -r a; do
  /opt/zimbra/bin/zmmailbox -z -m "$a" -t 0 getRestURL "//?fmt=tgz" \
      > "/mnt/nas/mbox/$a.tgz" || echo "FAIL $a" >> /mnt/nas/mbox/errors.log
done < /tmp/accounts.txt

Скорость на реальном железе честная, но невысокая: ящик на 3 ГБ выгружается за 4–6 минут, ящик на 28 ГБ — около 50 минут. Это примерно 10 мегабайт в секунду, и цикл идёт последовательно, ящик за ящиком. На 43 ящиках и 620 ГБ полный прогон занял 17 часов 40 минут — в ночной перерыв буднего дня он не помещается никак. Поэтому полный проход я ставлю на вечер пятницы: старт в 18:00, к полудню субботы всё лежит на хранилище. По будням гоняются только самые ходовые ящики, их немного.

Обратная операция — импорт в ящик:

/opt/zimbra/bin/zmmailbox -z -m sklad@example.ru -t 0 \
    postRestURL "//?fmt=tgz&resolve=reset" /mnt/nas/mbox/sklad@example.ru.tgz

Параметр resolve=reset означает, что целевой ящик будет полностью очищен перед импортом. Это ровно то, что нужно при восстановлении, и совсем не то, что нужно, если вы хотите долить письма к существующим. Перепутать легко, а последствия необратимы.

Проверьте у себя за две минуты

Проверка отвечает на один вопрос: что именно у вас сейчас копируется. Все команды только читают.

# 1. Редакция сервера — есть ли вообще штатный бэкап
su - zimbra -c 'zmcontrol -v'
ls -l /opt/zimbra/bin/zmbackup 2>/dev/null || echo 'штатного бэкапа нет (OSE)'

# 2. Сколько ящиков должно быть в копии
su - zimbra -c 'zmprov -l gaa' | wc -l

# 3. Что реально лежит в последней копии
ls -1 /path/to/backup/ | head -20
du -sh /path/to/backup/
Что увиделиЧто это значитЧто делать
В версии написано FOSS, файла zmbackup нетОткрытая редакция. Всё, что работает, — чей-то скриптНайти этот скрипт и прочитать его
В копии только каталог storeСкопирована почта, но не почтовая системаДобавить базу, каталог учёток и конфигурацию
Число архивов ящиков меньше числа учётокЧасть ящиков не выгружается, и об этом никто не знаетСмотреть журнал ошибок выгрузки
Есть архивы размером в единицы килобайтВыгрузка оборвалась по таймауту — забыт ключ -t 0Перевыгрузить с ключом
Размер копии не меняется месяцамиЗадание выполняется, но кладёт не тоРаспаковать и посмотреть содержимое
Каталог data/ldap в копии отсутствуетУчётные записи и пароли не сохраняютсяДобавить выгрузку через zmslapcat

Третья и четвёртая строки — то, на чём я сам обжёгся у этого клиента. Первую неделю схема работала, а я не сверял размеры. Из 43 архивов шесть весили по 4 килобайта: самые большие ящики обрывались по таймауту, потому что ключ -t 0 я в скрипт поставил, а в ручной прогон для проверки — забыл, и именно ручной прогон считал эталонным.

Честное сравнение: чего не сохраняет каждая схема

Это тот раздел, ради которого писалось всё остальное.

КритерийХолодная копияГорячий экспорт ящиков
Простой4–5 минут за прогонНет
Время на 620 ГБ3 ч 10 мин фоном17 ч 40 мин
Учётные записи и паролиДаНет
Алиасы, списки рассылки, доменыДаНет
Настройки сервера, сертификатыДаНет
Восстановить один ящикТяжелоЛегко, минуты
Восстановить всё разомЛегкоДолго, по одному
Работает на другом сервереС оговоркамиДа, на любой Zimbra

Смотрите на три жирные строки. Горячий экспорт — копия содержимого ящиков и ничего больше. Письма, папки, календари и контакты вы получите, но возвращать их будет некуда: учёток на пустом сервере нет, и создавать их придётся заново — с паролями, алиасами и списками рассылки.

Поэтому у клиента в Мытищах мы поставили обе:

  • холодная копия по воскресеньям, простой около 5 минут в 03:00, три последние копии на хранилище — 1,9 ТБ;
  • полный горячий поящичный прогон раз в неделю, с вечера пятницы; два последних набора — 820 ГБ, архивы ужимаются примерно на треть от живого store;
  • ежесуточный горячий экспорт семи критичных ящиков — закупки, продажи, склад, бухгалтерия, директор и два общих: 54 ГБ за прогон, глубина 14 дней, 756 ГБ на диске;
  • выгрузка каталога учётных записей — ежедневно, 34 МБ;
  • раз в квартал — восстановление одного случайного ящика на тестовую машину, по регламенту не дольше 40 минут.

Глубину хранения здесь продиктовало не желание, а арифметика тома. Хранилище 4 ТБ, занято под всю схему 3,4 ТБ, свободно около 600 гигабайт. Держать поящичные наборы по всем 43 ящикам за две недели — это ещё почти 6 ТБ, которых нет; поэтому две недели держатся только те семь ящиков, из-за которых обычно и звонят.

Первую проверку прошли 28 марта 2020 года: развернули ящик закупок на 11 ГБ за 34 минуты. Настройка — 16 часов работ. Само хранилище на 4 ТБ стоит в другом помещении и обошлось в 61 тысячу рублей.

Цена альтернативы считается просто. Вся переписка по поставкам, спецификациям и рекламациям живёт в почте, глубина архива — четыре года. Потеря сервера без восстановления остановила бы продажи и снабжение минимум на неделю: 43 человека × 40 часов ≈ 1720 человеко-часов, около 900 тысяч рублей упущенной работы. Претензии по договорам владелец считать отказался.

Что делать, если вы дочитали и поняли, что у вас первый вариант

Короткий порядок действий на ближайшую неделю.

  1. Найдите скрипт. Не задание в планировщике, а сам файл, и прочитайте его. Половина вопросов снимется на этом шаге.
  2. Сверьте число архивов с числом учёток. Расхождение почти всегда есть.
  3. Посмотрите на размеры. Архивы в килобайтах и ровный размер копии месяц за месяцем — два самых частых симптома.
  4. Добавьте выгрузку каталога учётных записей. Это одна строка и 34 мегабайта, а без неё восстанавливать некуда.
  5. Разверните одну копию на тестовой машине. Пока этого не сделано, у вас не бэкап, а гипотеза.

И про совет, который часто дают в форумах и который малому бизнесу выходит боком: «просто снимайте снапшот виртуалки, этого достаточно». Снимок гипервизора, сделанный на работающем сервере, фиксирует базу в произвольный момент — с недописанными транзакциями и наполовину обновлёнными ссылками. Иногда такой снимок разворачивается нормально. Иногда база после разворачивания требует восстановления, и вы узнаёте об этом в худший день. Снимок — хорошее дополнение к согласованной копии, но не замена ей.

Хотите понять, что у вас сейчас в копии на самом деле, — выполните три команды из проверки выше и пришлите вывод: версию сервера, число учётных записей и листинг папки с бэкапом. За день отвечу, что именно вы сможете восстановить, чего не сможете, и сколько работы, чтобы закрыть дыру. Если окажется, что всё нормально, — так и напишу, это тоже бывает.

Частые вопросы

Правда ли, что в бесплатной Zimbra совсем нет бэкапа?

Правда. Средство резервного копирования — часть коммерческой редакции; в открытой версии соответствующей команды на сервере просто нет, и проверяется это одной строкой: ls -l /opt/zimbra/bin/zmbackup. Всё, что работает у вас сейчас, — либо самописный скрипт, либо сторонний инструмент, либо снимки гипервизора. Это не значит, что бесплатная версия непригодна: две схемы из статьи закрывают задачу полностью. Это значит, что за качество отвечает тот, кто их настроил, и прочитать этот скрипт стоит до того, как он понадобится.

Зачем нужен ключ -t 0 при выгрузке ящика?

Он снимает ограничение по времени на операцию. Без него выгрузка большого ящика упирается в таймаут и обрывается с ошибкой вида zclient.IO_ERROR (invoke Read timed out). Коварство в том, что файл при этом остаётся на диске — обрезанный, но с виду нормальный, — а скрипт отчитывается об успехе. У клиента в Мытищах из 43 архивов шесть весили по 4 килобайта, и это были ровно шесть самых крупных ящиков, то есть самых ценных. Поэтому ключ ставьте всегда, а после прогона обязательно сверяйте размеры архивов между собой.

Чем resolve=reset отличается от обычного импорта?

Тем, что целевой ящик перед импортом очищается полностью. Для восстановления после аварии это правильное поведение: вы получаете ящик ровно в том состоянии, в каком он был на момент копии, без наслоений. Но если задача другая — например, вернуть письма за один месяц к уже работающему ящику, — этим параметром вы уничтожите всё, что человек накопил после аварии. Перед импортом в живой ящик я всегда сначала делаю его выгрузку, даже если уверен в параметрах. Пять минут страховки против необратимой потери.

Достаточно ли снимков виртуальной машины вместо всего этого?

Как единственная мера — нет. Снимок работающей машины фиксирует базу в произвольной точке: часть транзакций не завершена, часть ссылок на файлы писем обновлена, часть нет. Развернуться такой снимок может нормально, а может потребовать восстановления базы, и предсказать заранее нельзя. Второй момент: снимки обычно живут на том же хранилище, что и сама машина, и умирают вместе с ним. Я использую снимки как быстрый откат на случай неудачного обновления, а рядом держу согласованную копию с остановкой служб. Это разные инструменты для разных бед.

Как часто проверять, что бэкап рабочий?

Автоматически — каждый день: сравнивать размер свежей копии с предыдущей и число архивов ящиков с числом учётных записей. Отклонение больше 15% или недостача архивов — повод посмотреть руками, и это ловится скриптом в пять строк. Руками — раз в квартал: развернуть один случайный ящик на тестовую машину и открыть его. У клиента в Мытищах на этой квартальной проверке за два года дважды всплывали проблемы, о которых иначе узнали бы в аварию. Полноценное учение с разворачиванием сервера с нуля стоит проводить раз в год.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#Zimbra#бэкап#zmmailbox#OSE#эксплуатация
Комментарии 0

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

загрузка...

Подпишитесь на рассылку ITfresh

Раз в неделю — практические гайды для руководителя IT и сисадмина: безопасность, 1С, миграции, резервные копии, лайфхаки из реальных проектов.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.