pulumi_rds.py

import pulumi_random as random
import pulumi
import pulumi_aws as aws
def create_internal_vpc(name_prefix: str, vpc_cidr: str = "10.0.0.0/16") -> dict:
"""
Creates an isolated VPC for internal AWS communication.
Includes private subnets across different AZs for Multi-AZ capabilities,
and a Security Group locked down to internal PostgreSQL traffic.
"""
# VPC: The foundational isolated network layer.
# enable_dns_hostnames and enable_dns_support ensure RDS endpoints resolve correctly.
vpc = aws.ec2.Vpc(f"{name_prefix}-vpc",
cidr_block=vpc_cidr,
enable_dns_hostnames=True,
enable_dns_support=True)
# AZ 1 Subnet: Private isolation from the internet.
subnet_a = aws.ec2.Subnet(f"{name_prefix}-subnet-a",
vpc_id=vpc.id,
cidr_block="10.0.1.0/24",
availability_zone="us-east-1a")
# AZ 2 Subnet: Required by RDS to enable Multi-AZ failover.
subnet_b = aws.ec2.Subnet(f"{name_prefix}-subnet-b",
vpc_id=vpc.id,
cidr_block="10.0.2.0/24",
availability_zone="us-east-1b")
# DB Subnet Group: Instructs the RDS service on which subnets it is allowed to use.
db_subnet_group = aws.rds.SubnetGroup(f"{name_prefix}-subnet-group",
subnet_ids=[subnet_a.id, subnet_b.id])
# Security Group: Locked down to PostgreSQL traffic.
# The ingress rule uses self=True to allow only resources within this same SG to connect.
postgres_sg = aws.ec2.SecurityGroup(f"{name_prefix}-postgres-sg",
vpc_id=vpc.id,
ingress=[aws.ec2.SecurityGroupIngressArgs(
protocol="tcp",
from_port=5432,
to_port=5432,
self=True,
)],
egress=[aws.ec2.SecurityGroupEgressArgs(
protocol="-1",
from_port=0,
to_port=0,
cidr_blocks=["0.0.0.0/0"],
)])
# Export values so they can be consumed by other stacks or retrieved via the CLI.
pulumi.export(f"{name_prefix}_vpc_id", vpc.id)
pulumi.export(f"{name_prefix}_subnet_group_name", db_subnet_group.name)
pulumi.export(f"{name_prefix}_postgres_sg_id", postgres_sg.id)
return {
"vpc": vpc,
"db_subnet_group": db_subnet_group,
"postgres_sg": postgres_sg,
}
def create_rds_postgres_cluster(
name_prefix: str,
primary_instance_class: str,
dr_instance_class: str,
subnet_group_name: str,
security_group_id: str,
):
"""
Provisions a highly available RDS PostgreSQL cluster with an in-region replica for read scaling and a cross-region
replica for disaster recovery. Auto-scaling is employed to prevent performance issues.
The RDS instance will ony be available over a private AWS network.
The master password is created and stored in AWS Secrets Manager. The workflow supports easy rotation of the
master password.
pulumi taint urn:pulumi:stackname::projectname::random:random_password:RandomPassword$app-db-password
pulumi up
Automated RDS Features & DBA Workflows:
* Automatic Backups (PITR): Continuously streams Write-Ahead Logs (WAL) to S3, enabling
point-in-time recovery to any second within the retention period.
* Automated Maintenance: Applies OS patching and DB engine updates automatically
during a specified weekly maintenance window.
* Encryption at Rest: Transparently leverages AWS KMS to encrypt primary storage,
read replicas, and automated snapshots.
* IOPS & Storage Autoscaling: Provisions baseline IOPS based on storage size/type (e.g., GP3).
Storage autoscaling handles burst capacity dynamically without manual disk tuning.
* DBA Automation: Completely manages failover orchestration (via Multi-AZ), host
provisioning, and zero-downtime volume expansions, eliminating routine sysadmin tasks.
"""
db_password = random.RandomPassword(f"{name_prefix}-password",
length=24,
special=True,
override_special="!#$%&*()-_=+[]{}<>:?")
db_secret = aws.secretsmanager.Secret(f"{name_prefix}-secret")
db_secret_version = aws.secretsmanager.SecretVersion(f"{name_prefix}-secret-version",
secret_id=db_secret.id,
secret_string=db_password.result)
# 1. Primary DB: Handles write traffic.
# max_allocated_storage: Flips on storage autoscaling.
# multi_az: Provisions a synchronous standby in another AZ for automatic failover.
primary_db = aws.rds.Instance(f"{name_prefix}-primary",
engine="postgres",
engine_version="18.3",
instance_class=primary_instance_class,
allocated_storage=50,
max_allocated_storage=200, # Provides autoscaling up to this limit
db_name="appdb",
username="dbadmin",
password=db_password.result,
db_subnet_group_name=subnet_group_name,
vpc_security_group_ids=[security_group_id],
multi_az=True, # Multi-AZ failover
storage_encrypted=True, # Encryption at rest
backup_retention_period=7, # Must be > 0 to enable replication
publicly_accessible=False, # Explicitly blocks internet access, available only on private network
skip_final_snapshot=True
)
# 2. In-Region Read Replica: Offloads read queries from the primary.
# replicate_source_db uses the primary identifier for in-region replication.
in_region_replica = aws.rds.Instance(f"{name_prefix}-local-replica",
instance_class=primary_instance_class,
replicate_source_db=primary_db.identifier,
vpc_security_group_ids=[security_group_id],
storage_encrypted=True,
skip_final_snapshot=True
)
# 3. Cross-Region Replica: For Disaster Recovery.
dr_provider = aws.Provider(f"{name_prefix}-dr-provider", region="us-west-2")
dr_kms_key = aws.kms.get_key(key_id="alias/aws/rds", opts=pulumi.InvokeOptions(provider=dr_provider))
# Custom VPC in us-west-2 (using the DR provider)
dr_vpc = aws.ec2.Vpc("dr-vpc",
cidr_block="10.1.0.0/16",
enable_dns_hostnames=True,
enable_dns_support=True,
opts=pulumi.ResourceOptions(provider=dr_provider))
# Private Subnets in us-west-2
dr_subnet_a = aws.ec2.Subnet("dr-subnet-a",
vpc_id=dr_vpc.id,
cidr_block="10.1.1.0/24",
availability_zone="us-west-2a",
opts=pulumi.ResourceOptions(provider=dr_provider))
dr_subnet_b = aws.ec2.Subnet("dr-subnet-b",
vpc_id=dr_vpc.id,
cidr_block="10.1.2.0/24",
availability_zone="us-west-2b",
opts=pulumi.ResourceOptions(provider=dr_provider))
# Secondary DB Subnet Group in us-west-2
dr_db_subnet_group = aws.rds.SubnetGroup("dr-db-subnet-group",
subnet_ids=[dr_subnet_a.id, dr_subnet_b.id],
opts=pulumi.ResourceOptions(provider=dr_provider))
# Secondary Security Group in us-west-2
dr_postgres_sg = aws.ec2.SecurityGroup("dr-postgres-sg",
vpc_id=dr_vpc.id,
ingress=[aws.ec2.SecurityGroupIngressArgs(
protocol="tcp", from_port=5432, to_port=5432, self=True
)],
opts=pulumi.ResourceOptions(provider=dr_provider))
# Pass the DR Subnet Group and Security Group to the DR Replica
dr_replica = aws.rds.Instance("dr-replica",
instance_class=dr_instance_class,
replicate_source_db=primary_db.arn,
db_subnet_group_name=dr_db_subnet_group.name, # Bound to us-west-2 VPC
vpc_security_group_ids=[dr_postgres_sg.id], # Bound to us-west-2 VPC
publicly_accessible=False,
storage_encrypted=True,
kms_key_id=dr_kms_key.arn,
skip_final_snapshot=True,
opts=pulumi.ResourceOptions(provider=dr_provider))
# Exports for application consumption
pulumi.export("write_endpoint", primary_db.endpoint)
pulumi.export("read_endpoint", in_region_replica.endpoint)
pulumi.export("dr_endpoint", dr_replica.endpoint)
# Export the automatically generated secret ARN so your app services (ECS/EC2) can retrieve it
pulumi.export("db_secret_arn", primary_db.master_user_secrets[0].secret_arn)
return primary_db, in_region_replica, dr_replica
if __name__ == "__main__":
network = create_internal_vpc(name_prefix="core-prod")
# ~$50 per month cost for all three instances
# trivial to scale up CPU, RAM, and IOPS (can be provisioned separately)
database = create_rds_postgres_cluster(
name_prefix="app-db",
primary_instance_class="db.t3.small", # consistent baseline of 3,000 IOPS and 125 MiB/s; 2 vCPUs and 1 GB of RAM;
dr_instance_class="db.t3.micro",
subnet_group_name=network["db_subnet_group"].name,
security_group_id=network["postgres_sg"].id,
)
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论