AWS CodeBuild & CodePipeline

AWS CodeBuild & CodePipeline

Reliable, Secure & Serverless Continuous Integration and Delivery

Introduction

AWS CodeBuild and AWS CodePipeline is a fully-managed continuous integration service that helps you to build, package & deploy your application in a safe and reliable manner. It enables your team to focus on building the actual application and worrying less about efforts or operations to ship it to customers.

CodeBuild & Code Pipeline Architecture

CodeBuild and CodePipeline do not only help you to build your deployment package, but also create and manage infrastructure itself via Infrastructure as Code tools like Terraform, CloudFormation, Serverless Framework, CDK, or many others.

Importance of Continuous Integration & Delivery

Compiling applications mostly requires a specific environment that offers all the needed tools, languages, and frameworks that are part of the build process. Furthermore, you want to deploy changes to your application or product regularly so that the version that is out there for either internal or external testing, as well as on production for customers, does not differ too much from the latest state of development. Thirdly, even a small-sized team of developers is usually very diverse, not only from a cultural perspective but also from a technical point of view. Everybody got his own preferences for development tools or even operating systems.

We also want to decouple the development process from the release process. Even more, we want to restrict manual production access by developers and team members as much as possible to avoid human error and also fulfill compliance requirements that may apply in a given country.

Lastly, in cases of any issue, we want to be able to easily roll back to a previous version to restore a healthy application state.

Let’s rephrase our requirements into a short summary:

  • we require a small or even large toolchain for our build processes

  • we want to have regular rollouts of new changes

  • we don’t want to rely on our build processes on developers, as development ecosystems may differ greatly from each other

  • we want to restrict manual access to production systems to reduce the chances of human error

  • we want to have reproducible build and deployments - including rollbacks to previous versions in case of issues

This sums up the following: we’re in need of a dedicated build environment with a stable toolchain, that runs without the necessity of human interactions and which is strictly separated from a security point of view.

And that’s exactly what continuous integration & delivery services and platforms like AWS CodeBuild & CodePipeline are built for.

AWS CodeBuild

As the name already implies, CodeBuild is the service that actually builds. But don’t get too caught up on this phrase, as you can basically execute anything at CodeBuild. It doesn’t just strictly map down to packaging and building applications.

You’re also able to execute infrastructure manipulations via infrastructure as code tools like Terraform or CDK, change routing destinations, execute the creation of backups, trigger Lambda functions for batch jobs, or any other process that can be poured into a script.

AWS CodePipeline

A structured and well-thought-out delivery process doesn’t just include a single build job. It’s an orchestration of many jobs, often idempotent jobs, that enable you to roll out deployment packages and infrastructure in a reliable and safe manner.

And that’s exactly what AWS CodePipeline does: it’s your CodeBuild orchestration tool. With CodePipeline, you can create pipelines that connect jobs into stages to create a multi-step rollout process that can be easily reproduced and understood.

Symbiosis of Both

If you want to stay within AWS for your delivery process, CodeBuild is a must. You don’t have to use CodePipeline but it offers itself as it perfectly extends the features of CodeBuild to build sophisticated continuous integration & delivery processes.

Those services work together very well and are quite easy to configure and set up.

Serverless and Managed

One major point that really speaks for AWS CodeBuild and CodePipeline: both are completely managed - there are no upfront costs nor costs for idling servers. You only pay per build minute and a very small fee per existing pipeline which is currently $1 per month after a pipeline has existed for at least 30 days - so you don’t pay for a new pipeline in the beginning.

Not having to maintain any build servers is a huge benefit and saves a lot of effort and operational burdens that can be used more sensibly in other places.

Key Terms

For understanding how CodeBuild and CodePipeline work, we need to go over their key terms and fundamentals.

Build Images & Containers

Builds are executed within containers. For the images that run within the containers, you’ll have two options:

  • provide your own image either via ECR or another non-AWS repository

  • use one of the managed images by AWS CodeBuild

If you’re using the managed images, they already include the runtimes for most programming languages.

Build Specs

Build specs define what your build job should actually do. Each spec file is a YAML and contains various build commands and related settings.

You can provide your build spec files either in your source code or provide a spec file when you create your build project. If provided via the source code, CodeBuild will look by default for buildspec.yml in the root directory, but you can adjust this at your build project.

Your buildspec file can be organized via the different phases which are executed by CodeBuild. Let’s have a look at a small example.

version: 0.2

