Резервное копирование сайтов в Яндекс Диск


Благодаря статье Михаила Воеводского заметил, что тема резервного копирования востребована в сообществе. Решил поделиться своим скриптом резервного копирования написанным на Python. Примечателен он тем, что полностью удовлетворяет закону импортозамещения заливает файлы на Яндекс Диск, раскладывая их по папочкам вида ГГГГ-ММ-ДД. Это не все его приятные особенности, вот список:

  • Умеет удалять старые бекапы с ЯДиска, если они старее чем N дней (настраивается в config.yaml)
  • Умеет удалять старые логи с сервера
  • Раскладывает бекапы на ЯДиске по папкам вида: ГГГГ-ММ-ДД
  • Бекапит системные папки: /etc/, /var/log/, /root/

В итоге, на Яндекс Диске, в папке для бекапов указанной в config.yaml, мы получаем список файлов, похожий на этот:

Не обращайте внимания на имена пользователей u1-u15 — это у меня на сервере панелька назначает их автоматически. Если вы называете пользователей в системе по-другому, то и на Яндекс Диске они будут называться также.

Примечание


Сервер обязательно должен быть настроен по этой инструкции:

  • На каждый сайт создаётся свой пользователь в системе (1 сайт = 1 пользователь)
  • Все сайты-пользователи располагаются в /var/www/
  • Имя пользователя сайта, название и имя пользователя БД одинаковые

Инструкция по установке в Linux Ubuntu, Debian и т.п.


У вас уже должен быть установлен на сервере Python 3.

  1. Устанавливаем менеджер пакетов для Python 3:
    apt-get install python3-pip
  2. Устанавливаем пакеты для Python, от которых зависим скрипт:
    pip3 install requests
    pip3 install pyyaml
  3. Закидываем папку с бекапером куда-нибудь на сервер, например в /root/scripts/py/
  4. Настраиваем config.yaml. В конфиге указывается:
    • Имя/пароль mysql root
    • Имя/пароль от Яндекс Диска
    • Временная папка, в которую закидывать бекапы на сервере
    • Папка на Яндекс Диске, где будут лежать бекапы
    • Что бекапить (системные папки, базу, файлы)
    • Удалять ли старые логи
    • Сколько дней хранить бекапы на Яндекс Диске (более старые будут удаляться)
    На самом деле файл config.yaml хорошо оснащён комментариями (благо формат yaml позволяет), поэтому разобраться там будет совершенно легко.
  5. Вызываем
    sudo crontab -e
    и прописываем ежедневный запуск в 2 часа ночи:
    0 2 * * * /usr/bin/env python3 /root/scripts/py/YaDiskBackuper/backuper.py

Вот собственно и всё. Теперь вы можете запустить скрипт и проверить, корректно ли он работает. В консоли от рута запускаем:
sudo python3 /root/scripts/py/YaDiskBackuper/backuper.py
Замените путь до скрипта на свой.

На сервере заходим во временную папку с бекапами, заходим на Яндекс Диск и наблюдаем, появляются ли там файлы.
Павел Гвоздь
26 июня 2016, 11:04
modx.pro
34
5 099
+14
Поблагодарить автора Отправить деньги

Комментарии: 22

Наумов Алексей
27 июня 2016, 11:19
0
Привет! Попробовал. При запуске руками из консоли через пару секунд увидел сообщение «Enter password:».

