Релиз nxs-anomaly: отечественная альтернатива Grafana OnCall для управления дежурствами, маршрутизации оповещений и эскалации инцидентов. Доступен на GitHub
Все статьи

Резервное копирование большого количества разнородных web-проектов

nxs-backup для централизованного резервного копирования web-проектов

Время чтения
12 минут
Раздел
Инструменты
Резервное копирование большого количества разнородных web-проектов

Почему понадобилось новое решение

Резервное копирование — базовая задача для любого web-проекта. Однако при большом количестве систем и разнородного ПО быстро возникают практические вопросы: как правильно собирать резервные копии, где их хранить, как обеспечить необходимую глубину хранения и как унифицировать процесс для разных типов данных и инфраструктуры.

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

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

Со временем количество проектов и используемого ПО увеличивалось, а вместе с ним росло число сценариев, которые старые скрипты не поддерживали. Например, не было поддержки Redis, а также горячего резервного копирования MySQL и PostgreSQL. Сам процесс резервного копирования практически не мониторился — использовались только email-уведомления.

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

Поэтому возникла необходимость заменить существующее решение более современной системой.

Требования к системе резервного копирования

Перед разработкой нового решения мы сформировали основные требования:

1. Поддержка наиболее распространённого ПО:

  • файлы — дискретное и инкрементное копирование;
  • MySQL — холодные и горячие бэкапы;
  • PostgreSQL — холодные и горячие бэкапы;
  • MongoDB;
  • Redis;

2. Поддержка различных хранилищ:

  • Local;
  • FTP;
  • SSH;
  • SMB;
  • NFS;
  • WebDAV;
  • S3;

3. Уведомления о проблемах в процессе резервного копирования;

4. Единый конфигурационный файл для централизованного управления;

5. Возможность добавлять поддержку нового ПО через внешние модули;

6. Возможность задавать дополнительные параметры создания дампов;

7. Восстановление резервных копий стандартными средствами;

8. Простая первоначальная настройка.

Анализ существующих решений

Мы рассмотрели несколько существующих open-source решений:

  • Bacula и её форки, например Bareos;
  • Amanda;
  • Borg;
  • Duplicaty;
  • Duplicity;
  • Rsnapshot;
  • Rdiff-backup.

Однако ни одно из них полностью не соответствовало требованиям.

Например, Bacula содержит значительно больше функций, чем требовалось для наших сценариев. Первоначальная настройка также требует большого объёма ручной работы, в том числе подготовки или поиска отдельных скриптов для резервного копирования баз данных. Для восстановления резервных копий в некоторых решениях необходимо использовать специальные утилиты.

В результате мы пришли к двум выводам:

1. Ни одно из рассмотренных решений не закрывает все необходимые сценарии.

2. Имеющегося опыта достаточно, чтобы разработать собственный инструмент.

Так появился nxs-backup.

Архитектура nxs-backup

Для реализации был выбран Python: он позволяет относительно просто разрабатывать и поддерживать систему, а также удобно расширять её функциональность.

Конфигурация описывается в формате YAML.

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

Возможности резервного копирования

Поддерживаемые типы данных и хранилищ

nxs-backup поддерживает следующие варианты.

Базы данных:

  • MySQL — горячие и холодные бэкапы;
  • PostgreSQL — горячие и холодные бэкапы;
  • Redis;
  • MongoDB.

Файлы:

  • дискретное копирование;
  • инкрементное копирование.

Хранилища:

  • Local;
  • S3;
  • SMB;
  • NFS;
  • FTP;
  • SSH;
  • WebDAV.

Дискретное резервное копирование

Для разных данных могут использоваться разные стратегии резервного копирования. Поэтому nxs-backup поддерживает как дискретные, так и инкрементные копии, причём способ можно задавать для отдельных файлов и каталогов.

Для дискретных копий файлов и баз данных можно настроить глубину хранения в формате:

  • дни;
  • недели;
  • месяцы.

Инкрементное резервное копирование

Для файлов используется многоуровневая схема инкрементного резервного копирования.

В начале года создаётся полный бэкап. Далее:

  • в начале каждого месяца создаётся месячная инкрементная копия относительно годичной;
  • внутри месяца создаются декадные копии относительно месячной;
  • внутри каждой декады создаются дневные копии относительно декадной.

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

Восстановление из инкрементных копий

С дискретными копиями восстановление выполняется непосредственно из нужного архива с помощью стандартного tar.

Для восстановления из инкрементных копий необходимо последовательно применить несколько архивов.

Например, для восстановления состояния файлов на 24 июля 2018 года необходимо:

1. Развернуть годичный бэкап, созданный 1 января 2018 года.

