From 5c1d69918d29ddaf97be64b0fc879d84cf894be2 Mon Sep 17 00:00:00 2001 From: Bill Monkman Date: Fri, 10 Jun 2022 11:51:35 -0700 Subject: [PATCH] feat: add support for creating RDS replica DBs. Warning: increases the required AWS provider version to 4.9. Otherwise, should be backwards compatible. --- modules/cache/main.tf | 4 +- modules/database/README.md | 6 ++- modules/database/main.tf | 71 ++++++++++++++++++++++------------- modules/database/outputs.tf | 5 +++ modules/database/variables.tf | 10 +++++ modules/database/versions.tf | 7 ++++ 6 files changed, 74 insertions(+), 29 deletions(-) diff --git a/modules/cache/main.tf b/modules/cache/main.tf index e695bee..d8cf57b 100644 --- a/modules/cache/main.tf +++ b/modules/cache/main.tf @@ -2,7 +2,7 @@ module "redis" { count = var.cache_store == "redis" ? 1 : 0 source = "cloudposse/elasticache-redis/aws" - version = "0.30.0" + version = "0.43.0" name = "redis" @@ -38,7 +38,7 @@ module "memcached" { count = var.cache_store == "memcached" ? 1 : 0 source = "cloudposse/elasticache-memcached/aws" - version = "0.10.0" + version = "0.15.1" name = "memcached" diff --git a/modules/database/README.md b/modules/database/README.md index fb3377e..35946f6 100644 --- a/modules/database/README.md +++ b/modules/database/README.md @@ -10,17 +10,19 @@ Create an RDS database. | Name | Version | |------|---------| | terraform | >= 0.13 | +| aws | >= 4.9 | ## Providers | Name | Version | |------|---------| -| aws | n/a | +| aws | >= 4.9 | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| additional\_identifier | An additional string to add to the rds identifier. The final string will look like: - | `string` | `""` | no | | allowed\_security\_group\_id | The security group to allow access | `any` | n/a | yes | | database\_engine | Which database engine to use, currently supports `postgres` or `mysql` | `any` | n/a | yes | | database\_engine\_version | Which database version to use. See the aws cli describe-db-engine-versions command for a list of valid versions | `any` | n/a | yes | @@ -32,6 +34,7 @@ Create an RDS database. | parameters | A list of DB parameters to set in a parameter group, passed directly to the underlying module | `list(map(string))` | `[]` | no | | password\_secret\_suffix | Suffix to add to the secret that will be generated containing the database credentials | `any` | n/a | yes | | project | The name of the project, mostly for tagging | `any` | n/a | yes | +| replicate\_from\_db\_id | Set this to the ID of a database to replicate from. If set, the database will be created as a read replica of the specified database | `any` | `null` | no | | storage\_gb | The amount of storage to allocate for the db, in GB | `any` | n/a | yes | | vpc\_id | The id of the VPC to create the DB in | `any` | n/a | yes | @@ -40,5 +43,6 @@ Create an RDS database. | Name | Description | |------|-------------| | database\_endpoint | The internal hostname used to connect to the database | +| database\_id | The instance id of the database | diff --git a/modules/database/main.tf b/modules/database/main.tf index ab07d76..916727e 100644 --- a/modules/database/main.tf +++ b/modules/database/main.tf @@ -1,9 +1,14 @@ +locals { + subnet_group_name = (var.replicate_from_db_id == null) ? ( + var.db_subnet_group != "" ? var.db_subnet_group : "${var.project}-${var.environment}-vpc" + ) : null +} module "rds_security_group" { source = "terraform-aws-modules/security-group/aws" version = "3.18.0" - name = "${var.project}-${var.environment}-rds-sg" + name = "${var.project}-${var.additional_identifier}${var.environment}-rds-sg" description = "Security group for RDS DB" vpc_id = var.vpc_id @@ -48,9 +53,9 @@ data "aws_secretsmanager_secret_version" "rds_master_secret" { module "rds_postgres" { count = var.database_engine == "postgres" ? 1 : 0 source = "terraform-aws-modules/rds/aws" - version = "3.5.0" + version = "4.3.0" - identifier = "${var.project}-${var.environment}" + identifier = "${var.project}-${var.additional_identifier}${var.environment}" engine = "postgres" engine_version = var.database_engine_version @@ -58,10 +63,12 @@ module "rds_postgres" { allocated_storage = var.storage_gb storage_encrypted = true - name = replace(var.project, "-", "") - username = "master_user" - password = data.aws_secretsmanager_secret_version.rds_master_secret.secret_string - port = "5432" + db_name = (var.replicate_from_db_id == null) ? replace(var.project, "-", "") : null + username = "master_user" + password = (var.replicate_from_db_id == null) ? data.aws_secretsmanager_secret_version.rds_master_secret.secret_string : null + create_random_password = false + + port = "5432" vpc_security_group_ids = [module.rds_security_group.this_security_group_id] @@ -69,11 +76,12 @@ module "rds_postgres" { backup_window = "03:00-06:00" # disable backups to create DB faster in non-production environments - backup_retention_period = var.environment == "prod" ? 30 : 0 + # note that read replicas can only replicate from databases with a backup period specified + backup_retention_period = (var.environment == "prod" && var.replicate_from_db_id == null) ? 30 : 0 # Subnet is created by the vpc module create_db_subnet_group = false - db_subnet_group_name = var.db_subnet_group != "" ? var.db_subnet_group : "${var.project}-${var.environment}-vpc" + db_subnet_group_name = local.subnet_group_name # DB parameter and option group family = var.parameter_group_family @@ -81,17 +89,21 @@ module "rds_postgres" { parameters = var.parameters - final_snapshot_identifier = "final-snapshot" - deletion_protection = true + final_snapshot_identifier_prefix = "final-snapshot" + skip_final_snapshot = (var.replicate_from_db_id != null) + deletion_protection = true # Enhanced monitoring - performance_insights_enabled = true + performance_insights_enabled = (var.replicate_from_db_id == null) create_monitoring_role = true - monitoring_role_name = "${var.project}-${var.environment}-rds-postgres-monitoring-role" + monitoring_role_name = "${var.project}-${var.additional_identifier}${var.environment}-rds-postgres-monitoring-role" monitoring_interval = "30" + # Read replica + replicate_source_db = var.replicate_from_db_id + tags = { - Name = "${var.project}-${var.environment}-rds-postgres" + Name = "${var.project}-${var.additional_identifier}${var.environment}-rds-postgres" Env = var.environment } depends_on = [module.rds_security_group] @@ -100,9 +112,9 @@ module "rds_postgres" { module "rds_mysql" { count = var.database_engine == "mysql" ? 1 : 0 source = "terraform-aws-modules/rds/aws" - version = "3.5.0" + version = "4.3.0" - identifier = "${var.project}-${var.environment}" + identifier = "${var.project}-${var.additional_identifier}${var.environment}" engine = "mysql" engine_version = var.database_engine_version @@ -110,10 +122,12 @@ module "rds_mysql" { allocated_storage = var.storage_gb storage_encrypted = true - name = replace(var.project, "-", "") - username = "master_user" - password = data.aws_secretsmanager_secret_version.rds_master_secret.secret_string - port = "3306" + db_name = (var.replicate_from_db_id == null) ? replace(var.project, "-", "") : null + username = "master_user" + password = (var.replicate_from_db_id == null) ? data.aws_secretsmanager_secret_version.rds_master_secret.secret_string : null + create_random_password = false + + port = "3306" vpc_security_group_ids = [module.rds_security_group.this_security_group_id] @@ -121,11 +135,12 @@ module "rds_mysql" { backup_window = "03:00-06:00" # disable backups to create DB faster in non-production environments - backup_retention_period = var.environment == "prod" ? 30 : 0 + # note that read replicas can only replicate from databases with a backup period specified + backup_retention_period = (var.environment == "prod" && var.replicate_from_db_id == null) ? 30 : 0 # Subnet is created by the vpc module create_db_subnet_group = false - db_subnet_group_name = var.db_subnet_group != "" ? var.db_subnet_group : "${var.project}-${var.environment}-vpc" + db_subnet_group_name = local.subnet_group_name # DB parameter and option group family = var.parameter_group_family @@ -133,8 +148,9 @@ module "rds_mysql" { parameters = var.parameters - final_snapshot_identifier = "final-snapshot" - deletion_protection = true + final_snapshot_identifier_prefix = "final-snapshot" + skip_final_snapshot = (var.replicate_from_db_id != null) + deletion_protection = true # Enhanced monitoring # Seems like mysql doesnt have performance insight on this instance size @@ -146,11 +162,14 @@ module "rds_mysql" { # all db.m6g instance classes, and all db.r6g instance classes. performance_insights_enabled = false create_monitoring_role = true - monitoring_role_name = "${var.project}-${var.environment}-rds-mysql-monitoring-role" + monitoring_role_name = "${var.project}-${var.additional_identifier}${var.environment}-rds-mysql-monitoring-role" monitoring_interval = "30" + # Read replica + replicate_source_db = var.replicate_from_db_id + tags = { - Name = "${var.project}-${var.environment}-rds-postgres" + Name = "${var.project}-${var.additional_identifier}${var.environment}-rds-mysql" Env = var.environment } depends_on = [module.rds_security_group] diff --git a/modules/database/outputs.tf b/modules/database/outputs.tf index 65f4767..64fb916 100644 --- a/modules/database/outputs.tf +++ b/modules/database/outputs.tf @@ -2,3 +2,8 @@ output "database_endpoint" { description = "The internal hostname used to connect to the database" value = (var.database_engine == "postgres") ? module.rds_postgres[0].db_instance_endpoint : module.rds_mysql[0].db_instance_endpoint } + +output "database_id" { + description = "The instance id of the database" + value = (var.database_engine == "postgres") ? module.rds_postgres[0].db_instance_id : module.rds_mysql[0].db_instance_id +} diff --git a/modules/database/variables.tf b/modules/database/variables.tf index 70e0ee2..abdc0b8 100644 --- a/modules/database/variables.tf +++ b/modules/database/variables.tf @@ -53,3 +53,13 @@ variable "parameters" { type = list(map(string)) default = [] } + +variable "replicate_from_db_id" { + description = "Set this to the ID of a database to replicate from. If set, the database will be created as a read replica of the specified database" + default = null +} + +variable "additional_identifier" { + description = "An additional string to add to the rds identifier. The final string will look like: -" + default = "" +} diff --git a/modules/database/versions.tf b/modules/database/versions.tf index 2606a5a..41eb9c3 100644 --- a/modules/database/versions.tf +++ b/modules/database/versions.tf @@ -1,4 +1,11 @@ terraform { required_version = ">= 0.13" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.9" + } + } }