Introduction#
GitHub this note shows basically how to develop a high performance backend app using auto scaling, application load balancer, and aurora
- Load balancer and auto scaling group
- Aurora multiple AZ
- Autoscaling stratergy (not yet here )
- Aurora multi AZ
- Aurora multi master
- Read only endpoint
Architectrure#
Network Stack#
Let create a new vpc
const vpc = new aws_ec2.Vpc(this, 'VpcForAuroraDemo', {vpcName: props.vpcName,cidr: props.cidir,enableDnsHostnames: true,enableDnsSupport: true,subnetConfiguration: [{cidrMask: 24,name: 'PublicSubnet',subnetType: aws_ec2.SubnetType.PUBLIC},{cidrMask: 24,name: 'PrivateSubnet',subnetType: aws_ec2.SubnetType.PRIVATE_ISOLATED},{cidrMask: 24,name: 'PrivateSubnetWithNat',subnetType: aws_ec2.SubnetType.PRIVATE_WITH_NAT}]})
Aurora Cluster#
Let create a security group for aurora
const sg = new aws_ec2.SecurityGroup(this, 'SecurityGroupForSsmEndpoint', {vpc,description: 'Allow port 443 from private instance',allowAllOutbound: true})sg.addIngressRule(aws_ec2.Peer.anyIpv4(),aws_ec2.Port.tcp(3306),'allow HTTPS from private ec2 ')
aurora cluster: single AZ, single master (write/read). There are advanced options for high performance multi-master and multi-az
const cluster = new aws_rds.DatabaseCluster(this, 'IcaDatabase', {removalPolicy: RemovalPolicy.DESTROY,defaultDatabaseName: props.dbName,engine: aws_rds.DatabaseClusterEngine.auroraMysql({version: aws_rds.AuroraMysqlEngineVersion.VER_2_08_1}),credentials: aws_rds.Credentials.fromGeneratedSecret('admin'),instanceProps: {instanceType: aws_ec2.InstanceType.of(aws_ec2.InstanceClass.BURSTABLE2,aws_ec2.InstanceSize.SMALL),vpcSubnets: {subnetType: aws_ec2.SubnetType.PUBLIC},vpc,securityGroups: [sg]},deletionProtection: false,// 1 - mean single AZ// 2+ mean multil AZ, single master, multiple read replicas// engine mode multi-master - cfnDBClusterinstances: 1})
Load Balancer#
Let create a iam role for EC2 to download from S3, access SSM, and Secret Mangement
const role = new aws_iam.Role(this, `RoleForEc2AsgToAccessSSM`, {roleName: `RoleForEc2AsgToAccessSSM-${this.region}`,assumedBy: new aws_iam.ServicePrincipal('ec2.amazonaws.com')})
add policy for s3 to download userData-web and read db credentials from secrete maanger
role.attachInlinePolicy(new aws_iam.Policy(this, `PolicyForEc2AsgToReadS3`, {policyName: `PolicyForEc2AsgToReadS3-${this.region}`,statements: [new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ['s3:*'],resources: ['arn:aws:s3:::haimtran-workspace/*']}),new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ['secretsmanager:*'],resources: ['*']})]}))
policy for system manager connection
role.addManagedPolicy(aws_iam.ManagedPolicy.fromManagedPolicyArn(this,`PolicyForEc2AsgToAccessSSM-${this.region}`,'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'))
auto scaling group
const asg = new aws_autoscaling.AutoScalingGroup(this, 'ASG', {vpc,instanceType: aws_ec2.InstanceType.of(aws_ec2.InstanceClass.T2,aws_ec2.InstanceSize.SMALL),machineImage: new aws_ec2.AmazonLinuxImage({generation: aws_ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,edition: aws_ec2.AmazonLinuxEdition.STANDARD}),minCapacity: 2,maxCapacity: 3,role: role,vpcSubnets: {subnets: [aws_ec2.Subnet.fromSubnetId(this,'PrivateSubnetWithNat1',privateSubnetIds[2]),aws_ec2.Subnet.fromSubnetId(this,'PrivateSubnetWithNat2',privateSubnetIds[3])]}})asg.addUserData(fs.readFileSync('./lib/script/user-data.sh', 'utf8'))
application load balancer
const alb = new aws_elasticloadbalancingv2.ApplicationLoadBalancer(this,'ALB',{vpc,internetFacing: true})
listen port 80
const listener = alb.addListener('Listener', {port: 80})listener.addTargets('Target', {port: 80,targets: [asg]})listener.connections.allowDefaultPortFromAnyIpv4('Open to the world')asg.scaleOnRequestCount('AmodestLoad', {targetRequestsPerMinute: 60})
User Data#
userdata-1 which is a simple web downloaded from s3
#!/bin/bashcd ~mkdir webcd webaws s3 cp s3://haimtran-workspace/aurora-web.zip .unzip aurora-web.zipsudo python3 -m pip install -r requirements.txtsudo python3 app.py
userdata-2 which is a simple web downloaded from github
#!/bin/bash# kill -9 $(lsof -t -i:8080)# secrete idexport SECRET_ID=aurora-secrete-name# secret regionexport REGION=ap-southeast-1# download vim configurationwget -O ~/.vimrc https://raw.githubusercontent.com/cdk-entest/basic-vim/main/.vimrc# download web appwget https://github.com/cdk-entest/vpc-alb-asg-aurora-demo/archive/refs/heads/master.zipunzip master.zipcd vpc-alb-asg-aurora-demo-master/# install pippython3 -m ensurepip --upgrade# install dependencies in requirements.txtpython3 -m pip install -r requirements.txt# run the flask appcd web-apppython3 -m app
Database Connection#
Let get DB credentials from secret management
# sm clientsecrete_client = boto3.client('secretsmanager',region_name=REGION)# get secret stringsecret = secrete_client.get_secret_value(SecretId=SECRET_ID)
In this simple case single master (read/write), use the master (read/write) endpoint for both read and write. If there are multiple read replica, can use the -ro- read only endpoints for higher preformance read. connector
conn = mysql.connector.connect(host=secret_dic['host'],user=secret_dic['username'],port=secret_dic['port'],password=secret_dic['password'],database=secret_dic['dbname'])
create table
# cursorcur = conn.cursor()# drop table if existsdrop = "DROP TABLE IF EXISTS employees"cur.execute(drop)# create tableemployee_table = ("CREATE TABLE employees ("" id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, "" name VARCHAR(30) DEFAULT '' NOT NULL, "" age TEXT, "" time TEXT, ""PRIMARY KEY (id))")cur.execute(employee_table)
query table
stmt_select = "SELECT id, name, age, time FROM employees ORDER BY id"cur.execute(stmt_select)# parsefor row in cur.fetchall():print(row)