Автоматический backup дисков в Yandex Cloud (с удалением старых версий) +2



Главная кнопка
Главная кнопка

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

За основу я использовал вот эту оригинальную статью из блога Yandex - просмотрите её сначала, чтобы понимать о чем идет речь ниже. (как заметил в комментарии автор этой статьи Николай Матросов, оригинальная статья была написана для Medium и находится здесь с некоторыми дополнениями).

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

Не забудьте еще создать файл package.json примерно такого содержания:

{
  "name": "snappy-yc",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "author": "bogdoslavik",
  "license": "ISC",
  "dependencies": {
    "yandex-cloud": "^1.3.3"
  }
}

Тут важна версия "yandex-cloud": "^1.3.3" для Node.js 12.

Upd: Как подсказали в комментариях, сейчас практически уже вышла новая версия v2 SDK поддерживающая все функции облака, и если вы планируете расширять функционал скрипта, то посмотрите в ее сторону, но придется немного переписать скрипт, так как версии не полностью совместимы.

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

Но! Моя ленивая натура понимала, что мне всё еще вручную придется удалять старые снапшоты: новые создаваться не будут после привышения квоты на общий размер снапшотов или их количества.

Поэтому я, повторно взял волю в кулак, и решил довести святое бэкап-дело до конца.

Не вдаваясь в подробности про небольшую возню с created_at снапшота, который хранится в волшебном формате google.protobuf.Timestamp родился вот такой простой скрипт:

const ycsdk = require("yandex-cloud/api/compute/v1");
const FOLDER_ID = process.env.FOLDER_ID;
const MAX_DAYS = process.env.MAX_DAYS;
async function handler(event, context) {
    const snapshotService = new ycsdk.SnapshotService();
    const diskService = new ycsdk.DiskService();
    const diskList = await diskService.list({
        folderId: FOLDER_ID,
    });
    
    console.log('Removing old snapshots');
    const {snapshots} = await snapshotService.list({folderId: FOLDER_ID});
    for ( let i in snapshots ) {
        const snapshot = snapshots[i];
        const createdMin = Date.now() / 1000 - (60 * 60 * 24 * MAX_DAYS);
        if ( snapshot && snapshot.createdAt && 
            snapshot.createdAt.seconds.low < createdMin ) {
            snapshotService.delete({snapshotId: snapshot.id});
        }
    }

    console.log('Iterating disks');
    for (const disk of diskList.disks) {
        console.log('disk.id',disk.id, 'name:', disk.name);
        if ('snapshot' in disk.labels) {
            snapshotService.create({
                folderId: FOLDER_ID,
                diskId: disk.id,
                description: disk.name
            });
            console.log('Creating snapshot');
        }
    }
    return {body: 'OK' }
}
exports.handler = handler;

Перфекционисты могут почикать console.log :)

Остается только добавить переменную окружения для скрипта MAX_DAYS - сколько дней хранить снапшоты.

Добавляем переменную MAX_DAYS в редакторе скрипта функции.
Добавляем переменную MAX_DAYS в редакторе скрипта функции.

Уверен, кому-то это сэкономит пару часов драгоценного времени.
Всем благ и надежных бакапов!




Комментарии (7):

  1. usbstor
    /#23942513

    Это волшебно!

  2. nik_the_spirit
    /#23943515

    Давайте по порядку. Во-первых, оригинальная статья была написана для блога на Medium. https://nikolaymatrosov.medium.com/yandex-cloud-cron-snapshot-bdee54c87541

    Во-вторых, вы правы, архивация кода и всех зависимостей не самое удобное решение, особенно, учитывая что зависимости нужно паковать для целевой платформы, которая далеко не всегда будет совпадать с платформой, на которой происходит сборка. Поэтому уже давно существует более простое решение: указать на директорию с кодом при помощи ключа --source-path и убедиться, что там есть файл с описанием зависимостей (для NodeJS это package.json). Все остальное за вас сделает yc CLI — соберет zip-архив с кодом, а потом на сервере будет выполнена загрузка указанных зависимостей.

    В-третьих, пример, указанный в статье, недавно был актуализирован и переписан с использованием новой версии SDK для NodeJS. Новая версия SDK v2 не является drop-in replacement'ом и еще находится в разработке, но именно на неё я бы рекомендовал ориентироваться в текущий момент. В основном потому что там поддержаны все сервисы Облака, а так же используются свежие версии сторонних зависимостей.

    Ну еще одно замечание: долгое время NodeJS SDK был не самым качественным и активно поддерживаемым, поэтому появилась альтернативная реализация, подхода описанного в статье, переписанная на Go.

    • bogdoslavik
      /#23945227

      Николай, огромное спасибо за вашу статью - без нее я бы, наверное, и не взялся за автоматизацию создания снапшотов для своего проекта.
      Добавил ссылку на статью на Медиум и написал по SDK v2.

  3. amarao
    /#23943769

    ... А откуда вы знаете, что у вас в бэкапе данные, которые вы бэкапили, а не погода на марсе?

    Любой бэкап состоит из пяти компонентов:

    • Код бэкапа

    • Код запуска бэкапа (таймеры/крон и т.д.)

    • Код проверки бэкапа

    • Код запуска проверки бэкапа

    • Система мониторинга/алертинга когда предыдущие пункты сломались

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

    • bogdoslavik
      /#23945301

      Спасибо за ваш едкий комментарий - без него здесь было немного скучно :). С удовольствием отвечу на ваш выпад.

      Лично я не сторонник холиваров - бинарно делить жизнь на "черное" и "белое", "бэкапы" и "не бэкапы". Мне любое понятие больше представляется эволюционным вектором 0 - 1: где в точке 0, нет не только бэкапа, но и даже никакой мысли о нем, а в точке 1 - идеальный атомарный проверенный и подписанный бэкап на каждый момент времени с алертами и страховкой от конца света. И эта статья дает возможность сделать неплохой шаг от почти 0 в сторону 1 - от ручного создания снапшотов "когда вспомню", к автоматизированному переодическому, с хранением нескольких версий.

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

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

      Поэтому я крайне рекомендую хранить несколько версий снапшотов, и вышеприведенный скрипт не просто удаляет все предыдущие, а только старее чем MAX_DAYS.

      • amarao
        /#23946383

        Сделанный вручную бэкап лучше, чем непроверенная автоматика №2 (т.к. человек сам себе алертинг). Но без проверки бэкапа человек вполне обнаруживает на месте архива с фотками архив симлинков или превьюшек. Т.е. проверка бэкапа, хотя бы руками и периодическая, это обязательное условие уверенности, что "бэкап есть".

        • bogdoslavik
          /#23947045

          Про ручную проверку согласен на все 100%.