Aurora Serverless V2 with AWS CDK
- Published on
- Authors
- Name
- Binh Bui
- @bvbinh
Introduction
Aurora Serverless is a fully managed, auto-scaling configuration for Amazon Aurora. It automatically starts up, shuts down, and scales capacity up or down based on your application’s needs. You can use Aurora Serverless to run your most demanding production workloads with less administrative effort than with other database options. Aurora Serverless is available in two versions: Aurora Serverless v1 and Aurora Serverless v2.
Aurora Serverless v2 is a new version of Aurora Serverless that provides a new storage engine, Aurora Storage Engine (Aurora SE), and a new query engine, Aurora Query Engine (Aurora QE). Aurora Serverless v2 is a drop-in replacement for Aurora Serverless v1. You can use the same API calls and tools to manage your Aurora Serverless v2 clusters as you use for Aurora Serverless v1.
In this article, we will use the AWS CDK to create an Aurora Serverless v2 cluster with a database and a database user. We will also create a Lambda function that will connect to the database and query the data.
Now AWS CDK has support for Aurora Serverless v2. You can use the AWS CDK to create an Aurora Serverless v2 cluster with a database and a database user.
Let’s get started.
// create a vpc
const vpc = new Vpc(this, 'VPC', {
cidr: '10.0.0.0/16',
subnetConfiguration: [{ name: 'egress', subnetType: SubnetType.PUBLIC }], // only one subnet is needed
natGateways: 0, // disable NAT gateways
})
// create a security group for aurora db
const dbSecurityGroup = new SecurityGroup(this, 'DbSecurityGroup', {
vpc: vpc, // use the vpc created above
allowAllOutbound: true, // allow outbound traffic to anywhere
})
// allow inbound traffic from anywhere to the db
dbSecurityGroup.addIngressRule(
Peer.anyIpv4(),
Port.tcp(5432), // allow inbound traffic on port 5432 (postgres)
'allow inbound traffic from anywhere to the db on port 5432'
)
// create a db cluster
// https://github.com/aws/aws-cdk/issues/20197#issuecomment-1117555047
const dbCluster = new rds.DatabaseCluster(this, 'DbCluster', {
engine: rds.DatabaseClusterEngine.auroraPostgres({
version: rds.AuroraPostgresEngineVersion.VER_13_6,
}),
instances: 1,
instanceProps: {
vpc: vpc,
instanceType: new InstanceType('serverless'),
autoMinorVersionUpgrade: true,
publiclyAccessible: true,
securityGroups: [dbSecurityGroup],
vpcSubnets: vpc.selectSubnets({
subnetType: SubnetType.PUBLIC, // use the public subnet created above for the db
}),
},
port: 5432, // use port 5432 instead of 3306
})
// add capacity to the db cluster to enable scaling
Aspects.of(dbCluster).add({
visit(node) {
if (node instanceof CfnDBCluster) {
node.serverlessV2ScalingConfiguration = {
minCapacity: 0.5, // min capacity is 0.5 vCPU
maxCapacity: 1, // max capacity is 1 vCPU (default)
}
}
},
})
Let see what we have done here.
- We created a VPC with a public subnet. We will use this VPC to create the Aurora Serverless v2 cluster.
- We created a security group for the Aurora Serverless v2 cluster. We will use this security group to allow inbound traffic from anywhere to the Aurora Serverless v2 cluster.
- We created an Aurora Serverless v2 cluster with a single instance. We used the
serverless
instance type to create an Aurora Serverless v2 cluster. We also set public accessibility totrue
to allow the Lambda function to connect to the Aurora Serverless v2 cluster. We also set the port to5432
to use the Postgres port. - We added capacity to the Aurora Serverless v2 cluster to enable scaling. We set the
minCapacity
to0.5
andmaxCapacity
to1
. This will allow the Aurora Serverless v2 cluster to scale up to1
vCPU and scale down to0.5
vCPU.
Create a lambda function to connect to the database and query the data
In this section, we will create a lambda function that will connect to the database and query the data. We will use the AWS CDK to create the lambda function.
const fn = new NodejsFunction(this, 'Lambda', {
entry: './lambda/index.ts',
runtime: Runtime.NODEJS_16_X,
handler: 'main',
bundling: {
externalModules: ['aws-sdk', 'pg-native'],
minify: false,
},
environment: {
databaseSecretArn: dbCluster.secret?.secretArn ?? '', // pass the secret arn to the lambda function
},
})
// allow the lambda function to access credentials stored in AWS Secrets Manager
// the lambda function will be able to access the credentials for the default database in the db cluster
dbCluster.secret?.grantRead(fn)
const api = new LambdaRestApi(this, 'Api', {
handler: fn,
})
Let see what we have done here.
- We created a lambda function with the AWS CDK. We used the
NodejsFunction
construct to create the lambda function. We used theexternalModules
option to exclude theaws-sdk
andpg-native
modules from the lambda function. We also used theminify
option to disable minification. - We passed the secret arn to the lambda function using the
environment
option. The lambda function will use the secret arn to access the credentials for the default database in the Aurora Serverless v2 cluster. - We allowed the lambda function to access credentials stored in AWS Secrets Manager. The lambda function will be able to access the credentials for the default database in the Aurora Serverless v2 cluster.
- And finally, we created a REST API using the lambda function. We will use this REST API to test the lambda function.
You can read more about how to Building Lambda functions with TypeScript in AWS CDK here
Below is the code for the lambda function.
import { GetSecretValueCommand, SecretsManagerClient } from '@aws-sdk/client-secrets-manager'
import { APIGatewayEvent, APIGatewayProxyResult } from 'aws-lambda'
import { Client } from 'pg'
export async function main(event: APIGatewayEvent): Promise<APIGatewayProxyResult> {
// get the secret from secrets manager.
const client = new SecretsManagerClient({})
const secret = await client.send(
new GetSecretValueCommand({
SecretId: process.env.databaseSecretArn,
})
)
const secretValues = JSON.parse(secret.SecretString ?? '{}')
console.log('secretValues', secretValues)
// connect to the database
const db = new Client({
host: secretValues.host, // host is the endpoint of the db cluster
port: secretValues.port, // port is 5432
user: secretValues.username, // username is the same as the secret name
password: secretValues.password, // this is the password for the default database in the db cluster
database: secretValues.dbname ?? 'postgres', // use the default database if no database is specified
})
await db.connect()
// execute a query
const res = await db.query('SELECT NOW()')
// disconnect from the database
await db.end()
return {
body: JSON.stringify({
message: `DB Response: ${res.rows[0].now}`,
}),
statusCode: 200,
isBase64Encoded: false,
headers: {
'Content-Type': 'application/json',
},
}
}
Let see what we have done here.
- We created a
SecretsManagerClient
to get the secret from AWS Secrets Manager. - We used the
SecretsManagerClient
to get the secret from AWS Secrets Manager. We used theSecretId
option to specify the secret arn. We used theGetSecretValueCommand
to get the secret from AWS Secrets Manager. - We parsed the secret string to get the secret values. The secret string contains the credentials for the default database in the Aurora Serverless v2 cluster.
- We created a
Client
to connect to the database. We used thehost
,port
,user
,password
, anddatabase
options to connect to the database. - We executed a query to get the current time from the database.
That's it. We have created an Aurora Serverless v2 cluster with a single instance. We have also created a lambda function that will connect to the database and query the data. Now, we can deploy the stack to AWS.
Deploy the stack to AWS
To deploy the stack to AWS, run the following command.
cdk deploy
After the stack is deployed, you can verify that the Aurora Serverless v2 cluster is created in the AWS console.
Besides, you can test the lambda function by making a request to the REST API.
curl -X GET https://<api-id>.execute-api.<region>.amazonaws.com/prod
You should get a response similar to the one below.
{
"message": "DB Response: 2022-11-08T15:52:00.000Z"
}
Clean up
Don't forget to delete the stack after you are done. This will prevent you from incurring any charges.
cdk destroy
Conclusion
In this article, we created an Aurora Serverless v2 cluster with a single instance. We also created a lambda function that will connect to the database and query the data. We used the AWS CDK to create the Aurora Serverless v2 cluster and the lambda function. You can find the code for this article here
That's it for this article. I hope you found it useful. If you have any questions or suggestions, please leave a comment below. You can also reach out to me on Twitter or LinkedIn.