env:
    # injects secrets into environment variables
  secrets-manager:
    MY_SECRET: some/secret
    # injects ssm parameters into environment variables
  parameter-store:
    MY_SSM_PARAMETER: /some/ssm-parameter
phases:
  install:
    commands:
      - npm i
  build:
    commands:
      - npx sls package
artifacts:
    # archive files which can be injected into downstream build projects
  # that follow in your pipeline created via AWS CodePipeline
  files:
    - '.serverless/**'

# cache paths so the next execution will be faster
cache:
  paths:
    - '.node_modules'

Phases

Looking into the phase details of our example build project, we can see the phases CodeBuild will run through. An example execution looks like this:

  • (<1s ms) Submitted: your job is submitted to CodeBuild's internal job queue

  • (32s) Queued: the job is waiting for unreserved compute resources

  • (53s) Provisioning: downloads your image & starts the container

  • (4s) Download Source: downloading your source code

  • (160s) Install: runs our NPM install

  • (53s) Build: runs our Serverless packing command

  • (<1s) Upload Artifacts: archives our artifacts and uploads them to S3

  • (2s) Finalizing: completing the job & freeing resources

  • Complete: build project is completed

Sources & Triggers

CodeBuild can check out a repository in the beginning. As a source provider, you can use Amazon S3, AWS CodeCommit, GitHub, or BitBucket.

Additionally, you can define if builds should be triggered automatically on source changes, e.g. a new commit to a specific branch in your repository.

Pipelines

Pipelines are an orchestrated collection of build projects. It allows structuring continuous integration and deployment into phases, including builds, quality gates, and actual deployments.

CodePipeline Pipeline AWS

The actual structuring of your pipelines is completely up to you and your requirements. You can orchestrate as many projects as needed and with as many quality gates as required.

Artifacts

At the end of a build project execution, you can chose to archive artifacts (outputs) which will then be saved at S3 and can be injected into other build projects (inputs) of your pipeline execution. CodePipeline itself will keep track of versioning, so you’ll always end up injecting the outputs of your current pipeline execution.

artifacts:
  # default artifact 'build_output'
  files:
    - 'dist/**'
  secondary-artifacts:
    # additional named artifacts
    terraform_output: # name of the artifact
      files:
        - '**/*'
      base-directory: 'infra'
      name: 'terraform_output'

The default output artifact will be named build_output. There’s the option to create additional output files via secondary-artifacts with a unique naming.

Monitoring

Your CodeBuild and CodePipeline projects execute the most critical actions in your AWS account. That’s why monitoring is crucial, as with every other resource.

Logging

All console output at CodeBuild is by default ingested at CloudWatch if the necessary permissions are assigned to the service roles. This allows for traceability if build projects fail.

Build Notifications

AWS CodePipeline integrates with AWS Chatbot which allows for simple and readable notifications via your favourite communication tools, e.g. Slack.

You’re also able to filter for events, as you may only want to get notified for specific events like failures.

resource "aws_codestarnotifications_notification_rule" "failures" {
  detail_type = "BASIC"
  event_type_ids = [
    "codepipeline-pipeline-stage-execution-succeeded",
    "codepipeline-pipeline-stage-execution-failed",
    "codepipeline-pipeline-manual-approval-succeeded",
    "codepipeline-pipeline-manual-approval-needed"
  ]

  name     = "Production"
  resource = "arn:aws:codepipeline:eu-central-1:0123456789012:production"

  target {
    address = "arn:aws:sns:eu-central-1:0123456789012:slack-alerts-chatbot"
  }
}

Security

Your continuous integration & delivery solution will likely have the widest permissions as it needs to be able to create, update and destroy your infrastructure and deploy code artifacts and may be the only entity to access the production environment.

This makes it a critical component from a security perspective.

AWS IAM Integration

CodeBuild and CodePipeline are fully integrated into AWS IAM. Each of your build projects and each of your pipelines will use IAM service roles to get their permissions.

This means that permissions can be as restrictive as needed and do not need to be shared in the first place.

VPC Support

By default, CodeBuild projects can’t access resources that reside in a VPC. By adding your VPC ID, the VPC subnet IDs, and the VPC security group IDs to your build project configuration, CodeBuild will be able to access private resources in your VPC.

Example use-cases that require VPC integration:

  • your relational database resides in a VPC and integration tests do require access

  • regression tests require directly verifying cached data in a Redis clusters

  • a build step requires access to a web service that only allows requests from allow listed IPs

If there is no dedicated requirement, CodeBuild doesn’t need to be integrated with a private VPC as it’s fully protected by IAM.

