There are multiple ways to handle your infrastructure as code, such as CloudFormation, CDK, and Terraform. This post will focus on CDK, which stands for AWS Cloud Development Kit. We will set up a React app as a dummy frontend and then use CDK to deploy it to AWS. The goal of the task is not to learn React but to try CDK out and use it in practice.
We want to achieve this:
CDK
With CDK, you can use familiar programming languages like TypeScript, Python, Java, or C#, abstracting away the complexity of AWS CloudFormation. It offers reusable components, integration with various AWS services, and benefits like type safety and IDE support. CDK simplifies infrastructure management, encourages best coding practices, and nurtures collaboration within development teams.
Taken from the official documentation by AWS:
“The AWS Cloud Development Kit (AWS CDK) is an open-source software development framework for defining cloud infrastructure in code and provisioning it through AWS CloudFormation.“
One important thing to know about CDK is that when it compiles, it compiles down to CloudFormation templates, which are then used for deployment into AWS. This means that CDK is an extra layer on top of CloudFormation that makes it easier to read and digest.
What I like most about CDK is that it decreases the knowledge gap for software developers to learn infrastructure as code. I am currently working on a project where we have TypeScript throughout the whole project. This means that the backend is in node/TypeScript, the frontend is in React/TypeScript, and the infrastructure is defined with CDK in TypeScript.
Prerequisites
- Make sure you have node 14.15.0 or later installed on your machine.
- Make sure you have TypeScript installed:
npm -g install typescript
- Setup and configure AWS CLI and CDK Toolkit
AWS CLI and CDK ToolKit setup
If you do not already have the AWS CLI and the CDK Toolkit setup and configured, here are a few links on how to get that done:
- To install AWS CLI, click here. Choose your OS and follow the instructions.
- To configure AWS CLI, click here. Choose a way to configure it.
- To get started with CDK Toolkit, click here
Let’s get started with creating our React app
- Create a new folder on your machine ->
mkdir cdk_demo
- Navigate to your newly created folder ->
cd cdk_demo
- Run:
npx create-react-app cdk_demo --template typescript
to create your React app. - Navigate to your app ->
cd cdk_demo
- Open your app in a code editor. I will be using VS Code. The command to open the project in VS code from the terminal is:
code .
Configuring your React app
Now, we need to make some modifications to this standard create-react app.
To decide where the compiled React app should be saved, we need to modify the current build script in the package.json file with this: "build": "BUILD_PATH='cdk/build' react-scripts build"
. We will later use this path to tell CDK where to get the files that we wish to deploy.
Initiate the CDK app inside of the React project
The next step will be to initiate our CDK configuration.
In the root of the project, create a folder where we want our infrastructure configurations to reside. I am calling this folder cdk.
Navigate to the folder you just created ->
cd cdk
Now initiate the CDK with TypeScript in this folder ->
cdk init app --language typescript
You should now have something that looks like this:
Configure CDK
First things first. We want to specify an out directory where the compiled CDK project will be saved. This is to gather the compiled files in a folder instead of them being mixed with all the other files.
Inside the cdk folder, we need to modify the tsconfig.json with this:
"outDir": "cdk_build"
Let’s start adding our infrastructure
Now, we can finally start adding our infrastructure definitions to our project.
- Inside the cdk folder, navigate to the folder lib. Create a new file here called deployment.ts and add this code.
import { Construct } from "constructs"; import { CfnOutput, RemovalPolicy } from "aws-cdk-lib"; import { Distribution, ViewerProtocolPolicy } from "aws-cdk-lib/aws-cloudfront"; import { S3Origin } from "aws-cdk-lib/aws-cloudfront-origins"; import { BlockPublicAccess, Bucket } from "aws-cdk-lib/aws-s3"; import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment"; // Note that we define our path here to the compiled react folder const path = "./build"; export class Deployment extends Construct { constructor(scope: Construct, id: string) { super(scope, id); // Creating the bucket where we want to deploy our React app const hostingBucket = new Bucket(this, "FrontendBucket", { autoDeleteObjects: true, blockPublicAccess: BlockPublicAccess.BLOCK_ALL, removalPolicy: RemovalPolicy.DESTROY, }); // Creating a cloudfront distribution which is used to deliver the app to the user const distribution = new Distribution(this, "CloudfrontDistribution", { defaultBehavior: { origin: new S3Origin(hostingBucket), viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS, }, defaultRootObject: "index.html", errorResponses: [ { httpStatus: 404, responseHttpStatus: 200, responsePagePath: "/index.html", }, ], }); // Creating the actual deployment new BucketDeployment(this, "BucketDeployment", { sources: [Source.asset(path)], destinationBucket: hostingBucket, distribution, distributionPaths: ["/*"], }); // Here we are outputting the URL that we can use to browse our webapp. new CfnOutput(this, "CloudFrontURL", { value: distribution.domainName, description: "The distribution URL", exportName: "CloudfrontURL", }); // Here we are outputting the name of the bucket we created new CfnOutput(this, "BucketName", { value: hostingBucket.bucketName, description: "The name of the S3 bucket", exportName: "BucketName", }); } }