Setting Up a Continuous Deployment Pipeline for a Static Website on AWS S3 Using CodeCommit, CodeBuild, and CodePipeline

In this blog post, we'll walk through the process of creating a Continuous Deployment (CD) pipeline for deploying a static website hosted on an AWS S3 bucket. Our source code will be stored in an AWS CodeCommit repository, and we'll leverage AWS CodeBuild to generate artifacts, such as index.html webpage. The entire pipeline will be orchestrated using AWS CodePipeline.

Our CD pipeline will follow a structured architecture that seamlessly integrates various AWS services:

Components of the Pipeline

  1. CodeCommit:

    • This is where we'll store and manage our website's source code securely. CodeCommit provides a fully-managed, scalable source control service.
  2. CodeBuild:

    • CodeBuild will be utilized to produce artifacts, which include the main index.html file and any error pages. (If using Docker, CodeBuild can also be employed to build Docker images if needed. Think of CodeBuild as compute resource)
  3. Production S3 Bucket:

    • A S3 bucket with static website hosting enabled to host our website content. This bucket will serve as the production environment for our static website.
  4. AWS CodePipeline:

    • CodePipeline will be the orchestrator of our entire deployment process.

    • Our pipeline will consist of multiple stages, each representing a logical phase in the deployment process.

    • Within each stage, we'll define actions that perform specific tasks:

      • Source Stage:

        Source action: Connects to CodeCommit to retrieve the latest version of the source code.

      • Build Stage:

        Build action: Utilizes CodeBuild to compile artifacts, such as HTML files or Docker images, from the source code.

      • Deploy Stage:

        Deploy action: Deploys the artifacts to the production S3 bucket, making the changes live.

Step 1: Creating a CodeCommit Repository

AWS CodeCommit serves as a robust and scalable source control service within the AWS ecosystem, providing a secure environment for hosting private Git repositories. Follow these steps to create a CodeCommit repository for your project:

  1. Navigate to AWS CodeCommit in the AWS Management Console.

  2. Click on the "Create repository" button.

  3. Provide a repository name and an optional description for better clarity.

  4. Configure repository settings such as repository description, repository visibility (public or private), and encryption options.

  5. Click "Create repository" to finalize the setup.

Upon successful creation, you'll be redirected to a page displaying repository details and options.

Connecting to GitHub Using HTTPS:

To connect your CodeCommit repository to GitHub using HTTPS, follow these steps:

  1. Create Git credentials for authentication.

  2. Now, push your source code (in this example, an Angular hello-world app) to the CodeCommit repository. If you already have a GitHub repository, you can clone it and change the remote origin to the CodeCommit repository. Here's an example:

git clone https://github.com/umerjamil16/hello-world-angular-app-for-codedeploy
git remote -v
git remote remove origin
git remote -v
git remote add origin https://git-codecommit.us-east-1.amazonaws.com/v1/repos/angular-sample-hello-world-app
git remote -v
git status
git push origin main

Now, your source code is successfully uploaded to the AWS CodeCommit repository.

Note: A buildspec.yml file is included in the repository, which we'll explain in the CodeDeploy section. This file is crucial for defining the build process and will be utilized in subsequent stages of the pipeline.

In the next steps, we'll explore how to set up the remaining components of the Continuous Deployment pipeline, including CodeBuild, CodePipeline, and deploying the static website to an S3 bucket.

Step 2: Creating a CodeBuild Project and Build Environment

AWS CodeBuild utilizes a project configuration to define and execute builds. This configuration encompasses various aspects of the build process, including source code location, build environment details, build commands, and post-build actions. Let's explore the key components of a CodeBuild project:

1. Source:

  • Specifies the source code location (e.g., CodeCommit, GitHub, Bitbucket, S3, or a custom location).

  • Defines the branch or source version to use for the build.

2. Environment:

  • Specifies build environment details (compute type, Docker image, environment variables).

  • Defines runtime versions for languages or tools required for the build.

3. Buildspec File:

  • Optionally, a build specification file (buildspec.yml) can be provided in the source code repository.

  • Contains commands and settings needed to build the project.

