Since AWS is going to sunset / auto-upgrade Aurora Serverless v1 in December 2024, it’s time to upgrade to Aurora Serverless v2. Upgrading to Serverless v2 MySQL instances also means upgrading from MySQL 5.7 to MySQL 8.0 under the hood.
This article describes how to adapt the AWS provided upgrade path to work with a CDK / CloudFormation infrastructure-as-code project, which requires a few more steps which I call the “CDK/CloudFormation retain-and-import dance“.
The dance needs to be done since a direct modification via CloudFormation would result a replacement of the cluster, since CloudFormation does not support the modification of the engine mode from serverless
to provisioned
.
Step 1: Unbind the Aurora Serverless v1 cluster from CloudFormation (RETAIN):
First, add removalPolicy: cdk.RemovalPolicy.RETAIN,
to the Aurora Serverless v1 cluster definition:
1 | // Serverless v1 cluster |
and deploy the change.
Next, comment out the AuroraCluster
resource, and check with cdk diff
that the cluster will be retained:
1 | Stack aurora-serverless-v1-upgrade |
As expected, the AuroraCluster
will be retained (“orphan”).
But, as you can see, the CDK might also have auto-generated CloudFormation resources such as secrets, security groups etc. (depending on your configuration), so there is an additional difficulty that CloudFormation would to delete (or try to delete) these still-in-use resources.
To prevent this, we can create and use these dependecies explicitly, so that they are not auto-generated (and auto-deleted) by the CDK anymore:
1 | const dbClusterSecurityGroup = new aws_ec2.SecurityGroup(this, 'dbClusterSecurityGroup', { |
Now after making all resources explicit, we can ensure with another cdk diff
that Cloudformation will not try to delete anything the cluster depends on:
1 | ➜ serverless-v1-upgrade-cdk git:(master) ✗ npx cdk diff |
The SecretTargetAttachment is still there, and it will be deleted by CloudFormation, since it’s not referenced anymore by the AuroraCluster
resource. But it will be recreated in the import
step later.
Step 2: Prepare for upgrade: Change the engine mode to “provisioned”
Now let’s follow the AWS blog post and modify the cluster to temporarily become a provisioned cluster:
1 | $ aws rds modify-db-cluster \ |
To cite the original AWS blog post:
The conversion will take a few minutes, during which time there will be an approximately 30-second failover window while the new provisioned instance is promoted. When the process is complete, your cluster will be converted to a provisioned Aurora database cluster.
Now we need to make the CDK/CloudFormation stack aware again of the changed cluster. So we add the AuroraCluster
resource again, and modify it to adapt to the provisioned
engine mode:
- The resource type changed from
ServerlessCluster
toDatabaseCluster
- There is a provisioned
writer
instance for now. This will become the serverless writer later.
1 | const dbCluster = new aws_rds.DatabaseCluster(this, 'AuroraCluster', { |
We should now be able to “reattach” the cluster to the CDK/Cloudformation stack with cdk import
.
1 | $ cdk import |
Check with cdk diff
that the cluster is now imported:
1 | $ cdk diff |
So let’s run a cdk deploy
to create the missing Secrets Manager attachment.
After that it’s a good idea to run a CloudFormation drift detection to make sure that the resources are now in sync with the CDK/CloudFormation stack.
Step 3: Upgrade the provisioned cluster to Aurora 3 / MySQL 8.0
Now it’s time to upgrade the provisioned cluster to Aurora 3 / MySQL 8.0. I have already described how to do this in Zero-downtime upgrade from AWS Aurora 2 (MySQL 5.7) to version 3 (MySQL 8.0) with the CDK and Aurora Blue/Green deployments , so please follow the steps there.
Step 4: Changing the engine mode back to “serverless”
Welcome back. We have now a provisioned cluster with MySQL 8.0. First, let’s add a serverless reader “instance” to the cluster which we can promote to the new writer later. This step is necessary to avoid extended downtime, which would happen if we would simply change the type from provisioned
to serverless
.
1 | const dbCluster = new aws_rds.DatabaseCluster(this, 'AuroraCluster', { |
After deploying this, we can fail-over to the serverless reader, and delete the provisioned writer instance:
1 | $ aws rds failover-db-cluster \ |
This step introduces drift into the CDK code since the writer is now the reader and vice versa. There is a GitHub discussion around this topic.
Since we want to get rid of the provisioned “writer” instance (which is actually the reader), we first change it to serverless as well:
1 | const dbCluster = new aws_rds.DatabaseCluster(this, 'AuroraCluster', { |
Then we fail over again to the serverless writer:
1 | $ aws rds failover-db-cluster \ |
That brings CDK and the cluster back in sync, at least for the moment. Finally, we can delete the reader instance.
Summary
This article described how to upgrade a CDK/CloudFormation-managed Aurora Serverless v1 cluster to Serverless v2 with minimal downtime.
Like what you read?
You can hire me or make a donation via PayPal!