2. Применить месячный бэкап за июль.

3. Применить декадный бэкап за 21 июля.

4. Применить дневной бэкап за 24 июля.

Для пунктов 2–4 при работе с tar необходимо использовать ключ -G, указывающий на работу с инкрементным бэкапом.

Такое восстановление занимает больше времени, чем разворачивание одной дискретной копии. Однако при редких операциях восстановления и необходимости экономить дисковое пространство эта схема позволяет эффективно использовать доступное хранилище.

Исключения

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

Правила исключений задаются в конфигурации:

- target:
      - /var/www/*/data/
      excludes:
      - exclude1/exclude_file
      - exclude2
      - /var/www/exclude_3

Ротация резервных копий

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

В nxs-backup используется другой порядок:

1. Удаляется устаревшая копия.

2. Запускается сбор новой.

3. Процесс контролируется и журналируется.

Для дискретного резервного копирования устаревшей считается копия, которая вышла за пределы заданной схемы хранения в формате дней, недель и месяцев.

Для инкрементных копий по умолчанию используется годовая ретроспектива. Удаление старых копий выполняется в начале каждого месяца. Например, перед созданием месячного бэкапа 1 августа 2018 года система проверяет наличие копий за август 2017 года и удаляет их.

Такой подход позволяет контролировать объём занимаемого дискового пространства.

Логирование

Для контроля процесса резервного копирования система ведёт журнал и фиксирует результаты отдельных операций:

  • запуск и остановку средств резервного копирования;
  • начало и завершение задания;
  • результат создания копии во временном каталоге;
  • результат копирования или перемещения во внешнее хранилище;
  • результат ротации;
  • ошибки на отдельных этапах.

Используются два уровня событий:

  • Info — информационные сообщения об успешном выполнении очередного этапа;
  • Error — сообщения об ошибках и аварийном завершении операций.

Email-уведомления

После выполнения операций система может отправлять email-уведомления. Предусмотрено два списка получателей:

1. Администраторы получают уведомления об ошибках. Информация об успешном выполнении резервного копирования для них не обязательна.

2. Бизнес-пользователи могут получать уведомления о состоянии резервного копирования и выбирать формат:

  • полный лог;
  • только сообщения об ошибках.

Конфигурация

Конфигурационные файлы имеют следующую структуру:

/etc/nxs-backup
├── conf.d
│ ├── desc_files_local.conf
│ ├── external_clickhouse_local.conf
│ ├── inc_files_smb.conf
│ ├── mongodb_nfs.conf
│ ├── mysql_s3.conf
│ ├── mysql_xtradb_scp.conf
│ ├── postgresql_ftp.conf
│ ├── postgresql_hot_webdav.conf
│ └── redis_local_ftp.conf
└── nxs-backup.conf

Главный конфигурационный файл /etc/nxs-backup/nxs-backup.conf содержит глобальные настройки:

main:
  server_name: SERVER_NAME

  admin_mail: project-tech@nixys.ru
  client_mail:
  - ''
  mail_from: backup@domain.ru
  level_message: error

  block_io_read: ''
  block_io_write: ''
  blkio_weight: ''
  general_path_to_all_tmp_dir: /var/nxs-backup

  cpu_shares: ''

  log_file_name: /var/log/nxs-backup/nxs-backup.log

jobs: !include [conf.d/*.conf]

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

Обычно каждое задание выносится в отдельный файл, который подключается через include в основном конфигурационном файле.

Генерация конфигурации

Для упрощения настройки предусмотрен генератор конфигурационных файлов.

Например, конфигурацию для MySQL с локальным и SCP-хранилищем можно создать командой:

nxs-backup generate --storage local scp --type mysql --path /etc/nxs-backup/conf.d/mysql_local_scp.conf

На выходе будет создан файл /etc/nxs-backup/conf.d/mysql_local_scp.conf, в котором останется заполнить необходимые значения:

- job: PROJECT-mysql
    type: mysql
    tmp_dir: /var/nxs-backup/databases/mysql/dump_tmp

    sources:
    - connect:
        db_host: ''
        db_port: ''
        socket: ''
        db_user: ''
        db_password: ''
        auth_file: ''
      target:
      - all
      excludes:
      - information_schema
      - performance_schema
      - mysql
      - sys
      gzip: no

      is_slave: no
      extra_keys: '--opt --add-drop-database --routines --comments --create-options --quote-names --order-by-primary --hex-blob'

    storages:
    - storage: local
      enable: yes

      backup_dir: /var/nxs-backup/databases/mysql/dump

      store:
        days: ''
        weeks: ''
        month: ''

    - storage: scp
      enable: yes

      backup_dir: /var/nxs-backup/databases/mysql/dump

      user: ''
      host: ''
      port: ''
      password: '' 
      path_to_key: ''

      store:
        days: ''
        weeks: ''
        month: ''

Пример: резервное копирование двух проектов 1С-Битрикс

Рассмотрим сервер, на котором в каталоге /var/www размещены два интернет-магазина на 1С-Битрикс:

  • bitrix-1.ru;
  • bitrix-2.ru.

Каждый проект работает со своей базой данных в отдельном экземпляре MySQL:

  • порт 3306 — bitrix_1_db;
  • порт 3307 — bitrix_2_db.

Типичная структура проекта выглядит следующим образом:

├── ...
├── bitrix
│ ├── ..
│ ├── admin
│ ├── backup
│ ├── cache
│ ├── ..
│ ├── managed_cache
│ ├── ..
│ ├── stack_cache
│ └── ..
├── upload
└── ...

Каталог upload, как правило, занимает значительный объём и постоянно растёт, поэтому его имеет смысл резервировать инкрементно.

Остальные каталоги резервируются дискретно, за исключением каталогов с кэшем и резервными копиями, которые создаются штатными средствами Bitrix.

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

  • файловые копии хранятся локально и на удалённом FTP;
  • резервные копии баз данных хранятся на удалённом SMB-хранилище.

Для этого создаются три конфигурационных файла:

  • bitrix-desc-files.conf — дискретное резервное копирование файлов;
  • bitrix-inc-files.conf — инкрементное резервное копирование файлов;
  • bitrix-mysql.conf — резервное копирование MySQL.

bitrix-desc-files.conf

 - job: Bitrix-desc-files
    type: desc_files
    tmp_dir: /var/nxs-backup/files/desc/dump_tmp

    sources:
    - target:
      - /var/www/*/
      excludes:
      - bitrix/backup
      - bitrix/cache
      - bitrix/managed_cache
      - bitrix/stack_cache
      - upload
      gzip: yes

    storages:
    - storage: local
      enable: yes

      backup_dir: /var/nxs-backup/files/desc/dump

      store:
        days: 6
        weeks: 4
        month: 6

    - storage: ftp
      enable: yes

      backup_dir: /nxs-backup/databases/mysql/dump

      host: ftp_host
      user: ftp_usr
      password: ftp_usr_pass

      store:
        days: 6
        weeks: 4
        month: 6