4. Artifacts:

  • Specifies where the build artifacts (output of the build process) should be stored.

  • Defines the base directory for the artifacts and file patterns to include.

5. Cache:

  • Optional build caching to speed up build times by storing dependencies between builds.

6. Logs:

  • Specifies the destination for build logs (e.g., CloudWatch Logs or S3).

7. Service Role:

  • Defines the IAM role granting necessary permissions to access AWS resources during the build.

8. Timeouts and Limits:

  • Specifies build timeouts, maximum concurrency settings, and other limits.

9. Post-Build Actions:

  • Optionally, post-build actions can be defined, such as deploying artifacts or triggering other AWS services.

When creating a CodeBuild project, these configurations are provided through the AWS Management Console, CLI, or SDKs/APIs. Once set up, builds can be triggered manually or automated through events from source code repositories or other AWS services.

Buildspec File Explanation:

The buildspec.yml file in your CodeCommit repository outlines the build process for your Angular project:

version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 18
    commands:
      - npm install -g @angular/cli
  pre_build:
    commands:
      - npm install --legacy-peer-deps
  build:
    commands:
      - ng build --configuration=production

artifacts:
  base-directory: "dist/my-angular-project/browser"
  files:
    - '**/*'

Key Elements:

  • Node.js Version and Angular CLI Installation:

    • Specifies Node.js version 18 for the build environment.

    • Installs the Angular CLI globally using npm in the install phase.

  • Pre-Build Phase:

    • Executes npm install with the --legacy-peer-deps flag to handle compatibility issues.

    • Lists files (ls) and prints the current working directory (pwd).

  • Build Phase:

    • Builds the Angular project in production mode using ng build --configuration=production.

    • Lists files and prints the current working directory.

  • Artifacts Configuration:

    • Specifies the base directory for artifacts as "dist/my-angular-project/browser."

    • Includes all files and subdirectories ('**/*') within the specified base directory as artifacts.

In summary, this CodeBuild configuration ensures the proper installation of dependencies, builds the Angular project in production mode, and defines the resulting artifacts for use in subsequent stages of the pipeline.

Creating an AWS CodeBuild Project

To set up the AWS CodeBuild project for our Angular hello-world app, follow these steps:

  1. Go to AWS CodeBuild:

    • Navigate to the AWS CodeBuild console.
  2. Create a Build Project:

    • Click on the "Create build project" button.
  3. Configure the Build Project:

    • Project Name:

      • Set the project name as "project-for-hello-world-angular-app."
    • Source:

      • Source Provider: Choose "AWS CodeCommit."

      • Repository: Select "angular-sample-hello-world-app."

      • Branch: Set it to "Main."

    • Environment:

      • Environment Image: Choose "Managed image."

      • Operating System: Select "Ubuntu."

      • Runtime(s): Choose "Standard."

      • Image: Set to "aws/codebuild/standard:7.0."

      • Image Version: Opt for "Always use the latest image for this runtime version."

    • Service Role:

      • Select "New service role."

      • Create a service role in your account with the name "Codebuild-project-for-hello-world-angular-app-service-role."

    • Buildspec:

      • Choose "Use a default buildspec file."
    • Logs:

      • CloudWatch Logs (Optional):

        • Group Name: Set it to "hello-world-angular-log-group."

        • Stream Name: Use "Hello-world-angular-stream."

  4. Complete Configuration:

    • Review the configuration to ensure accuracy.
  5. Create the Build Project:

    • Click on the "Create build project" button to finalize the setup.

This configuration establishes a CodeBuild project named "project-for-hello-world-angular-app." It sources code from the specified CodeCommit repository, utilizes a managed image with Ubuntu as the operating system, and uses the AWS CodeBuild standard image version 7.0. The build logs can be optionally stored in CloudWatch Logs under the specified group and stream names.

By following these steps, you create a CodeBuild project tailored for building and deploying your Angular hello-world app.

Step 3: Creating an S3 Bucket with Static Website Hosting

