Друзья, всем привет!

Помимо основной работы инженером данных, я поддерживаю небольшой сайт на Django (посвящен информационным материалам по преподаванию истории и обществознания).

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

Сразу скажу, что такой подход подойдет для баз, размер которых не является астрономическим (десятки и сотни гигабайт), в моем случае база весит всего 50 Мб, статика около 400 - поэтому мне не составляло большого труда синхронизировать такие объемы. Думаю, небольшие и даже средние интернет магазины и блоги вряд ли хранят на порядки больше данных.

Для больших проектов, лучше бэкапы архивировать, шифровать и отправлять куда-нибудь в s3 типа  Minio.

Когда новая инфа на сайте появлялась довольно редко, я все делал руками, а именно:

  • заходил на удаленный сервер, где крутится сайт,  по ssh

  • выполнял команду для создания полной копии БД
    sudo -u postgres pg_dumpall -c -f {remote_db_copy_file_path

  • потом переключался в терминал ос рабочего ноута, создавал папку с названием, соответствующем дате бэкапа

  • с помощью утилиты scp, копировал с удаленной машины с сайтом бэкап, полученный в пункте 2 - т.е. типа такой команды
    scp -r {remote_user}@{remote_host}:{remote_media_path} {local_media_full_path}

  • опять же с помощью scp копировал статику с файлами из папки

  • удалял файл бэкапа из папки на удаленном сервере

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

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

Сам скрипт лежит вот здесь, в моем GitHub, скачивайте и пользуйтесь.

Давайте более подробно рассмотрим, как работает скрипт:

  1. Делается подключение по ssh с помощью библиотеки paramiko, авторизация с помощью файла rsa-key, который paramiko ищет автоматом, соответственно пароль указывать не надо. В скрипте за подключение отвечает функция _initialize_ssh_client

  2. Получаем название файла с копией БД, которую необходимо будет создать, с помощью функции _get_db_copy_remote_filename. Принцип простой, берем текущее время и дату, и подставляем в название файлика, получается что то типа “01072023_155045.sql". К этому имени подставится путь, взятый из переменной окружения REMOTE_DBCOPY_FOLDER

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

  4. Функция make_db_backup собственно делает сам бэкап, через команду pg_dumpall, предварительно выдав права юзеру postgres на папку, куда положится бэкап

  5. Бэкап грузится на локальную машину (функция upload_db_backup_to_local_machine)

  6. Старые бэкапы  удаляются с сервера (delete_old_copies_on_remote). Важно отметить, что срок актуальности бэкапа в днях можно задать в конфиге через переменную old-db-copies-exp-period. Потом данный период подставится в команду утилиты find.

  7. Ну и в конце, функция copy_media_files_to_local перекачивает статику с сервера на локальную машину

С алгоритмом работы понятно, теперь давайте распишу, что вам надо сделать, чтобы у Вас тоже все запустилось и работало,

  1. Иметь интерпретатор питона на локальной машине, а также менеджер пакетов pip

  2. Скачать репозиторий с моего гитхаба https://github.com/Riddik1993/DB-and-static-copy-from-remote

  3. Настроить с Вашим удаленным сервером вход по ssh не по паролю, а по ключу из файла. Как это сделать - есть много туториалов в статьях и на ютубе, я сам научился по вот этому видео на канале Диджитализируй. https://www.youtube.com/watch?v=IVHv3eVQa14&t=165s

Также это стоит сделать и не только ради скрипта с копированием базы, но и просто из соображений безопасности - так как по паролю ваш сервер гораздо легче взломать чем через ключ rsa

  1. Находясь в папке скаченного репозитория, вводим в терминале команду pip install requirements.txt и ставим нужные для скрипта зависимости. Если не хотите ставить их глобально, но создайте виртуальное окружение сначала и ставьте туда

  2. Обращаем внимание на файл config.conf. Надо создать переменные окружения, которые указаны внутри фигурных скобок - это можно сделать, отредактировав файл ~/.bashsrc

Просто открываем этот файлик, добавляем строчки такого формата

export REMOTE_USER=”username”

Прогреваем переменные окружения, вводим команду 

source ~/.bashsrc

Если совсем нет времени это делать, можно конечно и прямо в файл config.conf задать, паролей там никаких нет, но светить параметры напрямую в коде - это конечно плохо, все же через переменные безопасней. 

  1. Когда все сделано, в терминале в папке репозитория запускаем команду

    python3 make_db_media_copy.py

В выводе вы увидите логирование всех стадий работы скрипта:

Файл с копией базы положился в папку, название которой хранится в переменной LOCAL_DBCOPY_PATH

Медиафайлы положились в папку, которую скрипт предварительно создал, в указанной нами директории LOCAL_MEDIA_PATH

А если что то упало - в принципе будет ясно почему, вот здесь я неправильно указал значение переменной REMOTE_DBCOPY_PATH

Но если что. пишете в комментариях - всегда рад помочь.

Также пишите, как делаете логирование Вы.

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

Комментарии (6)


  1. maledog
    14.07.2023 11:43

    Не программирую на python, но мне кажется нет проверки на пустую переменную и валидность пути. Можно что-то куда-то не туда записать. Не говоря уже о том, что нужно следить за зависимостями. Тут и /bin/sh с головой хватило бы. И объём кода скорее всего тот же был бы.
    Еще можно было бы наладить отправку на почту или в телеграмм результатов и логов.


    1. Riddik1 Автор
      14.07.2023 11:43

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


  1. hardtop
    14.07.2023 11:43

    А мне понравилось. Просто, понятно, легко подправить под себя. Можно поворчать на отсутствие doc-string, но в принципе, и так всё понятно. Спасибо!


    1. Riddik1 Автор
      14.07.2023 11:43

      спасибо вам за комментарий, рад что полезно)


  1. ak545
    14.07.2023 11:43

    Я бы заменил paramiko на parallel-ssh.
    Paramiko не умеет работать с кодировками отличными от строгого utf8


    1. Riddik1 Автор
      14.07.2023 11:43

      спасибо за совет, поизучаю parallel-ssh )