Encryption

Your build outputs are sensitive information. As they will be saved at S3 you can enable encryption as with all other objects. You can either choose to use those S3-managed encryption keys or go with a dedicated customer-managed key from KMS only for your CodePipeline project.

This also applies to caching.

Approval Stages

Your typical release pipeline does not run through all stages without user interaction. Most teams do want to have a fixed release cycle which requires developers to manually approve the deployment to production.

CodePipeline meets this requirement via approval steps that can be integrated between build projects and do require a response from a user that has the needed codepipeline:PutApprovalResult permissions assigned.

Users will also be asked to put a message for either approval or rejection, so decisions can be traced later.

Pricing

As mentioned earlier, CodeBuild and CodePipeline are solely pay-per-use except for a small fee per created CodePipeline project.

Advantages and Downsides

After going through all the fundamentals, it’s great to recap what AWS CodeBuilds and AWS CodePipelines do very well and what might be improved in the future. In any project, you’ll spend a significant amount of time with continuous integration & delivery services so it’s important that it does meet your requirements.

On the plus side

There are a lot of things done right by both services.

Pay-as-you-go Pricing

You’ll never pay for idling build agents as it’s an on-demand service with linear pricing based on your actual usage. This makes it a perfect fit for side projects or any project that does not require running builds 24 hours a day.

Fully-managed

A managed service is a good service. In the case of AWS CodeBuild and AWS CodePipeline, you don’t need to maintain anything besides the configuration of your projects.

Reliability

Both services offer high availability and also do grant service credits for certain availability levels that are not met within a month.

You’ll receive 10% of your charges back for a monthly uptime percentage that is less than 99.9% (less than 1 hour per month), 25% for less than 99%, and full reimbursement of costs for less than 90%.

Room for Improvements

There’s no perfect service or solution for anything. This includes AWS CodeBuild and CodePipeline. Let’s visit the most prominent critics.

Build Times

Each CodeBuild job will bootstrap a build container with your desired image and therefore run to a lot of initial phases. This includes: submitting the job to AWS’ CodeBuild queue to wait for computation resources, preparing the needed infrastructure for your build environment, downloading the build image, starting the container itself and maybe executing any pre-build commands, installing scripts, or downloading outputs from previous build jobs.

All of this takes time for which you’ll be billed. In non-serverless build environments with steady build agents, this happens way faster as the infrastructure stays intact, containers are already running and caches may be already in place at the build agent.

Console Interfaces

The console interface has a lot of nested views and is very heavy on written texts instead of good visualizations. Also, there’s no single overview for the build projects of several pipelines which developers are used to if they know build tools like Jenkins.

Because of that, we decided in a previous project to build our own dashboard to reduce the daily struggle with CodePipeline's console interface. The good thing: it is a very low effort! That's why I've created a small article about how you can build your own zero-cost build dashboard with CloudFront, S3, Lambda & API Gateway.

On-demand Pricing

We’ve listed this on the pro side, but it can also be negative. For projects that require constant execution of builds, CodeBuild can get very expensive.

Have a second thoughts and use AWS Pricing Calculator to get an estimate of your bill beforehand if your project meets either one of the following:

  • extensive automated quality gates and testing that does require a lot of time

  • many automated checks on pull requests or branches

  • many build projects that are executed without much idling times

  • very regular release cycles, maybe even multiple times per day

Either one of those criteria may result in a large bill only for CodeBuild. A build tool with steady build agents that are always available (e.g. self-hosted Jenkins on ECS with Fargate) may be a cheaper option.

Container Images

AWS offers managed images for CodeBuild and you’re able to choose to automatically make use of the latest version. It contains a default set of developer tools and languages that are sufficient for a lot of cases.

Nevertheless, you may have requirements for a lot more tools and dedicated versions which result in having to use your own container image. Relying on non-managed container images results in operational costs in keeping them up to date by updating them in a regular manner.

If your application landscape may be built via a lot of different tools and technologies, this can result in having a single very large build image for all build projects, spiking build times due to longer phases for downloading and bootstrapping containers, or several, dedicated container images that do require more efforts to be kept up to date.

Final Words

AWS CodeBuild and CodePipeline are not the holy grail of continuous integration & delivery solutions due to constraints like a sluggish user interface, comparably slow build times, and a list of missing features.

But nevertheless, it’s a mature service, that offers high reliability, and fair pricing and does not come with many operational costs. Due to its native IAM integration, there are no additional efforts to make it as secure as any other resource of your AWS account which comes with a huge plus.