Now, let's set up an S3 bucket to host the static website. Follow these steps to configure the S3 bucket and enable static website hosting:

  1. Create an S3 Bucket:

    • Go to the AWS S3 console.

    • Click on the "Create bucket" button.

    • Choose a globally unique name for your bucket (e.g., "my-hello-world-angular-website-016").

    • Enable "Object ownership: ACL Enabled" (Objects in this bucket can be owned by other AWS accounts).

  2. Configure Static Website Hosting:

    • After creating the bucket, go to the bucket's properties.

    • Navigate to the "Static website hosting" section.

    • Click on "Edit" and add "index.html" as both the index and error document.

    • Save the changes.

  3. Get Public URL:

Configure Bucket Policy:

  • In the "Permissions" tab, add the following bucket policy:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::my-hello-world-angular-website-016/*"
        }
    ]
}

This policy allows public read access to the objects in the bucket, ensuring that users can view the static website.

Note: As of now, there are no index.html files in the bucket, explaining why the browser displays an empty page. In the upcoming steps, we'll automate the deployment of your Angular app's artifacts into this S3 bucket using CodePipeline and CodeDeploy.

Step 4: Creating a CI/CD Workflow in AWS CodePipeline

Now, let's set up a continuous integration and continuous delivery (CI/CD) workflow using AWS CodePipeline. This workflow automates the build, test, and deployment phases of your release process. Here are the key components and concepts related to a pipeline in AWS CodePipeline:

1. Pipeline:

  • A pipeline is the central construct in AWS CodePipeline, representing the entire workflow and automation process from source code to deployment.

2. Stages:

  • Stages are logical units within a pipeline, representing phases in your release process (e.g., source, build, test, deploy).

3. Actions:

  • Actions are individual tasks or operations performed within each stage, such as retrieving source code, building artifacts, running tests, or deploying to a target environment.

4. Source Stage:

  • The source stage is the starting point, retrieving the source code from a version control system like AWS CodeCommit.

5. Build Stage:

  • The build stage involves using a build service like AWS CodeBuild to compile source code, run tests, and generate artifacts.

6. Test Stage:

  • In the test stage, automated tests are run to ensure the quality and correctness of the application.

7. Deploy Stage:

  • The deploy stage involves deploying the built and tested artifacts to a target environment using services like AWS CodeDeploy or AWS Elastic Beanstalk.

Creating the CodePipeline

  • Go to AWS CodePipeline:

    • Navigate to the AWS CodePipeline console.
  • Create a New Pipeline:

    • Click on "Create pipeline."
  • Configure Pipeline:

    • Pipeline Name: Set it as "pipeline-for-hello-world-angular-app."

    • Pipeline Type: Choose "V2."

    • Service Role: Create a new service role.

  • Add Source Stage:

    • Select CodeCommit as the source provider.

    • Choose your repository and branch.

  • Add Build Stage:

    • Select AWS CodeBuild as the build provider.

    • Choose your CodeBuild project.

  • Add Deploy Stage:

    • Select S3 as the deploy provider.

    • Choose the region and your S3 bucket.

    • Ensure to tick "Extract file before deploy" to unzip artifacts before deployment.

  • Review and Create:

    • Review your pipeline settings.

    • Click on "Create pipeline" to finalize the setup.

This creates a CI/CD pipeline named "pipeline-for-hello-world-angular-app" that automates the build and deployment process for your Angular hello-world app. The pipeline will trigger based on events such as code commits or manual starts, ensuring a streamlined and efficient release process.

As soon as the pipeline is created, it will be automatically triggered.

Now if you visit S3 url, you will see following:

Conclusion

In conclusion, this blog post provided a comprehensive guide to setting up a robust Continuous Deployment (CD) pipeline for a static website hosted on an AWS S3 bucket using CodeCommit, CodeBuild, and CodePipeline. We began by creating a CodeCommit repository to securely store the source code, then configured a CodeBuild project to build artifacts from the source. Following this, an S3 bucket was established for hosting the static website, complete with proper permissions and a static website configuration.