Continuous Deployment with AWS CodePipeline for Static Websites and Front End Apps

  • by Emre Yilmaz
  • Feb 23, 2020
  • AWSDevOps
  • Istanbul
CD Pipeline for Static Websites and Front End Apps on S3 with AWS CodePipeline

Whether you have a static website like this blog or a front end application developed using a framework like Angular, React or Vue.js, you can follow similar steps to create a continuous deployment pipeline on AWS using AWS CodePipeline. In this post, I will share the AWS services you can use while creating this type of pipelines to achieve fast and frequent deployments.

AWS architecture for static websites

Before talking about deployment automation, let’s start with the common AWS architecture used to deploy static websites and front end applications. Actually, I call both of them as static websites, because their contents are similar. You have HTML, Javascript or CSS files to serve to your clients in the end.

Where do you host your static websites? You can deploy your static websites on an Amazon EC2 instance. But it is not be an ideal place if you have a more scalable, reliable and cost-effective option like Amazon S3. Besides, you can distribute your content on your S3 bucket globally with Amazon CloudFront to serve it faster.

Hence, our common architecture for static website will be like below:

  • Amazon S3 bucket configured for static website hosting. We will be deploying this bucket using our pipeline.
  • Amazon CloudFront in front of the S3 bucket to distribute content globally.
  • Amazon Route 53 for DNS hosting.
  • Amazon Certificate Manager SSL certificate configured on CloudFront to encrypt data in transit.

Static Website Hosting - AWS Architecture

Why create a CI/CD pipeline?

If you are familiar with DevOps principles, you already know that one of the goals of DevOps is to deploy new versions of your software fast and frequently. Hence, you can deploy the changes in your applications in small chunks and take actions at an early phase if they do not perform as expected. But to be able to deploy fast and frequently, you should have standard and tested deployment processes. In other words, you need to automate your deployments, because manual processes are not repeatable and prone to errors.

CI/CD introduces automation to your deployment process to solve this problem. By applying CI/CD, you create a pipeline which builds, tests and deploys your code automatically each time you submit your changes.AWS CodePipeline is the continous delivery service of AWS which you can use to create your CI?CD workflows. You can build a pipeline for just continuous integration (CI) or one of the CD processes, continuous deployment or continuious delivery. But what are CI and CD?

  • CI is the process of building your code and running unit tests on it automatically each time you push your changes to your code repository. The aim is to solve possible integration errors due to compilation or another reason earlier.
  • In continuous delivery, you do all steps in CI, but you deploy to a staging environment after it. Then you may run additional tests and you submit to a manual approval. After the approval, all changes are deployed to your production environment automatically.
  • If you apply continuous deployment, all is same with continuous delivery except the manual approval. All your changes are deployed to the production environment automatically after your tests finish successfully on the staging environment. But you should have good test coverage to apply continuous deployment successfully.

Now let’s continue with building a pipeline on AWS CodePipeline to deploy your static website content and apply continuous deployment.

Pipeline on AWS CodePipeline

AWS CodePipeline concepts

AWS CodePipeline is the orchestrator of your pipeline. You create a pipeline on AWS CodePipeline, it automatically triggers when you update your source repository, and pass your changes through its stages. So it executes your workflow for your CI/CD.

But how does AWS CodePipeline do this? In your pipeline, you define actions in your stages to pull the source changes, build it, test it, deploy it, etc. In your actions you can use AWS developer tools like CodeCommit, CodeBuild, CodeDeploy, third party tools like Jenkins, BlazeMeter, or you can define custom actions using AWS Lambda.

Now let’s talk about what to use to build a continuous deployment pipeline for a static website.

Stages for a static website deployment to Amazon S3

To deploy a static website like Jekyll automatically using AWS CodePipeline, you will need at least the stages below.

  • A source stage to pull your changes from a central repository.
  • A build stage to install depenedencies and build your code. You can run unit tests in this stage if you have.
  • A production stage to deploy to your production environment.

You can have more stages such as a staging or testing stage to deploy to a non-production environment before the production stage. In that case, you will add a deployment action to deploy to your staging environment and one or more test actions to run some integration or load tests. But in order to keep this blog simple, I will focus on only the least needed ones.

