Setup#
Let install postgresqlfor Amazon Linux 2023
sudo dnf updatesudo dnf install postgresql15.x86_64 postgresql15-serversudo yum install postgresql15-contrib.x86_64
Command to check installed package and find package
yum search all postgresql15-contribrpm -qa | grep postgresql15-contribyum list installed | grep postgres
Basic Query#
Clear screen
\! clear
List database
\list;
List table
\dt;
List user
\du
Check current user
\conninfo
Check where files are stored
SELECT *, pg_tablespace_location(oid) FROM pg_tablespace;
Generate Data#
psql -h localhost -P 5432 -U demo -d dvdrental
Check the generate_series function.
psql select * from generate_series(1, 10);
Create a student table
CREATE TABLE if not EXISTS student (id SERIAL PRIMARY KEY,name TEXT,login TEXT,age INT,gpa REAL);
Insert a student in to the table
INSERT INTO student(name, login, age, gpa) VALUES('mike','mike@gmail.com',24,4.0);
Insert 1000 students into the table using generate_series
INSERT INTO student(name, login, age, gpa) VALUES('mike','mike@gmail.com',generate_series(1,1000),4.0)
Extension and Pages#
Install pg_freespacemap extension
CREATE EXTENSION 'pg_freespacemap';
Check available space (pages)
SELECT *, round(100 * avail/8192, 2) as "freespace ratio" FROM pg_freespace('student');
Check the pg_freespace table
SELECT * FROM pg_freespace;
Show available extensions
SELECT * FROM pg_extension;
Locate where files of database stored
dvdrental=# select pg_relation_filepath('student');pg_relation_filepath----------------------base/16388/16731(1 row)
Monitor Connection#
Check the max connection configuration.
SELECT * FROM pg_settings WHERE name = 'max_connections';
Edit the max connection from configuration file.
/var/lib/pgsql/{version_number}/data/postgresql.conf
Query current number of connection to database.
SELECT sum(numbackends) FROM pg_stat_database WHERE datname is not null;SELECT count(*) FROM pg_stat_activity WHERE datname is not null;
Count Idle Connection#
- Query from pg_stat_activity table
- Analyze from Amazon RDS prformance insights and CloudWatch
Let count number of active session.
select count(*) from (select state from pg_stat_activity where state='active') x;
Let count number of idle session.
select count(*) from (select state from pg_stat_activity where state='idle') x;
For more information about the pg_stat_activity table
Troubleshooting#
Search package
yum search all postgresql15-contrib
Then install
yum install postgresql15-contrib.x86_64
Search installed package
rpm -qa | grep postgres
Search installed packages
yum list installed | grep postgres
Golang Simple Test#
Let write go script to test connection:
- ping connection
- simple query
- concurrent user and connection
database_connection_test.go
package testimport ("database/sql""entest/postgresql/config""fmt"_ "github.com/lib/pq""testing""time")func TestPingDatabase(t *testing.T) {fmt.Println("test sending connections to database")// connection string to database postgresqlconnStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s", config.HOST, config.PORT, config.USER, config.DB_NAME, config.PASSWORD)// ping databasedb, error := sql.Open("postgres", connStr)if error != nil {panic(error)}error = db.Ping()if error != nil {panic(error)}fmt.Println("Successfully connected to database")}func TestQuerySelectStudent(t *testing.T) {fmt.Println("test sending connections to database")// connection string to database postgresqlconnStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s", config.HOST, config.PORT, config.USER, config.DB_NAME, config.PASSWORD)// ping databasedb, error := sql.Open("postgres", connStr)if error != nil {panic(error)}// query a tablerows, error := db.Query("SELECT * FROM student LIMIT 100;")if error != nil {panic(error)}// parse rows responsefor rows.Next() {var id intvar name stringvar login stringvar age intvar gpa float32error = rows.Scan(&id, &name, &login, &age, &gpa)if error != nil {panic(error)}fmt.Println(id, name, login, age, gpa)}}func TestConcurrentConnection(t *testing.T) {var num_user int = 500// create a channelchannel := make(chan int, num_user)// loop to run 10 connections using goroutinefor i := 0; i < num_user; i++ {go func(user int) {// connection string to database postgresqlconnStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s", config.HOST, config.PORT, config.USER, config.DB_NAME, config.PASSWORD)// ping databasedb, error := sql.Open("postgres", connStr)if error != nil {panic(error)}// infinite loopvar count int = 0for {// query a tablerows, error := db.Query("SELECT count(*) FROM student;")if error != nil {panic(error)}// close db connection// defer rows.Close()// defer db.Close()// parse number of student from query resultvar n_student intfor rows.Next() {rows.Scan(&n_student)}fmt.Printf("loop: %d, user: %d num student: %d\n", count, user, n_student)// sleep few secondstime.Sleep(3 * time.Second)count += 1}// send a message to channelchannel <- 1}(i)}// retrieve values from the channel to wait for go routine completedfor i := 0; i < num_user; i++ {fmt.Println(<-channel)}}
CloudFormation Template#
Network stack.
1-network.yaml
AWSTemplateFormatVersion: "2010-09-09"#------------------------------------------------------# Mappings#------------------------------------------------------Mappings:CidrMappings:public-subnet-1:CIDR: 10.0.0.0/24public-subnet-2:CIDR: 10.0.2.0/24public-subnet-3:CIDR: 10.0.4.0/24private-subnet-1:CIDR: 10.0.1.0/24private-subnet-2:CIDR: 10.0.3.0/24private-subnet-3:CIDR: 10.0.5.0/24#------------------------------------------------------# Parameters#------------------------------------------------------Parameters:CidrBlock:Type: StringDescription: CidrBlockDefault: 10.0.0.0/16InternetCidrBlock:Type: StringDescription: UserCidrBlockDefault: 0.0.0.0/0#------------------------------------------------------# Resources: VPC, Subnets, NAT, Routes#------------------------------------------------------Resources:VPC:Type: AWS::EC2::VPCMetadata:cfn_nag:rules_to_suppress:- id: W60reason: VPC flow logs not required for this exampleProperties:CidrBlock: !Ref CidrBlockEnableDnsSupport: trueEnableDnsHostnames: trueTags:- Key: NameValue: !Sub ${AWS::StackName}-vpc#------------------------------------------------------# Resources: internet gateway#------------------------------------------------------InternetGateway:Type: AWS::EC2::InternetGatewayProperties:Tags:- Key: NameValue: !Sub ${AWS::StackName}-igAttachGateway:Type: AWS::EC2::VPCGatewayAttachmentProperties:VpcId: !Ref VPCInternetGatewayId: !Ref InternetGateway#------------------------------------------------------# Resources: public and private subnets#------------------------------------------------------PublicSubnet1:Type: AWS::EC2::SubnetProperties:MapPublicIpOnLaunch: falseAvailabilityZone:Fn::Select: - 0 - Fn::GetAZs:Ref: AWS::RegionVpcId: !Ref VPCCidrBlock:Fn::FindInMap: - CidrMappings - public-subnet-1 - CIDRTags: - Key: NameValue: !Sub ${AWS::StackName}-public-subnet-1PublicSubnet2:Type: AWS::EC2::SubnetProperties:MapPublicIpOnLaunch: falseAvailabilityZone:Fn::Select: - 1 - Fn::GetAZs:Ref: AWS::RegionVpcId: !Ref VPCCidrBlock:Fn::FindInMap: - CidrMappings - public-subnet-2 - CIDRTags: - Key: NameValue: !Sub ${AWS::StackName}-public-subnet-2PublicSubnet3:Type: AWS::EC2::SubnetProperties:MapPublicIpOnLaunch: falseAvailabilityZone:Fn::Select: - 2 - Fn::GetAZs:Ref: AWS::RegionVpcId: !Ref VPCCidrBlock:Fn::FindInMap: - CidrMappings - public-subnet-3 - CIDRTags: - Key: NameValue: !Sub ${AWS::StackName}-public-subnet-3PrivateSubnet1:Type: AWS::EC2::SubnetProperties:MapPublicIpOnLaunch: falseAvailabilityZone:Fn::Select: - 0 - Fn::GetAZs:Ref: AWS::RegionVpcId: !Ref VPCCidrBlock:Fn::FindInMap: - CidrMappings - private-subnet-1 - CIDRTags: - Key: NameValue: !Sub ${AWS::StackName}-private-subnet-1PrivateSubnet2:Type: AWS::EC2::SubnetProperties:MapPublicIpOnLaunch: falseAvailabilityZone:Fn::Select: - 1 - Fn::GetAZs:Ref: AWS::RegionVpcId: !Ref VPCCidrBlock:Fn::FindInMap: - CidrMappings - private-subnet-2 - CIDRTags: - Key: NameValue: !Sub ${AWS::StackName}-private-subnet-2PrivateSubnet3:Type: AWS::EC2::SubnetProperties:MapPublicIpOnLaunch: falseAvailabilityZone:Fn::Select: - 2 - Fn::GetAZs:Ref: AWS::RegionVpcId: !Ref VPCCidrBlock:Fn::FindInMap: - CidrMappings - private-subnet-3 - CIDRTags: - Key: NameValue: !Sub ${AWS::StackName}-private-subnet-3#------------------------------------------------------# Resources: nat gateway#------------------------------------------------------NatGatewayEIP:Type: AWS::EC2::EIPProperties:Domain: vpcNatGateway:Type: AWS::EC2::NatGatewayProperties:AllocationId:Fn::GetAtt: [NatGatewayEIP, AllocationId]SubnetId: !Ref PublicSubnet1Tags: - Key: NameValue: !Sub ${AWS::StackName}-nat-gateway#------------------------------------------------------# Resources: public route table#------------------------------------------------------PublicRouteTable:Type: AWS::EC2::RouteTableProperties:VpcId: !Ref VPCTags: - Key: NameValue: !Sub ${AWS::StackName}-public-rtRouteInternetGateway:Type: AWS::EC2::RouteDependsOn: AttachGatewayProperties:RouteTableId: !Ref PublicRouteTableDestinationCidrBlock: !Ref InternetCidrBlockGatewayId: !Ref InternetGateway#------------------------------------------------------# Resources: private route table#------------------------------------------------------PrivateRouteTable:Type: AWS::EC2::RouteTableProperties:VpcId: !Ref VPCTags: - Key: NameValue: !Sub ${AWS::StackName}-private-rtPrivateRoute:Type: AWS::EC2::RouteProperties:RouteTableId: !Ref PrivateRouteTableDestinationCidrBlock: !Ref InternetCidrBlockNatGatewayId: !Ref NatGateway#------------------------------------------------------# Resources: route table subnet associations#------------------------------------------------------PublicSubnet1RouteTableAssociation:Type: AWS::EC2::SubnetRouteTableAssociationProperties:SubnetId: !Ref PublicSubnet1RouteTableId: !Ref PublicRouteTablePublicSubnet2RouteTableAssociation:Type: AWS::EC2::SubnetRouteTableAssociationProperties:SubnetId: !Ref PublicSubnet2RouteTableId: !Ref PublicRouteTablePublicSubnet3RouteTableAssociation:Type: AWS::EC2::SubnetRouteTableAssociationProperties:SubnetId: !Ref PublicSubnet3RouteTableId: !Ref PublicRouteTablePrivateSubnet1RouteTableAssociation:Type: AWS::EC2::SubnetRouteTableAssociationProperties:SubnetId: !Ref PrivateSubnet1RouteTableId: !Ref PrivateRouteTablePrivateSubnet2RouteTableAssociation:Type: AWS::EC2::SubnetRouteTableAssociationProperties:SubnetId: !Ref PrivateSubnet2RouteTableId: !Ref PrivateRouteTablePrivateSubnet3RouteTableAssociation:Type: AWS::EC2::SubnetRouteTableAssociationProperties:SubnetId: !Ref PrivateSubnet3RouteTableId: !Ref PrivateRouteTable#------------------------------------------------------# WebServerSecurityGroup:#------------------------------------------------------WebServerSecurityGroup:Type: AWS::EC2::SecurityGroupMetadata:cfn_nag:rules_to_suppress: - id: W5reason: return traffic to user from internet for testing - id: W40reason: egress open all port for the internetProperties:GroupDescription: web server security groupVpcId: !Ref VPCWebServerSecurityGroupEgress:Type: AWS::EC2::SecurityGroupEgressProperties:Description: Egress for environmentGroupId: !Ref WebServerSecurityGroupIpProtocol: -1FromPort: -1ToPort: -1DestinationSecurityGroupId: !Ref DatabaseSecurityGroup#------------------------------------------------------# LoadBalancerSecurityGroup:#------------------------------------------------------LoadBalancerSecurityGroup:Type: AWS::EC2::SecurityGroupMetadata:cfn_nag:rules_to_suppress: - id: W5reason: return traffic to user from internet for testing - id: W40reason: egress open all port for the internetProperties:GroupDescription: load balancer security groupVpcId: !Ref VPCLoadBalancerSecurityGroupEgress:Type: AWS::EC2::SecurityGroupEgressProperties:Description: Egress for environmentGroupId: !Ref LoadBalancerSecurityGroupIpProtocol: -1FromPort: -1ToPort: -1DestinationSecurityGroupId: !Ref WebServerSecurityGroupLoadBalancerSecurityGroupIngress:Type: AWS::EC2::SecurityGroupIngressProperties:Description: open port 80 for web serverGroupId: !Ref LoadBalancerSecurityGroupIpProtocol: tcpFromPort: 80ToPort: 80CidrIp: !Ref InternetCidrBlock#------------------------------------------------------# DatabaseSecurityGroupIngress:#------------------------------------------------------# DatabaseSecurityGroup:#------------------------------------------------------DatabaseSecurityGroup:Type: AWS::EC2::SecurityGroupMetadata:cfn_nag:rules_to_suppress: - id: W5reason: return traffic to user from internet for testing - id: W40reason: egress open all port for the internetProperties:GroupDescription: database security groupVpcId: !Ref VPCDatabaseSecurityGroupPostgreSQLIngress:Type: AWS::EC2::SecurityGroupIngressProperties:Description: open port 5432 for web serverGroupId: !Ref DatabaseSecurityGroupIpProtocol: tcpFromPort: 5432ToPort: 5432SourceSecurityGroupId: !Ref WebServerSecurityGroupSourceSecurityGroupOwnerId: !Ref AWS::AccountIdDatabaseSecurityGroupMySQLIngress:Type: AWS::EC2::SecurityGroupIngressProperties:Description: open port 3306 for web serverGroupId: !Ref DatabaseSecurityGroupIpProtocol: tcpFromPort: 3306ToPort: 3306SourceSecurityGroupId: !Ref WebServerSecurityGroupSourceSecurityGroupOwnerId: !Ref AWS::AccountIdDatabaseSecurityGroupEgress:Type: AWS::EC2::SecurityGroupEgressProperties:Description: Egress for environmentGroupId: !Ref DatabaseSecurityGroupIpProtocol: -1FromPort: -1ToPort: -1CidrIp: !Ref InternetCidrBlock#------------------------------------------------------# Export:#------------------------------------------------------Outputs:VPC:Value: !Ref VPCExport:Name: !Sub ${AWS::StackName}-vpcPublicSubnet1:Value: !Ref PublicSubnet1Export:Name: !Sub ${AWS::StackName}-public-subnet-1PublicSubnet2:Value: !Ref PublicSubnet2Export:Name: !Sub ${AWS::StackName}-public-subnet-2PublicSubnet3:Value: !Ref PublicSubnet3Export:Name: !Sub ${AWS::StackName}-public-subnet-3PrivateSubnet1:Value: !Ref PrivateSubnet2Export:Name: !Sub ${AWS::StackName}-private-subnet-1PrivateSubnet2:Value: !Ref PrivateSubnet2Export:Name: !Sub ${AWS::StackName}-private-subnet-2PrivateSubnet3:Value: !Ref PrivateSubnet3Export:Name: !Sub ${AWS::StackName}-private-subnet-3PrivateRouteTable:Value: !Ref PrivateRouteTableExport:Name: !Sub ${AWS::StackName}-private-route-tableInternetGateway:Value: !Ref InternetGatewayExport:Name: !Sub ${AWS::StackName}-igwDatabaseSecurityGroup:Value: !Ref DatabaseSecurityGroupExport:Name: !Sub ${AWS::StackName}-database-security-groupWebServerSecurityGroup:Value: !Ref WebServerSecurityGroupExport:Name: !Sub ${AWS::StackName}-web-server-security-group
RDS database instance stack.
2-rds-instance-postgresql.yaml
AWSTemplateFormatVersion: 2010-09-09Description: AWS CloudFormation Sample Template for creating a Aurora PostgreSQL DB cluster.Parameters:NetworkStackName:Description: Stack name of the network stackType: StringDefault: network-stackDBName:Default: demoDescription: My databaseType: StringMinLength: '1'MaxLength: '64'AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'ConstraintDescription: Must begin with a letter and contain only alphanumeric characters.MasterUsername:NoEcho: 'true'Description: Username for database accessType: StringMinLength: '1'MaxLength: '16'AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'ConstraintDescription: Must begin with a letter and contain only alphanumeric characters.MasterUserPassword:NoEcho: 'true'Description: Password for database accessType: StringMinLength: '8'MaxLength: '41'AllowedPattern: '[a-zA-Z0-9]*'ConstraintDescription: Must contain only alphanumeric characters.DBClusterIdentifier:Type: StringDefault: 'aurora-cluster-postgresql'Description: The DB cluster identifierMinLength: '1'MaxLength: '63'AllowedPattern: '[a-zA-Z0-9-]*'ConstraintDescription: Must contain only alphanumeric characters and hyphens.DBClusterInstanceClass:Default: db.r5.largeDescription: DB instance classType: StringConstraintDescription: Must select a valid DB instance type.AllowedValues:- db.r5.largeDBInstanceClass:Default: db.r5.largeDescription: DB instance classType: StringConstraintDescription: Must select a valid DB instance type.AllowedValues:- db.r5.largeEngine:Default: "aurora-postgresql"Type: StringAllowedValues:- aurora-mysql- aurora-postgresqlEngineVersion:Default: "16.1"Type: StringDescription: Aurora MySQL engine versionAllowedValues:- "16.1"- "16.2"- "16.3"- "16.4"Resources:#------------------------------------------------------# iam role for rds push logs to cloudwatch:#------------------------------------------------------MonitoringRole:Type: 'AWS::IAM::Role'Properties:AssumeRolePolicyDocument:Version: 2012-10-17Statement:- Effect: AllowPrincipal:Service:- monitoring.rds.amazonaws.comAction:- sts:AssumeRoleManagedPolicyArns:- arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole#------------------------------------------------------# database subnet group:#------------------------------------------------------DatabaseSubnetGroup:Type: 'AWS::RDS::DBSubnetGroup'Properties:DBSubnetGroupDescription: Subnet group for database instanceSubnetIds:- Fn::ImportValue: !Sub ${NetworkStackName}-public-subnet-1- Fn::ImportValue: !Sub ${NetworkStackName}-public-subnet-2- Fn::ImportValue: !Sub ${NetworkStackName}-public-subnet-3#------------------------------------------------------# aurora cluster parameter group#------------------------------------------------------RDSDBClusterParameterGroup:Type: 'AWS::RDS::DBClusterParameterGroup'Properties:Description: CloudFormation Sample Aurora Cluster Parameter GroupFamily: aurora-postgresql16Parameters:timezone: UTCmax_locks_per_transaction: 64#------------------------------------------------------# aurora parameter group#------------------------------------------------------RDSDBParameterGroup:Type: 'AWS::RDS::DBParameterGroup'Properties:Description: CloudFormation Sample Aurora Parameter GroupFamily: aurora-postgresql16Parameters:log_timezone: UTCmax_stack_depth: 6144#------------------------------------------------------# aurora cluster#------------------------------------------------------RDSCluster:Type: 'AWS::RDS::DBCluster'Metadata:cfn_nag:rules_to_suppress:- id: F26reason: disable encryption for demo purpose- id: F27reason: disable encryption for demo purpose- id: F80reason: disable delete protection for demo purpose- id: F22reason: enable public access for demo purposeProperties:BackupRetentionPeriod: 7DBSubnetGroupName: !Ref DatabaseSubnetGroupDeletionProtection: falseDBClusterParameterGroupName: !Ref RDSDBClusterParameterGroupDBClusterIdentifier: !Ref DBClusterIdentifierDatabaseName: !Ref DBNameMasterUsername: !Ref MasterUsernameMasterUserPassword: !Ref MasterUserPasswordEngine: !Ref EngineEngineMode: "provisioned"EngineVersion: !Ref EngineVersionEnableCloudwatchLogsExports:- postgresqlPort: 5432VpcSecurityGroupIds:- Fn::ImportValue: !Sub ${NetworkStackName}-database-security-groupStorageEncrypted: false#------------------------------------------------------# aurora instance 1#------------------------------------------------------RDSDBInstance1:Type: 'AWS::RDS::DBInstance'Metadata:cfn_nag:rules_to_suppress: - id: F26reason: disable encryption for demo purpose - id: F27reason: disable encryption for demo purpose - id: F80reason: disable delete protection for demo purpose - id: F22reason: enable public access for demo purposeProperties:DBParameterGroupName: !Ref RDSDBParameterGroupDBInstanceClass: !Ref DBInstanceClassDBClusterIdentifier: !Ref RDSClusterDBInstanceIdentifier: !Sub ${DBClusterIdentifier}-instance-1DBSubnetGroupName: !Ref DatabaseSubnetGroupEnablePerformanceInsights: trueEngine: !Ref EnginePubliclyAccessible: truePerformanceInsightsRetentionPeriod: 7StorageEncrypted: falseMonitoringInterval: 60MonitoringRoleArn: !GetAtt [MonitoringRole, Arn] # EngineLifecycleSupport: "open-source-rds-extended-support"#------------------------------------------------------# exported output:#------------------------------------------------------Outputs:DatabaseArn:Description: Database Cluster ARNValue: !GetAtt RDSCluster.DBClusterArnExport:Name: !Sub ${AWS::StackName}-database-cluster-arnDatabasePort:Description: Database portValue: !GetAtt RDSCluster.Endpoint.PortExport:Name: !Sub ${AWS::StackName}-database-portDatabaseEndpointAddress:Description: Database endpoint addressValue: !GetAtt RDSCluster.Endpoint.AddressExport:Name: !Sub ${AWS::StackName}-database-cluster-endpoint-address
RDS Aurora cluster stack.
2-aurora-cluster-postgresql.yaml
AWSTemplateFormatVersion: 2010-09-09Description:Create a database parameter groupCreate a database subnet groupCreate a database instance PostgreSQLParameters:NetworkStackName:Description: Stack name of the network stackType: StringDefault: network-stackDBEngine:Default: "16.1"Description: PostgresQLType: StringAllowedValues:- "14.10"- "14.11"- "14.12"- "14.13"- "15.4"- "15.5"- "15.6"- "15.7"- "15.8"- "16.1"- "16.2"- "16.3"- "16.4"ParameterGroupFamily:Default: postgres16Description: Parameter group familyType: StringAllowedValues:- postgres14- postgres15- postgres16DBInstanceID:Default: DemoVectorDescription: My database instanceType: StringMinLength: '1'MaxLength: '63'AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'ConstraintDescription: >-Must begin with a letter and must not end with a hyphen or contain twoconsecutive hyphens.DBName:Default: DemoVectorDescription: My databaseType: StringMinLength: '1'MaxLength: '64'AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'ConstraintDescription: Must begin with a letter and contain only alphanumeric characters.DBInstanceClass:Default: db.m5.largeDescription: DB instance classType: StringConstraintDescription: Must select a valid DB instance type.AllowedValues:- "db.m5.large"- "db.m5.xlarge"- "db.m5.2xlarge"- "db.m5.4xlarge"- "db.m5.8xlarge"DBAllocatedStorage:Default: '64'Description: The size of the database (GiB)Type: NumberMinValue: '20'MaxValue: '65536'ConstraintDescription: must be between 20 and 65536 GiB.DBUsername:NoEcho: 'true'Description: Username for MySQL database accessType: StringMinLength: '1'MaxLength: '16'AllowedPattern: '[a-zA-Z][a-zA-Z0-9]*'ConstraintDescription: must begin with a letter and contain only alphanumeric characters.DBPassword:NoEcho: 'true'Description: Password MySQL database accessType: StringMinLength: '8'MaxLength: '41'AllowedPattern: '[a-zA-Z0-9]*'ConstraintDescription: must contain only alphanumeric characters.Resources:#------------------------------------------------------# database subnet group:#------------------------------------------------------DatabaseSubnetGroup:Type: 'AWS::RDS::DBSubnetGroup'Properties:DBSubnetGroupDescription: Subnet group for database instanceSubnetIds:- Fn::ImportValue: !Sub ${NetworkStackName}-public-subnet-1- Fn::ImportValue: !Sub ${NetworkStackName}-public-subnet-2#------------------------------------------------------# database instance parameter group#------------------------------------------------------RDSDBParameterGroup:Type: 'AWS::RDS::DBParameterGroup'Properties:Description: database parameter groupFamily: !Ref ParameterGroupFamilyParameters:archive_timeout: 300#------------------------------------------------------# iam role for rds push logs to cloudwatch:#------------------------------------------------------MonitoringRole:Type: 'AWS::IAM::Role'Properties:AssumeRolePolicyDocument:Version: 2012-10-17Statement:- Effect: AllowPrincipal:Service:- monitoring.rds.amazonaws.comAction:- sts:AssumeRoleManagedPolicyArns:- arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole#------------------------------------------------------# database rds instance:#------------------------------------------------------RDSDatabaseInstance:Type: 'AWS::RDS::DBInstance'Metadata:cfn_nag:rules_to_suppress:- id: F27reason: disable encryption for demo purpose- id: F80reason: disable delete protection for demo purpose- id: F22reason: enable public access for demo purposeProperties:DBInstanceIdentifier: !Ref DBInstanceIDDBName: !Ref DBNameDBInstanceClass: !Ref DBInstanceClassDBParameterGroupName: !Ref RDSDBParameterGroupAllocatedStorage: !Ref DBAllocatedStorageEngine: postgresEngineVersion: !Ref DBEngineMasterUsername: !Ref DBUsernameMasterUserPassword: !Ref DBPasswordEnablePerformanceInsights: truePerformanceInsightsRetentionPeriod: 7MultiAZ: falseDBSubnetGroupName: !Ref DatabaseSubnetGroupPubliclyAccessible: trueEnableCloudwatchLogsExports:- postgresql- upgradeMonitoringInterval: 60MonitoringRoleArn: !GetAtt [MonitoringRole, Arn]BackupRetentionPeriod: 1AutoMinorVersionUpgrade: falseDeletionProtection: falseStorageType: "gp3"StorageEncrypted: false# EngineLifecycleSupport: "open-source-rds-extended-support"VPCSecurityGroups:- Fn::ImportValue: !Sub ${NetworkStackName}-database-security-group#------------------------------------------------------# exported output:#------------------------------------------------------Outputs:DatabaseArn:Description: Database ARNValue: !GetAtt RDSDatabaseInstance.DBInstanceArnExport:Name: !Sub ${AWS::StackName}-database-arnDatabasePort:Description: Database portValue: !GetAtt RDSDatabaseInstance.Endpoint.PortExport:Name: !Sub ${AWS::StackName}-database-portDatabaseEndpointAddress:Description: Database endpoint addressValue: !GetAtt RDSDatabaseInstance.Endpoint.AddressExport:Name: !Sub ${AWS::StackName}-database-endpoint-address
Deploy script.
deploy.sh
# create network stackaws cloudformation create-stack \--stack-name network-stack \--template-body file://1-network.yaml \--capabilities CAPABILITY_NAMED_IAM# update network stackaws cloudformation update-stack \--stack-name network-stack \--template-body file://1-network.yaml \--capabilities CAPABILITY_NAMED_IAMaws cloudformation update-stack \--stack-name network-database \--template-body file://1-network-database.yaml \--capabilities CAPABILITY_NAMED_IAM# create rds mysql instanceaws cloudformation create-stack \--stack-name rds-instance-postgresql-stack \--template-body file://2-rds-instance-postgresql.yaml \--capabilities CAPABILITY_NAMED_IAM \--parameters '[{"ParameterKey":"NetworkStackName","ParameterValue":"network-database"},{"ParameterKey":"DBUsername","ParameterValue":"demo"},{"ParameterKey":"DBPassword","ParameterValue":"Password"}]'# create aurora postgresql clusteraws cloudformation create-stack \--stack-name aurora-cluster-postgresql-stack \--template-body file://42-aurora-cluster-postgresql.yaml \--capabilities CAPABILITY_NAMED_IAM \--parameters '[{"ParameterKey":"NetworkStackName","ParameterValue":"network-database"},{"ParameterKey":"MasterUsername","ParameterValue":"demo"},{"ParameterKey":"MasterUserPassword","ParameterValue":"Demo@2024"}]'