.NET on AWS Blog
Bob’s Used Books: A .NET Sample Application – Part 3: Infrastructure
Introduction
Welcome to the third and final post in the Bob’s Used Books blog post series.
In the first post I discussed how to get started with Bob’s Used Books and described the different debug and deployment modes you can use to test and run the application. In the second post I discussed the architecture of Bob’s Used Books and provided some insight into the decisions that were made whilst building the sample application. In this post I will dive into the AWS Cloud Development Kit (AWS CDK) project that provisions AWS resources and deploys the sample application.
This post references v1.0.0 of Bob’s Used Books. The Bob’s Used Books v1.0.0 GitHub repository can be found here.
Overview
The AWS CDK is an Infrastructure-as-Code (IaC) framework that enables developers to represent AWS resources and services as application code. When that application code is executed against an AWS account the resources and services defined within that code are automatically provisioned within the AWS account.
IaC is often used in conjunction with DevOps to automate the provisioning of application environments as part of a CI/CD pipeline. IaC provides the following benefits:
- Application environments can be version controlled by committing IaC scripts to source control
- Environment creation and deletion can be automated, reducing the risk of human errors
- Environments can be created and deleted on demand, enabling agile software development workflows and greater cost control
When an AWS CDK project is synthesized it generates an AWS CloudFormation template which is then passed to the CloudFormation service for processing. Although developers can create CloudFormation scripts directly, the AWS CDK provides higher-level constructs that typically enable developers to achieve the same outcomes with less effort.
Bob’s Used Books uses the AWS CDK to provision a number of AWS resources and services, including:
- An Amazon Virtual Private Cloud (Amazon VPC) to host the application and its components
- An Amazon Simple Storage Service (Amazon S3) bucket to store book cover images
- An Amazon CloudFront distribution for low latency delivery of application assets
- An Amazon Cognito user pool and admin user for Customer Identity and Access Management (CIAM)
- An Amazon Relational Database Service (Amazon RDS) for SQL Server for the application backend
- An Amazon Elastic Cloud Compute (Amazon EC2) instance to act as the web server when the application is deployed to AWS
- A number of Amazon Identity and Access Management (IAM) roles, policies, and permissions that enable the application’s components to communicate with each other.
As you can see, Bob’s Used Books takes advantage of numerous AWS services. This is very common for applications that run in the cloud. Further, almost all applications these days have multiple non-production environments like Test and UAT in addition to a production environment. Using an IaC framework like the AWS CDK guarantees that each of those environments is provisioned quickly and consistently.
With all that in mind, let’s take a look at how Bob’s Used Books uses the AWS CDK.
CDK Stacks
As discussed in the overview, applications that run in the cloud often depend upon multiple services and resources. The AWS CDK makes it easy to group these services and resources together into stacks. A stack is a group of services and resources that can be managed as a single unit. When a stack is deployed, all of the resources defined in that stack are deployed; when a stack is deleted, all the resources in that stack are deleted.
For small applications it might make sense to maintain a single stack that contains all the resources for that application. As the application grows to include more services and resources though, maintaining a monolithic stack could become difficult. At that point it makes sense to split that monolithic stack into multiple stacks.
Bob’s Used Books has been organized into four stacks:
- CoreStack – Defines an Amazon S3 bucket, an Amazon Cognito user pool, and a CloudFront distribution
- NetworkStack – Defines an Amazon VPC and associated resources
- DatabaseStack – Defines an Amazon RDS for SQL Server database
- EC2ComputeStack – Defines an Amazon EC2 instance that acts as the web server and deploys the application to that web server
Organizing the resources for Bob’s Used Books into stacks provides greater control over resource deployment. When you are in Integrated Debugging mode (see the first post in this series for details on Integrated Debugging) you only need to deploy the Amazon S3 bucket, the Amazon CloudFront distribution, and the Amazon Cognito user pool. The application still runs locally in your development environment and doesn’t require the networking resources, the database, or the web server. You deploy the resources required for Integrated Debugging by deploying CoreStack with the following command:
cdk deploy BobsBookstoreCore
When you want to simulate a production environment you need to deploy all of the stacks. You can do that with the following command:
cdk deploy BobsBookstoreEC2
But wait, doesn’t that just provision the web server and deploy the application? What about the network resources and the database? The AWS CDK project in Bob’s Used Books takes advantage of a feature of the AWS CDK framework called cross-stack references. The EC2ComputeStack stack has references to resources defined in the other stacks. When you deploy the EC2ComputeStack the AWS CDK recognizes those dependencies and ensures they are also deployed. Let’s take a closer look at how Bob’s Used Books uses cross-stack references to manage resources.
Cross-Stack References
The four stacks that are defined by Bob’s Used Books are instantiated in the Main method of Bookstore.Cdk/Program.cs
. When EC2ComputeStack is initialized it is passed an instance of EC2ComputeStackProps:
var ec2Stack = new EC2ComputeStack(app, $"{Constants.AppName}EC2", new EC2ComputeStackProps
{
Env = env,
Vpc = networkStack.Vpc,
Database = databaseStack.Database,
ImageBucket = coreStack.ImageBucket,
WebAppUserPool = coreStack.WebAppUserPool
});
EC2ComputeStackProps implements the IStackProps interface and is populated with the resources created in NetworkStack, DatabaseStack, and CoreStack. For example, EC2ComputeStack deploys an Amazon EC2 instance into the VPC that was created by NetworkStack. It uses the Amazon Cognito user pool created in CoreStack to generate a user pool client app for the web server, and it uses the Amazon S3 bucket and RDS for SQL Server database to generate the appropriate access permissions for the web server. When you run cdk deploy BobsBookstoreEC2
the AWS CDK recognizes that EC2ComputeStack is dependent upon the VPC created in NetworkStack, the database created in DatabaseStack, and the bucket and user pool created in CoreStack, and it ensures they are provisioned first.
Application Deployment
In addition to defining compute resources for the solution, EC2ComputeStack also deploys the application to the web server.
NOTE: Application deployments are typically facilitated by CI/CD pipelines rather than an IaC framework like AWS CDK, however we want to provide the .NET development community with a simple, self-contained development experience and deploying the application via the CDK achieved that goal.
The Bookstore.Cdk project has a folder called EC2Artifacts that contains the following files:
bobsbookstore.conf
– An Apache configuration file that defines the virtual host for Bob’s Used Books.bobsbookstore.service
– A Linux service that starts the application via the dotnet CLI.ssl.conf
– A configuration file that is used as part of the self-signed certificate configuration.configure_ec2_web_app.sh
– A bash script that configures the EC2 instance that hosts Bob’s Used Books.
EC2ComputeStack uploads these files, along with the application outputs that are produced when the application is published, to an S3 bucket (this is a different bucket from the one which is defined in CoreStack). This is achieved by using the Asset class defined in the Amazon.CDK.S3.Assets namespace and is implemented in the UploadAssestsToS3 method.
Once the EC2 instance is provisioned a UserData script is created that copies the files from the S3 bucket to the EC2 instance and executes configure_ec2_web_app.sh to configure the EC2 instance. configure_ec2_web_app.sh installs the latest updates, installs and configures Apache, unzips and copies Bob’s Used Books to var/www/bobsbookstore, and starts bobsbookstore.service. All of these steps are performed in the ConfigureUserData method of EC2ComputeStack.
Clean Up
If you have deployed any of the CDK stacks that are included in Bob’s Used Books you can delete the AWS services and resources that were created by opening a command-line prompt, navigating to the application solution folder, and running the following command:
cdk destroy BobsBookstore*
This is an important step to ensure you don’t incur unnecessary costs.
Conclusion
Bob’s Used Books takes advantage of the AWS SDK for .NET to define and provision the required AWS resources. The AWS CDK for .NET is a powerful Infrastructure-as-Code framework that enables .NET developers to represent their AWS infrastructure using a programming language with which they are familiar and productive.
This is the final post in the introductory series to Bob’s Used Books. The first post in this series describes how to get up and running with the application and the different debug and deployment modes that are available. The second post in the series dives deep into the architecture of Bob’s Used Books and provides insight into our thought processes as we designed and built the application.
This is not, however, the last you will hear about Bob’s Used Books! On the contrary, we plan on using Bob’s Used Books to demonstrate common .NET modernization scenarios, to demonstrate integrating with additional AWS services, and for inclusion in upcoming training and enablement content.
You can download Bob’s Used Books from our GitHub repository.