So which AWS services will you need to create this pipeline? The answer is in the diagram below.

CD Pipeline on AWS CodePipeline for static websites and front ends

Let’s explain the stages in this diagram one by one.

Source Action: AWS Commit

Whether you apply CI or CD, it all starts with pushing your code changes to a central source repository. On AWS CodePipeline, you can define an S3 bucket, an Amazon ECR repository or a Git repository on AWS CodeCommit, GitHub or Bitbucket.

S3 buckets has its own use cases, ECR may suit well in case you need to rebuild some code when a dependent Docker image is changed, etc. But a Git repository suits better to manage versions of a software project as well as a static website content.

AWS CodeCommit is the private Git repository service of AWS. It is not different than using GitHub or Bitbucket, because you use Git commands to pull/push your changes.

In our example, we have a Git repository on AWS CodeCommit which is defined as the source location of our pipeline. It may contain our Jekyll website content, or Angular, React or Vue.js code whatever we use to build our static website.

The thing is we push our code unbuilt to this repository. Besides, the libraries needed such as Ruby gems, NPM packages, etc.. will not be in this repsoitory as well. The pipeline will install it in the build stage.

Build Action: AWS CodeBuild

In the build stage, we install the dependencies and build the source code pulled in the source stage. On AWS CodePipeline, we do this with the help of a build action and we can use AWS CodeBuild for this. You use AWS CodeBuild on your pipeline by creating a CodeBuild project and defining it as the provider of your build action.

AWS CodeBuild acts like a command line tool for your source. You define a buildspec.yml file at the root of your source code whcih contains the specifications to build it. Then AWS CodeBuild starts a container you defined in it such as a Ruby or Node.js image and runs your commands one by one. Then it packages and exports the outputs you defined as an artifact.

Let me give you an example of the buildspec of a Jekyll website below.

version: 0.2
env:
  variables:
    JEKYLL_ENV: production
phases:
  install:
    runtime-versions:
      ruby: 2.6
    commands:
      - gem install bundler
      - bundle install
  build:
    commands:
      - bundle exec jekyll build
artifacts:
  type: zip
  base-directory: _site
  files:
    - '**/*'
    - 

AWS CodeBuild buildspec files has its own structure and this also depends on the version of the specification you use. In this example, I use the newest version at the time of this post which is 0.2. Now let me explain the sections of this file below.

  • env section is the place where you define your environment variables in your build container. To build Jekyll website for production, you need to set JEKYLL_ENV environment variable to production. In most example, you may see that JEKYLL_ENV=production is provided just before jekyll build step. But providing it in the env section is more suitable for AWS CodeBuild specs.
  • phases section is the place where you define your commands in each phase of the CodeBuild project. install phase is where you set the environment and install the dependencies.
  • runtime-versions in the install phase, you define the runtime for your CodeBuild container. In this example, our CodeBuild project uses an Ubuntu imagae and we would like our environment to have Ruby version 2.6 installed. Similarly, if you need Node.JS version 12.0 to build Angular code, you can define it in a list item here. You can define both Ruby and Node.js packages as well.
  • In the commands list of the install phase, you provide all commands necessary to install your dependencies. In our example, we need Ruby bundler to be installed for Ruby v2.6 and then use it to install our gems defined in the Gemfile. If you have an Angular front end, you would provide npm install command here. The commands in this list are executed in the order they are provided.
  • In the build phase, you build your code. So its commands list should contain the commands for this. In our example, we build a Jekyll website, so our command is bundle exec jekyll build. Actually, we could install jekyll gem as a global gem and use it directly with jekyll build command as well. But we might encounter version mismatches in our source and container. So it is best to use bundler while making Jekyll builds. However, this is specific to Jekyll. If you have an Angular app, you run ng build command with necessary options here.
  • artifacts is the place where you define your outputs of the build execution. In this example, we provide the contents under _site folder, because it is where Jekyll builds your content by default. In an Angular app, this would be dist folder. Also, type should be zip because we will extract it in the deploy action.

When your build run finishes, AWS CodeBuild automatically tear down the build container and you pay only for the time it executed.