Проверил пароли, вроде все верно… Это к чему запрос относится? Файлы, кстати, на Яндекс.Диск начали появляться… логи и папка etc по крайней мере :)
    Павел Гвоздь
    27 июня 2016, 11:33
    0
    Привет! Странно, сейчас проверил у себя, запроса нет. Может пароль от root юзера просит? Потому что в скриптах такого запроса нет.
    А файлы сайтов и базы появились на Яндекс Диске?
      Наумов Алексей
      27 июня 2016, 11:53
      0
      Да, они начали появляться, правда я потом консоль закрыл и все остановилось :)

      Решил подождать пока сработает крон…
    Николай
    27 июня 2016, 21:25
    0
    Можно сделать проще без установки питонов
    Alex Vakhitov
    28 июня 2016, 16:58
    0
    По моему лучше было бы загрузить пакет в pypi и сделать скрипт исполняемым, чтобы не мучатся. Ну и провести рефакторинг чтобы все работало на python 2, тогда сразу на любой версии ubuntu можно будет запускать. Ну и исправить нейминг :) уже давно не видел кэмэлкейс в именах файлов и модулей, а лучше просто добавить этот пакет который вы используете как зависимость
      Павел Гвоздь
      28 июня 2016, 17:01
      0
      Покажи, как надо, пожалуйста, в соседнем топике.
        Alex Vakhitov
        28 июня 2016, 17:12
        +1
        Ну показывать если честно лень, для себя мне это не нужно учитывая что есть официальный консольный ЯД, и таки вещи по мне проще реализовать на bash. Но решение имеет право на жизнь и каждый пункт можно легко реализовать с помощью гугла, пофакту нужно просто настроить все в setup.py прри формирования пакетаю
      Наумов Алексей
      17 августа 2016, 10:32
      0
      Привет!
      Есть небольшая проблемка, не сохраняются бекапы баз, файлы все ок, а вот баз нет.

      Пароль в конфиге root пользователя проверил 3-ды, верный.

      Куда еще посмотреть можно?..
      Воеводский Михаил
      28 января 2017, 18:15
      0
      Сталкивался ли кто-нибудь с ошибкой выполнения скрипта?

      Есть 2 сервера на Ubuntu 16.04.1, настроенные аналогично, отличия в них:
      1) На площадке Flops с установленной по умолчанию системой для работы в облаке
      2) Выделенный сервер на другой площадке с системой, установленной из официального образа

      В первом случае скрипт создания бэкапов вываливается с ошибками, во втором работает без запинки.
      На обоих серверах python3 версии 3.5.1-3, модуль requests версии 2.13.0.

      Вывод ошибок:
      # python3 /root/scripts/py/YaDiskBackuper/backuper.py
      Traceback (most recent call last):
      File "/usr/local/lib/python3.5/dist-packages/requests/utils.py", line 792, in check_header_validity
      if not pat.match(value):
      TypeError: expected string or bytes-like object
      During handling of the above exception, another exception occurred:
      Traceback (most recent call last):
      File "/root/scripts/py/YaDiskBackuper/backuper.py", line 72, in <module>
      disk.ls( path_webdav_today )
      File "/root/scripts/py/YaDiskBackuper/YaDiskClient/YaDiskClient.py", line 83, in ls
      resp = self._sendRequest("PROPFIND", path, {'Depth': 1})
      File "/root/scripts/py/YaDiskBackuper/YaDiskClient/YaDiskClient.py", line 54, in _sendRequest
      return s.send(req.prepare())
      File "/usr/local/lib/python3.5/dist-packages/requests/models.py", line 257, in prepare
      hooks=self.hooks,
      File "/usr/local/lib/python3.5/dist-packages/requests/models.py", line 303, in prepare
      self.prepare_headers(headers)
      File "/usr/local/lib/python3.5/dist-packages/requests/models.py", line 443, in prepare_headers
      check_header_validity(header)
      File "/usr/local/lib/python3.5/dist-packages/requests/utils.py", line 796, in check_header_validity
      "not %s" % (value, type(value)))
      requests.exceptions.InvalidHeader: Header value 1 must be of type str or bytes, not <class 'int'>
      Поддержка Flops ничего существенного, естественно не говорит, ибо речь идет не только о стандартном ПО из пакетов.
      Поскольку Питон не знаю от слова совсем, отладка превращается почти в метод научного тыка. Понимаю лишь общую логику выполнения, не более того.

      Надеюсь на помощь более опытных в Питоне товарищей.
        Семён Лобачевский
        20 апреля 2017, 18:03
        +1
        После очередного обновления системы, стала появляться такая же ошибка.
        Проанализировав логи, оказалось, что данный скрипт не работает с модулем requests версии 2.13.
        Помог откат модуля до версии 2.10
        pip3 install requests==2.10
      Наумов Алексей
      05 марта 2017, 21:13
      0
      Павел, привет.

      А можно спросить совета о доработке, как выкинуть из бекапа некоторые жестко прописанные директории?
      У меня есть сайт (среди десятков других на сервере), где имеется фото архив на несколько Гб, не хочу его бекапить каждый раз. Как бы прописать эту директорию в игнор? Т.е. сам сайт пусть идет в бекап, но без этой директории с фотографиями.
        Павел Гвоздь
        06 марта 2017, 22:42
        +2
        На самом деле особо великой сложности нет. Я бы создал файлик в корне юзера, в котором бы указывалось, какие папки исключать при запаковке, в формате: 1 строка — 1 директория. А на стороне бекапера получал бы содержимое этого файла и передавал необходимые параметры (--exclude="") в tar.
          Наумов Алексей
          07 марта 2017, 09:28
          0
          Благодарю за наводку!
          Теперь с питоном разобраться бы)
        Николай Загумённов
        22 февраля 2019, 00:03
        0
        Traceback (most recent call last):
          File "/root/scripts/py/YaDiskBackuper/backuper.py", line 30, in <module>
            config = yaml.load( config_f )
          File "/usr/local/lib/python3.5/dist-packages/yaml/__init__.py", line 70, in load
            loader = Loader(stream)
          File "/usr/local/lib/python3.5/dist-packages/yaml/loader.py", line 34, in __init__
            Reader.__init__(self, stream)
          File "/usr/local/lib/python3.5/dist-packages/yaml/reader.py", line 85, in __init__
            self.determine_encoding()
          File "/usr/local/lib/python3.5/dist-packages/yaml/reader.py", line 135, in determine_encoding
            self.update(1)
          File "/usr/local/lib/python3.5/dist-packages/yaml/reader.py", line 169, in update
            self.check_printable(data)
          File "/usr/local/lib/python3.5/dist-packages/yaml/reader.py", line 144, in check_printable
            'unicode', "special characters are not allowed")
        yaml.reader.ReaderError: unacceptable character #x009f: special characters are not allowed
          in "/root/scripts/py/YaDiskBackuper/config.yaml", position 118
        Была вот такая ошибка из-за русских коментов в файле config.yaml, может версия у меня старая, не знаю
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        22