Terraform资源重新创建动态AWS RDS实例计数

时间:2019-01-23 15:37:49

标签: terraform terraform-provider-aws

我有一个与AWS RDS集群和实例创建有关的问题。

环境

我们最近进行了实验:

  

Terraform v0.11.11    provider.aws v1.41.0

背景

创建一些AWS RDS数据库。我们的任务是,在某些环境(例如分阶段)中,我们可以比在其他环境(例如生产)中运行更少的实例。考虑到这一点,并且不想在每个环境中使用完全不同的terraform文件,我们决定只指定一次数据库资源,并使用变量来设置staging.tfproduction.tf中设置的实例数文件分别用于实例数量。

我们的设置可能还有一个“怪胎”,即存在子网的VPC并非以Terraform定义,VPC已经通过AWS控制台中的手动创建而存在,因此它是作为数据提供者提供的, RDS的子网在terraform中是特定的-但是从某种意义上讲,这是动态的,在某些环境中,我们可能有3个子网(每个AZ中有1个),而在其他环境中,也许只有2个子网。为了达到这一目的,我们再次使用了迭代,如下所示:

结构

|-/environments
     -/staging
         -staging.tf
     -/production
         -production.tf
|- /resources
     - database.tf

示例环境变量文件

  • dev.tf
terraform {
  terraform {
  backend "s3" {
    bucket         = "my-bucket-dev"
    key            = "terraform"
    region         = "eu-west-1"
    encrypt        = "true"
    acl            = "private"
    dynamodb_table = "terraform-state-locking"
  }

  version = "~> 0.11.8"
}

provider "aws" {
  access_key          = "${var.access_key}"
  secret_key          = "${var.secret_key}"
  region              = "${var.region}"
  version             = "~> 1.33"
  allowed_account_ids = ["XXX"]
}

module "main" {
  source                                  = "../../resources"
  vpc_name                                = "test"
  test_db_name                    = "terraform-test-db-dev"
  test_db_instance_count          = 1
  test_db_backup_retention_period = 7
  test_db_backup_window           = "00:57-01:27"
  test_db_maintenance_window      = "tue:04:40-tue:05:10"
  test_db_subnet_count            = 2
  test_db_subnet_cidr_blocks      = ["10.2.4.0/24", "10.2.5.0/24"]
}

主要由于以下讨论,我们来到了基于模块的环境隔离结构:

我们的问题

初始资源创建工作正常,我们的子网已创建,数据库集群已启动。

我们的问题在下一次我们随后运行terraform planterraform apply(文件没有更改)时开始,此时我们会看到有趣的事情,例如:

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:
module.main.aws_rds_cluster.test_db (new resource required)
id: "terraform-test-db-dev" => (forces new resource)
availability_zones.#: "3" => "1" (forces new resource)
availability_zones.1924028850: "eu-west-1b" => "" (forces new resource)
availability_zones.3953592328: "eu-west-1a" => "eu-west-1a"
availability_zones.94988580: "eu-west-1c" => "" (forces new resource)

module.main.aws_rds_cluster_instance.test_db (new resource required)
id: "terraform-test-db-dev" => (forces new resource)
cluster_identifier: "terraform-test-db-dev" => "${aws_rds_cluster.test_db.id}" (forces new resource)

关于我们如何解决此问题的某种方式似乎正在使terraform相信资源已发生了一定程度的变化,以致它必须销毁现有资源并创建全新的资源。

配置

variable "aws_availability_zones" {
  description = "Run the EC2 Instances in these Availability Zones"
  type        = "list"
  default     = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
}

variable "test_db_name" {
  description = "Name of the RDS instance, must be unique per region and is provided by the module config"
}

variable "test_db_subnet_count" {
  description = "Number of subnets to create, is provided by the module config"
}

resource "aws_security_group" "test_db_service" {
  name   = "${var.test_db_service_user_name}"
  vpc_id = "${data.aws_vpc.vpc.id}"
}

resource "aws_security_group" "test_db" {
  name   = "${var.test_db_name}"
  vpc_id = "${data.aws_vpc.vpc.id}"
}

resource "aws_security_group_rule" "test_db_ingress_app_server" {
  security_group_id        = "${aws_security_group.test_db.id}"
...
  source_security_group_id = "${aws_security_group.test_db_service.id}"
}

variable "test_db_subnet_cidr_blocks" {
  description = "Cidr block allocated to the subnets"
  type        = "list"
}

resource "aws_subnet" "test_db" {
  count             = "${var.test_db_subnet_count}"
  vpc_id            = "${data.aws_vpc.vpc.id}"
  cidr_block        = "${element(var.test_db_subnet_cidr_blocks, count.index)}"
  availability_zone = "${element(var.aws_availability_zones, count.index)}"
}

resource "aws_db_subnet_group" "test_db" {
  name       = "${var.test_db_name}"
  subnet_ids = ["${aws_subnet.test_db.*.id}"]
}

variable "test_db_backup_retention_period" {
  description = "Number of days to keep the backup, is provided by the module config"
}

variable "test_db_backup_window" {
  description = "Window during which the backup is done, is provided by the module config"
}

variable "test_db_maintenance_window" {
  description = "Window during which the maintenance is done, is provided by the module config"
}

data "aws_secretsmanager_secret" "test_db_master_password" {
  name = "terraform/db/test-db/root-password"
}

data "aws_secretsmanager_secret_version" "test_db_master_password" {
  secret_id = "${data.aws_secretsmanager_secret.test_db_master_password.id}"
}

data "aws_iam_role" "rds-monitoring-role" {
  name = "rds-monitoring-role"
}

resource "aws_rds_cluster" "test_db" {
  cluster_identifier = "${var.test_db_name}"
  engine             = "aurora-mysql"
  engine_version     = "5.7.12"

  # can only request to deploy in AZ's where there is a subnet in the subnet group.
  availability_zones              = "${slice(var.aws_availability_zones, 0, var.test_db_instance_count)}"
  database_name                   = "${var.test_db_schema_name}"
  master_username                 = "root"
  master_password                 = "${data.aws_secretsmanager_secret_version.test_db_master_password.secret_string}"
  preferred_backup_window         = "${var.test_db_backup_window}"
  preferred_maintenance_window    = "${var.test_db_maintenance_window}"
  backup_retention_period         = "${var.test_db_backup_retention_period}"
  db_subnet_group_name            = "${aws_db_subnet_group.test_db.name}"
  storage_encrypted               = true
  kms_key_id                      = "${data.aws_kms_key.kms_rds_key.arn}"
  deletion_protection             = true
  enabled_cloudwatch_logs_exports = ["audit", "error", "general", "slowquery"]
  vpc_security_group_ids          = ["${aws_security_group.test_db.id}"]
  final_snapshot_identifier       = "test-db-final-snapshot"
}

variable "test_db_instance_count" {
  description = "Number of instances to create, is provided by the module config"
}

resource "aws_rds_cluster_instance" "test_db" {
  count                = "${var.test_db_instance_count}"
  identifier           = "${var.test_db_name}"
  cluster_identifier   = "${aws_rds_cluster.test_db.id}"
  availability_zone    = "${element(var.aws_availability_zones, count.index)}"
  instance_class       = "db.t2.small"
  db_subnet_group_name = "${aws_db_subnet_group.test_db.name}"
  monitoring_interval  = 60
  engine               = "aurora-mysql"
  engine_version       = "5.7.12"
  monitoring_role_arn  = "${data.aws_iam_role.rds-monitoring-role.arn}"

  tags {
    Name = "test_db-${count.index}"
  }
}

我的问题是,有没有办法做到这一点,以便terraform不会尝试重新创建资源(例如,确保每次我们运行terraform时群集的可用区和实例的ID都不会改变。 >

1 个答案:

答案 0 :(得分:2)

结果证明,只需从aws_rds_clusteraws_rds_cluster_instance中删除显式的可用区定义,此问题就消失了,到目前为止,一切似乎都可以正常工作。另请参见https://github.com/terraform-providers/terraform-provider-aws/issues/7307#issuecomment-457441633