What about unit tests? You can add a Test action using CodeBuild and run unit tests on your code. For example, for Ruby on Rails applications, you can execute Rspec or minitest tests. The usage will be same except you will provide your test execution commands in the build phase. ALternatively, you can add your test commands to the same buildspec above and run as another command after your build command or in the post-build phase. However, I am in favor of separating build and test actions to troubleshoot easier when I have an error in either of them.

Deploy Action: Amazon S3

Last year, AWS CodePipeline started supporting Amazon S3 buckets as deployment actions. Before that, I used an AWS Lambda function that I created to deploy the zip package exported by the build action. Now it is simpler. You only configure an S3 action.

However, you should note these things to deploy to your S3 bucket successfully.

  • You should enable Extract before deploy to extract the contents of the zip package the pipeline receives from the build action.
  • You should set CannedACL to public-read in order to make your content readable from the internet. Then the extracted content will be automatically made public.

How can you enhance this pipeline more?

This is a basic pipeline. But you can enhance it by adding test stages, integration tests, etc. In the end, you can send notifications or invalidate your CloudFront distribution using a custom AWS Lambda function. You can add new stages or actions depending on your need. Besides, you can add a manual approval step using Amazon SNS after deploying to a staging environment and apply continuous delivery instead of continuous deployment.

Join my AWS CodePipeline Course on Udemy!

Would you like to learn AWS CodePipeline? You can enroll my AWS CodePipeline Step by Step course on Udemy by clicking the link below with a special discount.

https://www.udemy.com/course/aws-codepipeline-step-by-step/?couponCode=SEP2020

Alternatively, use the coupon code SEP2020 during the checkout.

In this course, you will learn how to use AWS CodeCommit, AWS CodeBuild, and AWS CodeDeploy with AWS CodePipeline to create CI/CD pipelines to deploy your applications to EC2 and S3. Besides, you will use a basic Angular application in your hands-on examples.

You can also read my AWS CodePipeline Step by Step announcement post to get more information about the topics covered.

See you in AWS CodePipeline Step by Step!

Conclusion

I have been using AWS CodePipeline and other AWS developer tools to build CI/CD pipelines on AWS for more than 3 years. Until now, I created dozens of pipelines for applications such as Jekyll, Angular front ends like the one in this post; Ruby on Rails, PHP, PHP Laravel back ends using AWS CodeDeploy; serverless applications and AWS infrastructures using AWS CloudFormation, Docker deployments on ECR and ECS, Fargate etc. AWS CodePipeline team is continously enhancing it by adding new features and it is a great tool to deploy all type of applications on AWS.

Besides, using AWS CodePipeline costs only $1/pipeline/month if you have at least 1 executions on your pipeline in that month. Of course, you also pay for the data transfer if you deploy cross-regionally and CodeBuild runtime, but those are negligible. If you have no executions, you pay nothing for that pipeline.

It is a serverless service, you do not maintain any EC2 instances like a Jekyll server for your builds or anything like that. It is also customizable using AWS Lambda as I described in the deploy action. Hence, I recommend you to learn and use it to automate your deployments.

Thanks for reading!

References

Emre Yilmaz

Freelance AWS Consultant • AWS Certified Solutions Architect (Pro) • DevOps Engineer • Udemy Instructor

CEO @ Shikisoft

Follow

Online Courses

AWS CodePipeline Step by Step course logo AWS CodePipeline Step by Step course logo

AWS CodePipeline Step by Step

Learn how to create CI/CD pipelines using AWS CodePipeline, CodeCommit, CodeBuild, CodeDeploy, and CloudFormation. Automate your deployments to Amazon EC2 and S3.

Use the link below to enroll in this course with special discount.

Enroll Now on Udemy!

Alternatively, use SEP2020 coupon code during the checkout.

AWS CloudFormation Step by Step: Beginner to Intermediate course logo AWS CloudFormation Step by Step: Beginner to Intermediate course logo

AWS CloudFormation Step by Step: Beginner to Intermediate

Learn how to manage your infrastructure as code on AWS. Start creating CloudFormation stacks and writing your own templates using YAML as a beginner step by step.

This course will also be a basis for its advanced level version in the upcoming months.

Use the link below to enroll in this course with special discount.

Enroll Now on Udemy!

Alternatively, use SEP2020 coupon code during the checkout.

RSS

Subscribe to this blog's RSS feed

Categories