bitrix-inc-files.conf

- job: Bitrix-inc-files
    type: inc_files

    sources:
    - target:
      - /var/www/*/upload/
      gzip: yes

    storages:
    - storage: ftp
      enable: yes

      backup_dir: /nxs-backup/files/inc

      host: ftp_host
      user: ftp_usr
      password: ftp_usr_pass

    - storage: local
      enable: yes

      backup_dir: /var/nxs-backup/files/inc

bitrix-mysql.conf

- job: Bitrix-mysql
    type: mysql
    tmp_dir: /var/nxs-backup/databases/mysql/dump_tmp

    sources:
    - connect:
         db_host: localhost
         db_port: 3306
         db_user: bitrux_usr_1
         db_password: password_1
      target:
      -   bitrix_1_db
      excludes:
      -  information_schema
      - performance_schema
      - mysql
      - sys
      gzip: no

      is_slave: no
      extra_keys: '--opt --add-drop-database --routines --comments --create-options --quote-names --order-by-primary --hex-blob'

    - connect:
        db_host: localhost
        db_port: 3307
        db_user: bitrix_usr_2
        db_password: password_2
      target:
      -  bitrix_2_db
      excludes:
      - information_schema
      - performance_schema
      - mysql
      - sys
      gzip: yes

      is_slave: no
      extra_keys: '--opt --add-drop-database --routines --comments --create-options --quote-names --order-by-primary --hex-blob'

    storages:
    - storage: smb
      enable: yes

      backup_dir: /nxs-backup/databases/mysql/dump

      host: smb_host
      port: smb_port
      share: smb_share_name
      user: smb_usr
      password: smb_usr_pass

      store:
        days: 6
        weeks: 4
        month: 6

Запуск резервного копирования

После подготовки конфигурации запуск выполняется командой:

nxs-backup start $JOB_NAME -c $PATH_TO_MAIN_CONFIG

Предусмотрены специальные имена job:

  • files — запуск всех заданий типов desc_files и inc_files;
  • databases — запуск заданий типов mysql, mysql_xtradb, postgresql, postgresql_hot, mongodb, redis;
  • external — запуск заданий типа external;
  • all — последовательный запуск files, databases и external. Это значение используется по умолчанию.

Если требуется получить резервные копии файлов и баз данных с максимально близкими временными отметками, рекомендуется запускать nxs-backup с job all.

Задания выполняются последовательно, а не параллельно. При каждом запуске программа также проверяет, не запущен ли уже другой процесс nxs-backup. Если такой процесс обнаружен, новый запуск завершается с соответствующей записью в журнале.

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

Внешние модули

Модульная архитектура позволяет расширять возможности nxs-backup с помощью пользовательских скриптов. Это позволяет добавлять резервное копирование ПО, для которого нет встроенного модуля.

Для внешнего задания используется тип external:

- job: TEST-external
    type: external

    dump_cmd: ''

    storages:
    ….

Ключ dump_cmd содержит полную команду запуска внешнего скрипта.

После выполнения скрипт должен:

1. Cоздать готовый архив.

2. Вывести в stdout JSON следующего формата:

{
"full_path": "ABS_PATH_TO_ARCHIVE",
"basename": "BASENAME_ARCHIVE",
"extension": "EXTERNSION_OF_ARCHIVE",
"gzip": true/false
}

Параметры basename, extension и gzip используются для формирования конечного имени резервной копии.

Код возврата 0 означает успешное выполнение, а любое другое значение говорит об ошибке.

Пример внешнего модуля для etcd

Допустим, используется скрипт /etc/nxs-backup-ext/etcd.py, который создаёт snapshot etcd:

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import os
import subprocess
import sys
import tarfile

def archive(snapshot_path):
abs_tmp_path = '%s.tar' %(snapshot_path)
with tarfile.open(abs_tmp_path, 'w:') as tar:
tar.add(snapshot_path)
os.unlink(snapshot_path)

return abs_tmp_path

def exec_cmd(cmdline):
data_dict = {}

current_process = subprocess.Popen([cmdline], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True,
executable='/bin/bash')
data = current_process.communicate()

data_dict['stdout'] = data[0][0:-1].decode('utf-8')
data_dict['stderr'] = data[1][0:-1].decode('utf-8')
data_dict['code'] = current_process.returncode

return data_dict

def main():
snapshot_path = "/var/backups/snapshot.db"
dump_cmd = "ETCDCTL_API=3 etcdctl --cacert=/etc/ssl/etcd/ssl/ca.pem --cert=/etc/ssl/etcd/ssl/member-node1.pem"+\
" --key=/etc/ssl/etcd/ssl/member-node1-key.pem --endpoints 'https://127.0.0.1:2379' snapshot save %s" %snapshot_path

command = exec_cmd(dump_cmd)

result_code = command['code']

if result_code:
sys.stderr.write(command['stderr'])
else:
try:
new_path = archive(snapshot_path)
except tarfile.TarError as e:
sys.exit(1)
else:
result_dict = {
"full_path": new_path,
"basename": "etcd",
"extension": "tar",
"gzip": False
}

print(json.dumps(result_dict))

sys.exit(result_code)

if __name__ == '__main__':
main()

Конфигурация для запуска:

- job: etcd-external
    type: external

    dump_cmd: '/etc/nxs-backup-ext/etcd.py'

    storages:
    - storage: local
      enable: yes

      backup_dir: /var/nxs-backup/external/dump

      store:
        days: 6
        weeks: 4
        month: 6

При запуске job etcd-external программа:

  • запускает /etc/nxs-backup-ext/etcd.py без параметров;
  • проверяет код завершения скрипта;
  • проверяет наличие необходимых данных в stdout;
  • при успешном выполнении использует тот же механизм обработки, что и для встроенных модулей, подставляя значение full_path в качестве tmp_path;
  • при ошибке завершает выполнение задания и фиксирует результат в журнале.

Разработка и обновление

Разработка и сопровождение nxs-backup построены с использованием CI/CD. Изменения не вносятся непосредственно в скрипты на рабочих серверах. Код хранится в центральном GitLab-репозитории.

Pipeline выполняет сборку новых версий deb/rpm-пакетов, после чего они загружаются в соответствующие репозитории. На конечные серверы обновления доставляются через менеджер пакетов.

Такой процесс позволяет централизованно управлять версиями и обновлениями системы резервного копирования.

nxs-backup как open-source проект

nxs-backup распространяется как open-source проект и может использоваться для организации резервного копирования собственных проектов, а также дорабатываться под конкретные задачи.

Исходный код, документация по установке и настройке доступны в GitHub-репозитории nxs-backup.

Также доступен Docker-образ nxs-backup.

Оставьте заявку, чтобы обсудить проект

Ваши контакты
О вашем проекте

Нажав на кнопку, соглашаюсь на обработку персональных данных, Ознакомлен со всеми документами, размещенными на сайте

См. Политику обработки персональных данных
См. Пользовательское соглашение