Terraform для AWS serverless v2 кластера RDS Postgres
AWS RDS Cluster serverless V2
Зачем нам serverless V2
К чему нам вообще AWS RDS serverless v2? Он даже двое дороже чем V1 из расчета за один вычислительный юнит.
Ну, например если вам понадобился RDS Proxy (AWS вариант pg_bouncer) то у вас просто нет выхода. RDS proxy не поддерживается для serverless V1.
Еще более сильный аргумент в том, что V2 тупо более продвинутая и современная версия с повышенной надежностью и масштабированием.
Terraform
Удивительно, но хотя RDS serveless v2 существует с 2020 года, внятной документации найти не удалось и поэтому и родился этот текст.
RDS Cluster
resource "aws_db_subnet_group" "this" {
name = "my-serveless-v2-rds-cluster"
subnet_ids = var.subnets # your subnets
}
resource "aws_rds_cluster" "this" {
#checkov:skip=CKV_AWS_139: Deletion protection does not play well with terraform
#checkov:skip=CKV_AWS_327: Just encryption without KMS is ok
#checkov:skip=CKV_AWS_162: plain password is ok for PACS Server, we do not need IAM auth
#checkov:skip=CKV_AWS_324: we do not need DB logs
cluster_identifier = "my-serveless-v2-rds-cluster"
engine = "aurora-postgresql"
engine_mode = "provisioned"
engine_version = "13.6"
master_username = jsondecode(aws_secretsmanager_secret_version.database.secret_string)["username"]
master_password = jsondecode(aws_secretsmanager_secret_version.database.secret_string)["password"]
db_subnet_group_name = aws_db_subnet_group.this.name
vpc_security_group_ids = var.ecs_security_groups # your security groups
skip_final_snapshot = true
deletion_protection = false
storage_encrypted = true
backup_retention_period = 7
copy_tags_to_snapshot = true
db_cluster_parameter_group_name = "default.aurora-postgresql13"
database_name = "mydb"
serverlessv2_scaling_configuration {
min_capacity = 0.5
max_capacity = var.db_max_units # your setting for max ACUs
}
}
Первый сюрприз - provisioned
режим. Для serverless V1 использовался более логичный serverless
.
Немаловажна и версия Postgres. Serverless V2 работает только для версий после 13.6.
И еще неожиданность - сбросить вычислительные юниты до 0, как это позволял serverless V1, невозможно. Минимум 0.5 ACU. Это примерно $45 в месяц.
Магию с jsondecode
я объясню позднее, пока воспринимайте это просто как некие секреты для авторизации в БД.
Важный момент - использование serverlessv2_scaling_configuration
, только он подходит для serverless V2.
RDS instance
И снова неожиданность - для RDS serverless V2 вам нужен instance.
Если для serverless V1 достаточно было описать RDS cluster, здесь это не работает.
Без этого в serverless v2 создание endpoints навсегда застрянет в статусе creating
.
resource "aws_rds_cluster_instance" "this" {
identifier = "my-serveless-v2-rds"
cluster_identifier = aws_rds_cluster.this.id
instance_class = "db.serverless"
engine = aws_rds_cluster.this.engine
engine_version = aws_rds_cluster.this.engine_version
auto_minor_version_upgrade = true
monitoring_interval = 5
tags = var.tags
}
Обратите внимание на специальный класс db.serverless
.
Чтобы оставаться сухими (DRY) мы ссылаемся на значения
для engine
и engine_version
в кластере.
Кластер будет создаваться неспешно, дождитесь когда он будет готов к работе.
Secrets
Я обещал объяснить про jsondecode
.
Мы создаем случайный пароль и сохраняем его в AWS Secrets Manager. Далее создаем RDS Cluster указывая этот пароль.
А после создания DB Cluster добавляем endpoint и название database в тот же самый секрет. Это уже не секреты, конечно, но удобно, когда все в одном месте.
Вся эта магия происходит автоматически благодаря следующему коду:
resource "random_password" "db" {
length = 16
special = false
}
resource "aws_secretsmanager_secret" "database" {
#checkov:skip=CKV_AWS_149: do not need KMS encryption here
name = "database"
description = "Master username and password for the database"
recovery_window_in_days = 0 # it's perfectly safe to delete and we do not need AWS delete protection
}
resource "aws_secretsmanager_secret_version" "database" {
# Store credentials before RDS cluster created
secret_id = aws_secretsmanager_secret.database.id
secret_string = jsonencode({
username = "myuser"
password = random_password.db.result
})
}
resource "aws_secretsmanager_secret_version" "database_endpoint" {
# Store endpoint after RDS cluster created
secret_id = aws_secretsmanager_secret.database.id
secret_string = jsonencode({
database = jsondecode(aws_secretsmanager_secret_version.database.secret_string)["database"]
username = jsondecode(aws_secretsmanager_secret_version.database.secret_string)["username"]
password = jsondecode(aws_secretsmanager_secret_version.database.secret_string)["password"]
endpoint = aws_rds_cluster.this.endpoint
databse = aws_rds_cluster.this.database_name
})
depends_on = [aws_rds_cluster.this]
}
Поскольку все манипуляции с секретами выполняет terraform нет необходимости в специальных IAM. Но конечно сам terraform надо запускать так, чтобы он имел доступ к AWS Secrets Manager.