Terraform RDS: Восстановление данных после уничтожения из-за модификации?

#amazon-web-services #terraform #amazon-rds #amazon-aurora

Вопрос:

Я пытаюсь создать MySQL-кластер RDS Aurora в AWS с использованием Terraform. Однако я замечаю, что каждый раз, когда я изменяю кластер таким образом, чтобы он требовал его замены, все данные теряются. Я настроил окончательный снимок и хотел бы восстановить его с помощью этого снимка или восстановить исходные данные с помощью альтернативной меры.

Пример: Изменение кластера -> TF Уничтожает исходный кластер ->> TF Заменяет новый кластер ->>> Восстановление данных из исходного

Я попытался использовать один и тот же идентификатор снимка для обоих aws_rds_cluster.snapshot_identifier и aws_rds_cluster.final_snapshot_identifier , но терраформировать бомбы, потому что окончательного снимка уничтоженного кластера еще не существует.

Я также пытался использовать rds-finalsnapshot модуль, но оказалось, что он в основном используется для вращения сред вверх и вниз, сохранения данных. т. Е. Уничтожения всего кластера, а затем его воссоздания как части отдельного развертывания. (Модуль: https://registry.terraform.io/modules/connect-group/rds-finalsnapshot/aws/latest)

 module "snapshot_maintenance" {
  source="connect-group/rds-finalsnapshot/aws//modules/rds_snapshot_maintenance"    
  identifier                    = local.cluster_identifier
  is_cluster                    = true
  database_endpoint             = element(aws_rds_cluster_instance.cluster_instance.*.endpoint, 0)
  number_of_snapshots_to_retain = 3
}

resource "aws_rds_cluster" "provisioned_cluster" {
  cluster_identifier                  = module.snapshot_maintenance.identifier
  engine                              = "aurora-mysql"
  engine_version                      = "5.7.mysql_aurora.2.10.0"
  port                                = 1234
  database_name                       = "example" 
  master_username                     = "example"
  master_password                     = "example"
  iam_database_authentication_enabled = true 
  storage_encrypted                   = true
  backup_retention_period             = 2
  db_subnet_group_name                = "example"
  skip_final_snapshot                 = false
  final_snapshot_identifier           = module.snapshot_maintenance.final_snapshot_identifier
  snapshot_identifier                 = module.snapshot_maintenance.snapshot_to_restore 
  vpc_security_group_ids              = ["example"]
    
}
 

Я нахожу, что если изменение требует уничтожения и восстановления, у меня нет отличного способа восстановить данные в рамках одного и того же развертывания.

Я добавлю, что не думаю, что это проблема с моим кодом. Это скорее ограничение жизненного цикла TF. Я считаю, что я не могу быть единственным человеком, который хочет сохранить данные в своем кластере в случае, если TF решит, что кластер должен быть воссоздан.

Если я хотел предотвратить потерю данных из-за изменения кластера, которое приводит к уничтожению, нужно ли мне уничтожать кластер за пределами terraform или через интерфейс командной строки, синхронизировать состояние Terraform и затем применить?

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

1. Каков ваш код TF, который вызывает проблему?

2. Когда вы говорите «Терраформируйте бомбы, потому что окончательный снимок разрушенного кластера еще не существует», это означает, что вы пытаетесь воссоздать кластер с помощью этих модулей, но до того, как был создан какой-либо снимок?

3. @Marcin — Я обновил вопрос примером кода.

4. @MiguelConde — Я лично не пытаюсь воссоздать кластер, Terraform определяет, что для обновления требуется заменить оригинал (уничтожить, а затем воссоздать). Когда он уничтожен, делается окончательный снимок. Однако я не нахожу способа сказать TF, что он должен использовать окончательный снимок на отдыхе. Все разумные меры, которые я принимал, приводили к провалу.

5. Итак, обнаруживает ли AWS изменения, даже если вы не запускали никаких обновлений на своем ресурсе aws_rds_cluster?

Ответ №1:

Решение оказалось довольно простым, хотя и неясным. Я испробовал более 50 различных подходов, используя комбинации существующих свойств ресурсов, поставщиков, нулевых ресурсов (с триггерами) и внешних блоков данных с командами AWS CLI и сценариями Powershell.

Проблема здесь заключалась в том, что мне нужно было убедиться, что подготовка выполняется в таком порядке, чтобы не допустить потери данных:

  1. Остановите задачи репликации DMS от репликации большего количества данных в базу данных.
  2. Сделайте новый снимок кластера, как только поступающие данные будут остановлены.
  3. Уничтожьте и воссоздайте кластер заново, используя snapshot_identifier для указания моментального снимка, сделанного на предыдущем шаге.
  4. Уничтожьте и воссоздайте задачи DMS заново.

Конечно, эти шаги были основаны на том, как Terraform решила, что ей необходимо применить обновления. Он может определить, что ему нужно выполнить обновление только на месте; меня это не касалось. Мне нужно было обрабатывать сценарии, в которых ресурсы были уничтожены.

Окончательное решение состояло в том, чтобы отказаться от использования внешних блоков данных и работать исключительно с локальными поставщиками, поскольку внешние блоки данных будут выполняться даже при запуске terraform plan . Я использовал локальных поставщиков для подключения к событиям жизненного цикла, таким как «создание» и «уничтожение», чтобы гарантировать, что мои сценарии Powershell будут выполняться только во terraform apply время .

В моем кластере я установил оба final_snapshot_identifier и snapshot_identifier на одно и то же значение.

 final_snapshot_identifier           = local.snapshot_identifier
snapshot_identifier    = data.external.check_for_first_run.result.isFirstRun == "true" ? null : local.snapshot_identifier
 

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

Затем я выполняю сценарий Powershell в локальном поставщике на «уничтожить», чтобы остановить любые задачи DMS, а затем удаляю снимок по имени local.snapshot_identifier .

   provisioner "local-exec" {
    when    = destroy
     # First, stop the inflow of data to the cluster by stopping the dms tasks.  
     # Next, we've tricked TF into thinking the snapshot we want to use is there by using the same name for old and new snapshots, but before we destroy the cluster, we need to delete the original.
     # Then TF will create the final snapshot immediately following the execution of the below script and it will be used to restore the cluster since we've set it as snapshot_identifier.
    command = "/powershell_scripts/stop_dms_tasks.ps1; aws rds delete-db-cluster-snapshot --db-cluster-snapshot-identifier benefitsystem-cluster"
    interpreter = ["PowerShell"]
  }
 

Это удаляет последний снимок и позволяет Terraform создать новый окончательный снимок с тем же именем, что и исходный, как раз вовремя, чтобы использовать его для восстановления.

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