«Из коробки» Elastic такого решения не предлагает, по крайней мере, в версии 5.х. Немного поспрашивав у Гугла Всемогущего, мы решили создать собственный велосипед. Пусть немного неуклюжий, зато родной.

Итак, дано:
Сервер с установленной на нём ОС Linux. На сервере установлен, настроен и работает Elasticsearch версии 5.х, в Elasticsearch хранятся индексы с именами вида project_name-yyyy.mm.dd
Задача:
Архивировать каждый индекс старше N дней, сжав его в отдельный файл для возможности восстановления данного конкретного индекса за нужную дату. По завершению процесса архивирования индекс удалить из Elasticsearch.
Решение
Архивирование индексов
Для работы с индексами нам потребуется curator версии старше 5.0.
Вытаскивать индексы из Elasticsearch будем через снапшоты. Поэтому для начала убедимся, что в файле конфигурации elasticsearch, обычно это файл /etc/elasticsearch/elasticsearch.yml, прописан путь до файлового репозитория:
path.repo: /opt/elasticsearch/snapshots
Если такой строки нет, пропишем и перезагрузим elasticsearch.
Далее создадим репозиторий, в котором мы будем размещать снапшоты:
mkdir -p /opt/elasticsearch/snapshots/repository curl -XPUT 'http://localhost:9200/_snapshot/repository' -H 'Content-Type: application/json' -d '{ "type": "fs", "settings": { "location": "repository", "compress": true } }'
И сразу же создадим ещё один репозиторий с именем «recovery», он нам понадобится для восстановления индексов:
mkdir -p /opt/elasticsearch/snapshots/recovery curl -XPUT 'http://localhost:9200/_snapshot/recovery' -H 'Content-Type: application/json' -d '{ "type": "fs", "settings": { "location": "recovery", "compress": true } }'
Ну и сам скрипт архивирования индексов. Из списка индексов, подлежащих архивированию, исключаем индексы .kibana и elastalert_status. Значения переменных, заданных в шапке скрипта, естественно, можно вытащить наружу и передавать скрипту в качестве аргументов, дело вкуса.
В качестве хранилища архивов в скрипте указана локальная папка, но это, конечно же, не очень хорошая практика, и лучше архивы складывать куда-нибудь подальше в надёжное место.
Процесс архивирования логируется, файл лога задаётся переменной $LOG. Не забывайте настроить ротацию для файла лога.
Логика работы скрипта описана в комментариях. Не забудьте поправить значения переменных, если ваши настройки будут отличаться от дефолтных.
#!/bin/bash DAYS=31 #Количество дней, от текущей даты, старше которого индексы будут архивироваться SNAPSHOT_DIRECTORY="/opt/elasticsearch/snapshots" BACKUP_DIR="/opt/elasticsearch/elasticsearch_backup" REPOSITORY="repository" LOG="/var/log/elasticsearch/elasticsearch_backup.log" DATE=`date` #Проверим существование папки для архивов и если нет, создадим её if ! [ -d $BACKUP_DIR ]; then mkdir -p $BACKUP_DIR fi #Получаем массив индексов, которые старше $DAYS INDICES=`curator_cli --config /etc/elasticsearch/curator-config.yml --host localhost --port 9200 show_indices --filter_list "[{\"filtertype\":\"age\",\"source\":\"creation_date\",\"direction\":\"older\",\"unit\":\"days\",\"unit_count\":\"$DAYS\"},{\"filtertype\":\"kibana\",\"exclude\":\"True\"},{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"elastalert_status\",\"exclude\":\"True\"}]"` #Проверим, не пустой ли список TEST_INDICES=`echo $INDICES | grep -q -i "error" && echo 1 || echo 0` if [ $TEST_INDICES == 1 ] then echo "$DATE Не найдено индексов для обработки" >> $LOG exit else # Составляем цикл для каждого индекса в массиве $INDICES for i in $INDICES do # Создаём снапшот для индекса $i curator_cli --config /etc/elasticsearch/curator-config.yml --timeout 600 --host localhost --port 9200 snapshot --repository $REPOSITORY --filter_list "{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"$i\"}" # Заносим в переменную имя снапшота для индекса $i SNAPSHOT=`curator_cli --config /etc/elasticsearch/curator-config.yml --host localhost --port 9200 show_snapshots --repository $REPOSITORY` # Архивируем папку репозитория и складываем архив в хранилище cd $SNAPSHOT_DIRECTORY/$REPOSITORY && tar cjf $BACKUP_DIR"/"$i".tar.bz" ./* # Удаляем snapshot curator_cli --config /etc/elasticsearch/curator-config.yml --host localhost --port 9200 delete_snapshots --repository $REPOSITORY --filter_list "{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"$SNAPSHOT\"}" # Удаляем индекс curator_cli --config /etc/elasticsearch/curator-config.yml --host localhost --port 9200 delete_indices --filter_list "{\"filtertype\":\"pattern\",\"kind\":\"regex\",\"value\":\"$i\"}" # Очищаем папку репозитория rm -rf $SNAPSHOT_DIRECTORY/$REPOSITORY/* done fi
Удаление устаревших архивов
Отлично! Мы получили архивы индексов в хранилище, но их-то тоже нужно периодически чистить. Сделаем для этого отдельный скрипт /opt/elasticsearch/delete_archives.sh
#!/bin/bash # Удаление бекапов старше $DAYS дней # ВАЖНО! В имени файла архива может быть только один знак "-" перед датой. Дата должна быть в формате "yyyy.mm.dd". # Например: aaa_bbb.ccc-yyyy.mm.dd.tar.bz DAYS=91 BACKUP_DIR="/opt/elasticsearch/elasticsearch_backup" #Определяем пороговую дату для удаления архивов THRESHOLD=$(date -d "$DAYS days ago" +%Y%m%d) #echo "THRESHOLD=$THRESHOLD" FILES=`ls -1 $BACKUP_DIR` TODELETE=`for i in $FILES; do echo $i | awk -F- '{printf "%s\n",$2 ;}' | awk -F. '{printf "%s%s%s \n",$1,$2,$3 ;}' | sed "s/$/$i/"; done` echo -e "$TODELETE" |\ while read DATE FILE do [[ $DATE -le $THRESHOLD ]] && rm -rf $BACKUP_DIR/$FILE done
Ну вот, теперь осталось установить скрипты в крон. У нас они выполняются раз в сутки по ночам. Вывод скриптов перенаправим в файл лога
0 1 * * * /bin/bash /opt/elasticsearch/backup_snapshot.sh >> /var/log/elasticsearch/elasticsearch_backup.log 0 3 * * * /bin/bash /opt/elasticsearch/delete_archive.sh >> /var/log/elasticsearch/elasticsearch_backup.log
Восстановление индексов из архива
Процесс восстановления индексов тоже несложный. Для удобства обернём процесс восстановления индекса из архива в скрипт, которому на вход в качестве аргумента будем передавать имя файла архива. Для работы скрипта необходимо установить утилиту jq. Папку репозитория /opt/elasticsearch/snapshots/recovery для восстановления индекса и сам репозиторий в Elasticsearch мы создали ранее.
#!/bin/bash #Зададим переменные ARCHIVE=$1 BACKUP_DIR="/opt/elasticsearch/elasticsearch_backup" RECOVERY_DIR="/opt/elasticsearch/snapshots/recovery/" # На всякий случай очищаем папку репозитория rm -rf $RECOVERY_DIR/* # Разархивируем индекс в папку репозитория tar xjf $BACKUP_DIR/$ARCHIVE -C $RECOVERY_DIR # Заносим в переменную $SNAPSHOT имя снапшота в репозиториии SNAPSHOT=`curl -s -XGET "localhost:9200/_snapshot/recovery/_all?pretty" | jq '.snapshots[0].snapshot' | sed 's/\"//g'` # Восстанавливаем индекс из снапшота curl -XPOST "localhost:9200/_snapshot/recovery/$SNAPSHOT/_restore?pretty" # Нужно выставить небольшую задержку, чтобы Elasticsearch не ругался на удаление восстанавливаемого снапшота sleep 30 # Удалим снапшот из репозитория curl -XDELETE "localhost:9200/_snapshot/recovery/$SNAPSHOT?pretty" # Очистим папку репозитория rm -rf $RECOVERY_DIR/*
Подводим итог
Мы сделали архивирование каждого индекса в отдельный файл, настроили удаление устаревших архивов и научились восстанавливать индекс за нужную дату из архива.
Можно позволить себе взять с полки пирожок.

