สร้าง Database บน AWS RDS ด้วย Terraform
จากบทความก่อน เราจะมาต่อยอดด้วยการ ให้ api connect กับ database เพื่อสามารถเอาไปใช้งานใน use case จริงได้
rds (relational database service) คือชื่อ service นึง ของทาง aws ที่สามารถให้เราสร้าง RDBMS (relational database management system) ได้ตามความต้องการ โดยทาง aws ก็มีเราให้เลือกใช้มากมายเช่น MySql, PostgreSQL และ MariaDB เป็นต้น ซึ่งตัวอย่างในครั้งนี้ เราจะใช้ PostgreSQL กันครับ

จากที่เกริ่นไปแล้ว เราจะเพิ่ม RDS เข้าไปในระบบของเรา ที่มีอยู่ก่อนแล้ว เมื่อมาปรับ diagram จะเป็นไปตามภาพด้านล่าง คือให้ ECS ที่เป็น api สามารถเชื่อมต่อกับ RDS ได้ ซึ่งจะอยู่ใน private subnet เช่นกัน รวมถึงมีการใช้ secret manager ในการเก็บ password ของ database อีกด้วย

Let’s start !!
- สร้าง secret manager
เราจะสร้าง secret manager เพื่อเก็บ database password แต่ถ้าใครไม่ต้องการใช้ จะข้ามขั้นตอนนี้เลยก็ไม่ว่ากันครับ
# main.tf
..
..
resource "random_password" "random_db_password" {
length = 16
special = false
}
locals {
db_password = random_password.random_db_password.result
}
resource "aws_secretsmanager_secret" "db_secret" {
name = "terraform_postgres_db"
description = "terraform secret"
recovery_window_in_days = 0
tags = {
Name = "terraform secret"
}
}
resource "aws_secretsmanager_secret_version" "db_secret_version" {
secret_id = aws_secretsmanager_secret.db_secret.id
secret_string = local.db_password
}
จากโค้ด คือ generate random password 16 ตัวอักษร แล้วเอาไปเก็บไว้ที่ secret manager
2. เพิ่ม subnet ของ database เข้ากับ VPC
# var.tf
..
..
variable "database_subnet_cidrs" {
type = list(string)
default = ["10.0.5.0/24", "10.0.6.0/24"]
}
# main.tf
..
..
resource "aws_subnet" "database_subnets" {
count = length(var.database_subnet_cidrs)
vpc_id = aws_vpc.vpc.id
cidr_block = element(var.database_subnet_cidrs, count.index)
availability_zone = element(var.azs, count.index)
tags = {
Name = "terraform database subnet ${count.index + 1}"
}
}
resource "aws_route_table" "route_table_database" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "terraform database route table"
}
}
resource "aws_route_table_association" "database_subnet_asso" {
count = length(var.database_subnet_cidrs)
subnet_id = element(aws_subnet.database_subnets[*].id, count.index)
route_table_id = aws_route_table.route_table_database.id
}
เพิ่ม database subnet เป็น private subnet และ map เข้ากับ route table ใน VPC
3. สร้าง RDS
# main.tf
..
..
resource "aws_db_subnet_group" "db_subnet_group" {
name = "db-subnet-group"
subnet_ids = [for subnet in aws_subnet.database_subnets : subnet.id]
}
resource "aws_security_group" "rds" {
name = "terraform-sg-rds"
vpc_id = aws_vpc.vpc.id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
description = "Postgres"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "terraform security group rds"
}
}
resource "aws_db_instance" "rds" {
identifier = "rds-terraform"
instance_class = "db.t2.micro"
allocated_storage = 5
engine = "postgres"
engine_version = "12.13"
skip_final_snapshot = true
publicly_accessible = true
db_subnet_group_name = aws_db_subnet_group.db_subnet_group.id
vpc_security_group_ids = [aws_security_group.rds.id]
db_name = "terraform_db"
username = "postgres"
password = local.db_password
}
สร้าง security group โดยอนุญาตเฉพาะ port 5432 และเลือก postgres เป็น database พร้อมทั้งระบุ ชื่อ database, username และ password
4. เซต password ให้ container ที่ ECS task
container ของเราเมื่อมีการ connect database โดยปกติเราคงไม่ hardcode password ใน source code อยู่แล้ว เราจะระบุค่าของ password ผ่าน env variable ซึ่ง ECS ก็มีช่องทางให้เราสามารถจัดการเรื่องนี้ได้ ให้ไปแก้ไข task definitionapi_task
โดยเพิ่ม secrets
ตามนี้
# main.tf
..
..
resource "aws_ecs_task_definition" "api_task" {
family = "api_task"
container_definitions = <<DEFINITION
[
{
"name": "api_task",
"image": "${aws_ecr_repository.api_ecr.repository_url}",
"secrets": ${jsonencode([
{
"name": "DB_PASSWORD",
"valueFrom": "${aws_secretsmanager_secret_version.db_secret_version.arn}",
}
])},
..
..
}
]
..
..
}
และเพิ่ม role policy ให้ ECS สามารถ มีสิทธ์ในการเข้าถึง secret manager
# main.tf
..
..
resource "aws_iam_role_policy" "sm_policy" {
name = "terraform_sm_access_permissions"
role = aws_iam_role.ecsTaskExecutionRole.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"secretsmanager:GetSecretValue",
]
Effect = "Allow"
Resource = "*"
},
]
})
}
หลังจากนั้นก็ apply terraform และรอสักครู่ แล้วลองเรียก api ผ่าน ALB ไป path ที่เรามีการเชื่อมต่อกับ database

ยิง api เพื่อ insert ข้อมูล และยิง api เพื่อ select ข้อมูลได้สำเร็จเรียบร้อย ทีนี้เราก็สามารถนำไปประยุกต์ใช้งานจริงได้แล้วครับบบบ 🎉 🎉 🎉