Deploy Your Web Application with AWS Elastic Beanstalk and AWS CDK Pipelines
A walk-through of deploying a web application using AWS Elastic Beanstalk and AWS CDK Pipelines to streamline the development process with best practices like versioning, change tracking, code review, testing, and rollbacks.
Create Infrastructure Using AWS CDK
Create GitHub Repository and personal access token
Move the Application into GitHub
Create the code for the resource stack
Upload the App to S3 Automatically
Add the Elastic Beanstalk CDK Dependencies
Create the Elastic Beanstalk Application
Create Elastic Beanstalk Application Version
Create Elastic Beanstalk Environment
Connect GitHub to CodePipelines
Build and Deploy the CDK Application
Add a Deploy Stage for Beanstalk Environment
Viewing Application Deployed in the Cloud
Update the Node.js Application Deployment
More Information and Troubleshooting
Using Multiple Versions of the CDK Libraries
- Create a simple non-containerized Node.js web application
- Use AWS CDK to:
- package the web application source code
- create the deployment infrastructure (using AWS Elastic Beanstalk resources), and
- create the CI/CD pipeline (using AWS CDK Pipelines).
About | |
---|---|
✅ AWS experience | 200 - Intermediate |
⏱ Time to complete | 40 minutes |
💰 Cost to complete | Free tier eligible |
🧩 Prerequisites | - AWS Account and the CLI installed - AWS CDK v2.7.0 installed - GitHub account |
💻 Code Sample | Code sample used in tutorial on GitHub |
📢 Feedback | Any feedback, issues, or just a 👍 / 👎 ? |
⏰ Last Updated | 2023-04-10 |
- An AWS account and CLI installed: If you don't already have an account, follow the Setting Up Your AWS Environment guide for a quick overview and CLI installation steps.
- CDK installed: Visit our Get Started with AWS CDK guide to learn more.
- A GitHub account: Visit GitHub.com and follow the prompts to create your account.
node_modules
directory and package-lock.json
files are created.app.js
. This file will contain the business logic for where our Node.js Express server will reside.app.js
file:/test
endpoint to our code; you can add in a different response, or code that does something specific.index.html
./path
when it is called. To do this, add the following code before the /test
call in app.js
file:index.html
file whenever a request for the root of the app (/) is made.package.json
with a script to make it easier to run. In the package.json
file, replace the scripts section as following:http://127.0.0.1:8080
or http://localhost:8080
.![View the application in local browser](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Fgsg_build_elb_1.a82b887bd1a7f77b51fbd8413743c888e262d0bb.gif%3FimgSize%3D552x381&w=3840&q=75)
npm start
.- Provide authentication to stage, commit, and push code from local repo to the GitHub repo. You may also use SSH keys for this.
- Connect GitHub to CodePipeline, so whenever new code is committed to GitHub repo it automatically triggers pipeline execution.
![GitHub token scopes provide access to repo and admin repo hook](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2FGitHub-repo-hooks.png%3FimgSize%3D981x850&w=3840&q=75)
src
..gitignore
file. We are asking git to include all files from the src/*
folder, except node_modules
and package-lock.json
. This is to ensure that every time Beanstalk deploys the application into a new virtual machine it will install the node_modules. Read more on the instructions on handling Node.js dependencies in Elastic Beanstalk packages.![Ideal folder structure](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Ffolder_structure_1.png%3FimgSize%3D616x1016&w=3840&q=75)
YOUR_USERNAME
with your github org and YOUR_REPOSITORY
with your repository name../lib/cdk-pipeline-eb-demo.ts
and create a new file ./lib/eb-appln-stack.ts
.lib/eb-appln-stack.ts
:Stack
class and a StackProps
interface to accept optional stack properties. These will be referenced during initialization later.lib/eb-appln-stack.ts
, we will write the code for all the resources stack we are going to create in this section. You can also copy-paste contents of this file from here.- IAM Instance profile and role: A container for an AWS Identity and Access Management (IAM) role that we can use to pass role information to an Amazon EC2 instance when the instance starts.
- S3 Assets: This helps us to upload the zipped application into Amazon Simple Storage Service (S3) and will provide the CDK application a way to get the object location.
- Elastic Beanstalk App: A logical collection of Elastic Beanstalk components, including environments, versions, and environment configurations.
- Elastic Beanstalk App Version: A specific, labeled iteration of deployable code for a web application. An application version points to an Amazon S3 object that contains the deployable code, in this case, the zip file that we will be uploading to S3 using S3 Assets. Applications can have many versions and each application version is unique.
- Elastic Beanstalk Environment: A collection of AWS resources running an application version. Each environment runs only one application version at a time.
lib/eb-appln-stack.ts
file, add the dependency to the top of the file.lib/eb-appln-stack.ts
file.lib/eb-appln-stack.ts
file. This code will create the application with the name MyWebApp
in Elastic Beanstalk.AWSElasticBeanstalkWebTier
, which grants permissions to the app to upload logs to Amazon S3 and debugging information to AWS X-Ray.AWSElasticBeanstalkWebTier
. We then create the instance profile with that role and the profile name.MyWebAppEnvironment
.For this particular case, we are going to put this string
'64bit Amazon Linux 2 v5.8.0 running Node.js 18'
. At the end of this blog, there is more information about solution stack names, if you are interested to know where this string came from.- IamInstanceProfile: Here we will reference the instance profile created in the previous steps.
- MinSize, MaxSize, and InstanceTypes: These are configurations for our instances and the autoscaling group that Elastic Beanstalk generates for us. These are optional parameters. If we don't set them up, Elastic Beanstalk will pick the instance type and the minimum and maximum sizes of the autoscaling group according to the platform definition. We are defining them with our own defaults so we can stay within the AWS Free Tier.
??
. For example, if during stack initialization we do not provide any InstanceTypes
, then CDK will consider the default value t2.micro
.envName
property is provided during stack/stage initialization, then use the default name "MyWebAppEnvironment"
.lib/eb-appln-stack.ts
:Source
, Build
and UpdatePipeline
and hence it is an empty pipeline. In the next section, we will add stages (PublishAssets
, Stage1
) and actions to it to suit the needs of our application.![diagram illustrates the stages of a CDK pipeline](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2FCDKPipelines_1.png%3FimgSize%3D106x305&w=3840&q=75)
lib/cdk-pipeline-stack.ts
. Remember to replace OWNER
and REPO
in the code below:- Name for the pipeline.
- Where to find the source in GitHub. This is
Source
stage. Every time we push new commits to this repo, the pipeline is triggered. - How to do the build and synthesis. For this use case, the
Build
stage will install latest npm packages and a standard NPM build (this type of build runsnpm run build
followed bynpx cdk synth
).
CdkPipelineStack
with the account and AWS Region where we want to deploy the pipeline. Put the following code in bin/cdk-pipeline-eb-demo.ts
. Please be sure to replace ACCOUNT
and the REGION
in there if necessary:cdk.json
file in the "context"
section, add a comma accordingly:true
, CDK synthesis uses a DefaultStackSynthesizer
; otherwise, a LegacyStackSynthesizer
is used. CDK Pipelines deployments is supported by the DefaultStackSynthesizer
. Also, the legacy template from CDK v1 is not supported in CDK v2.github-token
.GITHUB_ACCESS_TOKEN
with your plaintext secret and REGION
in following command and run it:github-token
, there is more information at the end of this blog.npx cdk bootstrap aws://ACCOUNT-NUMBER/REGION
npx cdk bootstrap aws://123456789012/us-east-1
CDKToolkit
and you can find it in the CloudFormation console.cdk deploy
one time to get the pipeline started. After that, the pipeline will automatically update itself, when we add the new stage (or CDK applications) in the source code.![cdk deploy confirm changes](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2FCDK-deploy-confirm.png%3FimgSize%3D1596x471&w=3840&q=75)
![New stack is in CREATE_IN_PROGRESS state in CloudFormation console](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2FcloudFormation-new-stack.png%3FimgSize%3D1025x80&w=3840&q=75)
![CodePipeline has a new pipeline](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Fcodepipeline-new-pipeline.png%3FimgSize%3D1482x863&w=3840&q=75)
lib/eb-stage.ts
and put the following code in it:CdkEBStage
to the pipeline.lib/cdk-pipeline-stack.ts
:minSize
, and maxSize
. We are using the default instanceTypes
and environment name
defined in the CDK stack. If you want to add another stage to the pipeline, make sure to add a custom value for envName
to differentiate the Beanstalk environments.npm run build
first to make sure there are no typos.Assets
and another for Pre-Prod
.![CodePipeline self mutated to add 2 new stages Assets and Pre-prod](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Fcodepipeline-pre-prod-stages.png%3FimgSize%3D1625x877&w=3840&q=75)
UpdatePipeline
stage has completed successfully, the pipeline will again run from start. This time it will not stop at UpdatePipeline
stage. It will transition further to the new stages Assets
and Pre-prod
to deploy the Beanstalk application, environment and the my_webapp
application.![CodePipeline running the new stages Assets and Pre-prod](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Fcodepipeline-pre-prod-stages-running.png%3FimgSize%3D2458x1464&w=3840&q=75)
Pre-Prod
stage in the CloudFormation console.![2 new CloudFormation stacks in the CloudFormation console](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Fcloudformation-two-stacks-desc.png%3FimgSize%3D1420x156&w=3840&q=75)
Pre-Prod-WebService
contains all the Elastic Beanstalk resources we created in the previous module: Elastic Beanstalk application, application version, instance profile, and environment.awseb-e-randomstring-stack
), which was created by Elastic Beanstalk, contains all the resources the Elastic Beanstalk app needs to run—autoscaling groups, instances, Amazon CloudWatch alarms and metrics, load balancers, and security groups.Pre-Prod
stage, we can confirm that the service is up and running.MyWebAppEnvironment
. Choose the URL to launch the web app.![Elastic Beanstalk console has URL](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Felasticbeanstalk-environment.png%3FimgSize%3D1549x340&w=3840&q=75)
![application should now be available to be accessed from anywhere](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Felasticbeanstalk-application.png%3FimgSize%3D763x327&w=3840&q=75)
- Make the changes in the web app
- Stage, Commit, and Push the changes to GitHub repo.
Pre-prod
stage of CodePipeline has completed successfully, we can verify that there is a new version of the Elastic Beanstalk app deployed. Simply refresh the application URL in the browser to see the deployed changes.Run the following command inside the CDK application directory:
CdkPipelineStack
stack was deleted by going to the AWS CloudFormation Management Console.cdk deploy
command. It will not destroy the 2 CloudFormation stacks that were deployed by the Pre-Prod
stage.Pre-Prod-WebService
manually from the CloudFormation Console or using following command:Cannot delete entity, must detach all policies first.
Then delete the IAM role (name starts with Pre-Prod-WebService-MyWebAppawselasticbeanstalkec2-randomstring
) manually from IAM Console and retry deleting the CloudFormation stack. For help, read Deleting roles or instance profiles in the AWS Documentation.CDKToolkit
created during bootstrap.cdkpipelinestack-pipelineartifactsbucket<random-letters>
. For more information, read S3 documentation to Emptying and Deleting a bucket.![CDK Application Error on this variable](/https/community.aws/_next/image?url=https%3A%2F%2F1.800.gay%3A443%2Fhttps%2Fcommunity.aws%2Fraw-post-images%2Ftutorials%2Fdeploy-webapp-eb-cdk%2Fimages%2Fgsg_build_elb_1.9611a2064c0d28bb71fee409ec55ff8ef4d197aa.png%3FimgSize%3D1124x200&w=3840&q=75)
package.json
file in your CDK application.64bit Amazon Linux 2 v5.8.0 running Node.js 18
, you can use the AWS CLI to get a list of all the supported platforms.Access Denied
to source code GitHub repository, then you do not have a secret with name github-token
, which is the default value in CDK.github-access-token-secret
, you have to update the CDK code in lib/cdk-pipeline-stack.ts
. Import cdk and add authentication with secret name using following code:Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.