Описание
Иногда, но требуется поднимать кластера RDS со снапшотов для тестов или восстановления данных (когда что-то пошло не так). Раньше все делалось руками, быстро наклацал в AWS Console и кластер восстановился или скопировал заготовленные aws-cli команды, использовал их в терминале и все готово. Как не крути, но хочется все манипуляции как то автоматизировать. Давно всю автоматизацию описываем в Jenkins, по этому попробуем очень просто и доступно организовать восстановление и удаления Aurora RDS Сluster c снапшотов.
Идея состоит в том, чтоб облегчить работу команде, использовать для восстановления Aurora Clusters или RDS Instance, передавая нужные нам параметры через Jenkins Job.
Что же должно уметь задание:
- принимать параметры для восстановления (sg, vpc, parametergroup, etc).
- возможность выбирать дату снапшотов.
- восстанавливать кластера аврора и обычные rds.
- удалять кластер и обычные rds.
В голове крутиться несколько вариантов, но я решил выбрать тот который посчитал оптимальным:
- Создадим директорию в Jenkins c именем RDS_RESTORE, в ней под директории с именами команд (web, game, etc).
- В директориях команд разместить задание для восстановления только их ресурсов, а в дескрипшин добавим таблицу с описанием параметров RDS. Таким образом таблица не будет загромождать интерфейс и по ней легко ориентироваться, выбирать нужные параметры.
- Что касается самого крипта, используем конструкцию switch case где опишем нужные action (восстановить, удалить) и одну функцию в которой будем выводить нужный нам snapshot. Все остальные параметры передаем через Jenkins Parameters в UI. В основном используем модуль sh и aws-cli под капотом, все добро будем выполнять в docker контейнере на master ноде.
Что понадобиться:
- Jenkins groovy script.
- docker images c aws-cli.
- список кластеров Aurora и RDS.
- AWS iAM пользователь c полным доступом к RDS.
Создание Jenkins Job
Создаем директорию RDS_Restore, далее в ней добавим 4 под директории для команд, в конечном результате выйдет следующее:
Тесты и задание будем проводить в директории Game, а после настройки и написания скрипта просто копируем его и изменять значения параметров.
В директории Game выбираем New Item, создаем задание с именем RDS_Gaming_Restore_from_Snapshot и типом Pipeline, далее добавляем параметры:
- AWS_REGION (choose parameter): регион в котором находятся RDS или кластера аврора, по умолчанию установим us-east-2.
- CHOSE_ACTION (choose parameter): действие, которое ходим выполнить.
- restore-aurora-cluster: восстановит кластер аврора.
- delete-restored-aurora-cluster: удалит кластер аврора.
- restore-rds-instance: восстановить RDS инстанс.
- delete-restored-rds-instance: удалить RDS инстанс.
- RDS_TO_DEL (choose parameter): список восстановленных кластеров или RDS на удаление. Их будем обозначать добавлением префикса restored. По умолчанию выставлено значение none.
- RDS_TO_RESTORE (choose parameter): список аврора кластеров или RDS которые доступны для восстановления. Сюда же добавим html таблицу с параметрами RDS, подробнее таблицу можно будет скачать здесь или воспользоваться ресурсом https://www.w3schools.com/html/html_tables.asp для создания нужной Вам таблицы.
- RESTORE_DATE (string parameter): название говорит само за себя, будем передавать дату снапшота в формате 2021-12-10.
- RDS_ENGINE(choose parameter):
- aurora-postgresql
- aurora-mysql
- mysql
- postgres
- RDS_ENGINE_VERSION (choose parameter): версии движков баз данных.
- RDS_VPC_SG_ID (string parameter): id cекюрити группы, которая будет закреплена.
- RDS_SUBNET_GROUP_NAME (string parameter): сабнет группа.
- RDS_PARAMETER_GROUP_NAME (string parameter): кастомная или дефолтная параметр группа, лучше всего создавать свою, тогда в ней можно будет вносить изменения в настройках баз.
- RDS_INSTANCE_TYPE (string parameter):тип инстанса, здесь добавим типы, которые используют текущие сервера.
- AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY (password paramater): по классике, данные пользователя для доступа в AWS с правами создание и удаление RDS.
В конечном результате после добавление всех параметров имеем следующую картину:
Далее переходим к написанию скрипта.
Создание Jenkins groovy
Весь скрипт можно скачать здесь. Описание скрипта разделим на две части, в первой опишем и проверим восстановление RDS а во второй удаление, приступаем.
Восстановление
Все мануальные или финальные идут без префикса rds:, а те которые создавались автоматически начинаются с rds:, пример:
$ aws rds describe-db-cluster-snapshots --query 'DBClusterSnapshots[].DBClusterSnapshotIdentifier[]'
....
"*****-dev-*****-*****-instance-1-final-snapshot", # manual snap
"rds:aurora-backend-dev-2021-12-17-05-17", # auto snap
.....
Создадим функцию, которая будет выводить нужные снапшоты, назовем ee rdsSnapshot. В ней будет выполняться две команды, которые на основе переданных параметров будут выводить необходимое имя снапшота за нужную дату:
def rdsSnapshot(){ // sort and filter rds snapshot for last day aurora_snap = sh (returnStdout: true, script:"aws rds describe-db-cluster-snapshots --query 'DBClusterSnapshots[].DBClusterSnapshotIdentifier[]' | grep ${RDS_TO_RESTORE} | grep ${RESTORE_DATE} |cut -d '\"' -f2 | tr -d '\n'") rds_snap = sh (returnStdout: true, script:"aws rds describe-db-snapshots --query 'DBSnapshots[].DBSnapshotIdentifier[]' | grep ${RDS_TO_RESTORE} | grep ${RESTORE_DATE} | cut -d '\"' -f2 | tr -d '\n'") }
где:
- aurora_snap – здесь выводим список доступных снапшотов, фильтруем их по имени аврора кластеров ${RDS_TO_RESTORE}, далее по дате ${RESTORE_DATE}, удаляем символ ” cut -d ‘\”‘ -f2 , в конце убираем все пробелы со строки tr -d ‘\n’, пример:
$ aws rds describe-db-cluster-snapshots --query 'DBClusterSnapshots[].DBClusterSnapshotIdentifier[]' | grep rds:aurora-gaming-stage-psql-cluster| grep 2021-12-10 | cut -d '"' -f2 | tr -d '\n'
rds:aurora-gaming-stage-psql-cluster-2021-12-10-04-11%
- rds_nap – то же самое что и с aurora_snap, но здесь выводиться список RDS снапшотов, пример:
aws rds describe-db-snapshots --query 'DBSnapshots[].DBSnapshotIdentifier[]' | grep psql*** | grep 2021-12-10 | cut -d '"' -f2 | tr -d '\n'
rds:psql****-qa-*******-2021-12-10-05-24%
Для определения action добавим конструкцию switch case, с действиями про которые говорили выше:
node('master'){ docker.image('amazon/aws-cli:2.2.33').inside("-v /var/run/docker.sock:/var/run/docker.sock -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} -e AWS_DEFAULT_REGION=${AWS_REGION} --entrypoint=''") { rdsSnapshot() switch("${CHOSE_ACTION}"){ case "restore-aurora-cluster": stage("RDS: Restore Aurora Cluster") { echo "=================================== AWS RDS: Restore Aurora Cluster ========================================" sh "aws rds restore-db-cluster-from-snapshot \ --snapshot-identifier ${aurora_snap} \ --engine ${RDS_ENGINE} \ --engine-version ${RDS_ENGINE_VERSION} \ --vpc-security-group-ids ${RDS_VPC_SG_ID} \ --db-cluster-identifier restored-${RDS_TO_RESTORE} \ --db-subnet-group-name ${RDS_SUBNET_GROUP_NAME} \ --db-cluster-parameter-group-name ${RDS_PARAMETER_GROUP_NAME}" echo "================================== AWS RDS: Create Aurora instance-1 =======================================" sh "aws rds create-db-instance \ --engine ${RDS_ENGINE} \ --publicly-accessible \ --db-cluster-identifier restored-${RDS_TO_RESTORE} \ --db-instance-identifier restored-${RDS_TO_RESTORE}-instance-1 \ --db-instance-class ${RDS_INSTANCE_TYPE}" echo "================================= AWS RDS: Create Aurora instance-2 =======================================" sh "aws rds create-db-instance \ --publicly-accessible \ --engine ${RDS_ENGINE} \ --db-cluster-identifier restored-${RDS_TO_RESTORE} \ --db-instance-identifier restored-${RDS_TO_RESTORE}-instance-2 \ --db-instance-class ${RDS_INSTANCE_TYPE}" echo "=========================== AWS RDS: Wait when Aurora Instance have been created ===========================" sh "sleep 500" sh "aws rds wait db-instance-available --db-instance-identifier restored-${RDS_TO_RESTORE}-instance-1" sh "aws rds wait db-instance-available --db-instance-identifier restored-${RDS_TO_RESTORE}-instance-2" } break
Расскажу немного про sh “sleep 500”. При использовании aws rds wait есть один нюанс, если кластер не перешёл в статус avalible за 30 минут, команда выдаст ошибку и задание завершиться со статусом Failed. При этом кластер будет продолжать восстановление в AWS. Пока что я не нашел решения на просторах интернета и форумах, по этому подсчитал сколько примерно восстанавливаются большие кластера и добавил sleep интервалом в 5 минут.
Таким образом перед запуском команды wait выполняется задержка в 5 минут, а уже после запуск команды, такой задержки хватает чтоб кластер успел восстановиться и задание завершилось успешно.
Проверяем работу скрипта, добавим его в задание и сохраним. Жмем Build with Parameters выбираем нужные параметры, имя кластера для восстановления и дату, запускаем нажав Build.
Для проверки статуса перейдем в AWS Console –> RDS —–> DataBases, ищем наш кластер по началу имени restored:
как видим, кластер в процессе восстановления, ожидаем и проверим еще раз:
кластер восстановился, переходим к описанию удаления.
Удаление
Добавляем возможность удаления аврора кластера и простого RDS:
case "delete-restored-aurora-cluster": stage("RDS: Delete Aurora Cluster") { sh "aws rds delete-db-instance --skip-final-snapshot --db-instance-identifier ${RDS_TO_DEL}-instance-1" sh "aws rds delete-db-instance --skip-final-snapshot --db-instance-identifier ${RDS_TO_DEL}-instance-2" sh "aws rds wait db-instance-deleted --db-instance-identifier ${RDS_TO_DEL}-instance-1" sh "aws rds wait db-instance-deleted --db-instance-identifier ${RDS_TO_DEL}-instance-2" sh "aws rds delete-db-cluster --skip-final-snapshot --db-cluster-identifier ${RDS_TO_DEL}" } break case "delete-restored-rds-instance": stage("RDS: Delete DB Instance"){ sh "aws rds delete-db-instance --skip-final-snapshot --db-instance-identifier ${RDS_TO_DEL}" sh "aws rds wait db-instance-deleted --db-instance-identifie ${RDS_TO_DEL}" } break } } }
выбираем CHOSE_ACTION: delete-restored-aurora-cluster и в RDS_TO_DEL: restored-aurora-gaming-psql-dev имя восстановленного кластера который хотим удалить, после жмем Build:
ожидаем завершение задания:
задание завершилось успешно, теперь осталось проверить удалился ли кластер. Воспользуемся терминалом и aws-cli:
$ aws rds describe-db-clusters --db-cluster-identifier restored-aurora-gaming-psql-dev
An error occurred (DBClusterNotFoundFault) when calling the DescribeDBClusters operation: DBCluster restored-aurora-gaming-psql-dev not found.
кластер удалился.
Полезные ссылки
– https://www.tutorialspoint.com/groovy/index.html
– https://docs.aws.amazon.com/cli/latest/reference/rds/restore-db-instance-from-db-snapshot.html
– https://docs.aws.amazon.com/cli/latest/reference/rds/restore-db-cluster-from-snapshot.html
– https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/BackupRestoreAurora.html
– https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_CommonTasks.BackupRestore.html