week-7: PostgreSQL RDS integration — terraform, backend, pipeline
This commit is contained in:
@@ -57,11 +57,17 @@ resource "aws_instance" "app" {
|
||||
docker pull ${var.aws_account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/task-backend:latest
|
||||
docker pull ${var.aws_account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/task-frontend:latest
|
||||
|
||||
# Run backend
|
||||
# Run backend — DB credentials passed as environment variables
|
||||
# Values come from Terraform variables which are sourced from GitHub Secrets
|
||||
docker run -d \
|
||||
--name task-backend \
|
||||
--restart unless-stopped \
|
||||
-p 3000:3000 \
|
||||
-e DB_HOST=${var.db_host} \
|
||||
-e DB_PORT=5432 \
|
||||
-e DB_NAME=${var.db_name} \
|
||||
-e DB_USER=${var.db_username} \
|
||||
-e DB_PASSWORD=${var.db_password} \
|
||||
${var.aws_account_id}.dkr.ecr.${var.aws_region}.amazonaws.com/task-backend:latest
|
||||
|
||||
# Wait for backend to be ready
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# ─────────────────────────────────────────────
|
||||
# RDS — PostgreSQL for Scalable Task Platform
|
||||
# Week 7 | infra/terraform/rds.tf
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
# ── DB Subnet Group ──────────────────────────
|
||||
# RDS needs to know which subnets it can live in.
|
||||
# We use the private subnets so it is never
|
||||
# reachable from the public internet.
|
||||
resource "aws_db_subnet_group" "tasks" {
|
||||
name = "${var.project_name}-db-subnet-group"
|
||||
subnet_ids = aws_subnet.private[*].id
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-db-subnet-group"
|
||||
Project = var.project_name
|
||||
}
|
||||
}
|
||||
|
||||
# ── Security Group: RDS ──────────────────────
|
||||
# Only the EC2 instance security group may reach
|
||||
# the database on port 5432. No public access.
|
||||
resource "aws_security_group" "rds" {
|
||||
name = "${var.project_name}-rds-sg"
|
||||
description = "Allow PostgreSQL access from EC2 only"
|
||||
vpc_id = aws_vpc.main.id
|
||||
|
||||
ingress {
|
||||
description = "PostgreSQL from EC2"
|
||||
from_port = 5432
|
||||
to_port = 5432
|
||||
protocol = "tcp"
|
||||
security_groups = [aws_security_group.ec2.id]
|
||||
}
|
||||
|
||||
egress {
|
||||
description = "Allow all outbound"
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-rds-sg"
|
||||
Project = var.project_name
|
||||
}
|
||||
}
|
||||
|
||||
# ── RDS Parameter Group ──────────────────────
|
||||
# Explicit parameter group gives you a place to
|
||||
# tune Postgres settings later without replacing
|
||||
# the instance.
|
||||
resource "aws_db_parameter_group" "tasks" {
|
||||
name = "${var.project_name}-pg16"
|
||||
family = "postgres16"
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-pg16"
|
||||
Project = var.project_name
|
||||
}
|
||||
}
|
||||
|
||||
# ── RDS Instance ─────────────────────────────
|
||||
resource "aws_db_instance" "tasks" {
|
||||
identifier = "${var.project_name}-db"
|
||||
|
||||
# Engine
|
||||
engine = "postgres"
|
||||
engine_version = "16"
|
||||
instance_class = "db.t3.micro" # Free-tier eligible
|
||||
|
||||
# Storage
|
||||
allocated_storage = 20
|
||||
max_allocated_storage = 100 # Enable storage autoscaling up to 100 GB
|
||||
storage_type = "gp2"
|
||||
storage_encrypted = true
|
||||
|
||||
# Credentials — sourced from Terraform variables
|
||||
# which are populated from GitHub Secrets via the pipeline
|
||||
db_name = var.db_name
|
||||
username = var.db_username
|
||||
password = var.db_password
|
||||
|
||||
# Network
|
||||
db_subnet_group_name = aws_db_subnet_group.tasks.name
|
||||
vpc_security_group_ids = [aws_security_group.rds.id]
|
||||
publicly_accessible = false
|
||||
multi_az = false # Single-AZ is fine for this stage
|
||||
|
||||
# Maintenance
|
||||
parameter_group_name = aws_db_parameter_group.tasks.name
|
||||
backup_retention_period = 7
|
||||
backup_window = "03:00-04:00"
|
||||
maintenance_window = "Mon:04:00-Mon:05:00"
|
||||
deletion_protection = false # Set to true before production hardening (Week 10)
|
||||
|
||||
# Lifecycle — prevent accidental destroy on credential rotation
|
||||
lifecycle {
|
||||
ignore_changes = [password]
|
||||
}
|
||||
|
||||
skip_final_snapshot = true # Change to false and set final_snapshot_identifier for production
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-db"
|
||||
Project = var.project_name
|
||||
}
|
||||
}
|
||||
|
||||
# ── Outputs ───────────────────────────────────
|
||||
# The EC2 user-data script and any future modules
|
||||
# that need the DB endpoint will read these.
|
||||
output "rds_endpoint" {
|
||||
description = "RDS instance endpoint (host:port)"
|
||||
value = aws_db_instance.tasks.endpoint
|
||||
}
|
||||
|
||||
output "rds_hostname" {
|
||||
description = "RDS hostname only (no port)"
|
||||
value = aws_db_instance.tasks.address
|
||||
}
|
||||
|
||||
output "rds_port" {
|
||||
description = "RDS port"
|
||||
value = aws_db_instance.tasks.port
|
||||
}
|
||||
|
||||
output "rds_db_name" {
|
||||
description = "Database name"
|
||||
value = aws_db_instance.tasks.db_name
|
||||
}
|
||||
@@ -36,4 +36,26 @@ variable "private_subnet_cidr" {
|
||||
description = "CIDR block for the private subnet"
|
||||
type = string
|
||||
default = "10.0.2.0/24"
|
||||
}
|
||||
}
|
||||
variable "db_name" {
|
||||
description = "PostgreSQL database name"
|
||||
type = string
|
||||
default = "tasksdb"
|
||||
}
|
||||
|
||||
variable "db_username" {
|
||||
description = "PostgreSQL master username"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "db_password" {
|
||||
description = "PostgreSQL master password"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
variable "db_host" {
|
||||
description = "RDS instance hostname — output from aws_db_instance.tasks.address"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user