GitHub Actions vs. AWS CodePipeline

Andreas WittigUpdated 16 Sep 2020

Deployment pipelines first! When launching a new project, start with building a deployment pipeline. Automating the process from changing the source code to shipping your application to the production environment is a success factor.

But how to build a deployment pipeline? This post compares two different approaches: GitHub Actions and AWS CodePipeline.

GitHub Actions vs. AWS CodePipeline

GitHub has been hosting source code for more than ten years. On top of that, GitHub announced their CI/CD service called GitHub Actions to the public in November 2019.

AWS empowers developers with its continuous delivery service CodePipeline since July 2015. About a year later, AWS announced an essential add-on: CodeBuild. When I write about CodePipeline in the following, I always refer to a combination of CodePipeline and CodeBuild. So to be more accurate, the title of this blog post should be: GitHub Actions vs. CodePipeline and CodeBuild.

Overview

Both GitHub Actions and AWS CodePipeline use similar concepts to provide a deployment pipeline:

  • Workflow Management: customize the deployment workflow to your needs by arranging actions in parallel or order.
  • Isolated Job Execution: use pre-build or custom container images to provide an isolated environment for executing actions (e.g., a build job).

Deployment Pipeline: Overview

In summary, the main concepts are similar, but what are the differences?

Comparison

The following table compares GitHub Actions and AWS CodePipeline. To achieve better comparability, I examine the GitHub-hosted runner with 2 CPU and 7 GB memory with the CodeBuild compute type general1.medium, which comes with 4 CPU and 7 GB memory.

GitHub ActionsAWS CodePipeline
Free Tier (Linux)free for public repositories
GitHub Free: 2,000 build minutes per month
GitHub Pro: 3,000 build minutes
GitHub Team: 10,000 build minutes
50 minutes per month
Costs for Pipelinefree$1.00 per month
Costs for Build Job$0.008 per minute$0.010 per minute
EnvironmentsLinux, Windows, macOSLinux, (Windows)
Source Code RepositoryGitHubGitHub, Bitbucket, AWS CodeCommit, Amazon S3
Deployment TargetAny environment, works best for public cloud providers.Mainly AWS, in theory you could deploy to other cloud providers as well.
AWS AuthenticationStore access keys of IAM user in GitHub SecretsIAM role, no need to manage access keys
Developer Experience🏖 Easy to use🤷‍♀️ Difficult to get started
IntegrationsOpen marketplace providing all kinds of integrations of mixed quality.Pre-built and high quality integrations into the AWS ecosystem.
Self-hosted Workers?⚠️ with custom actions and custom code
Serialize pipeline executions
Support for multiple branches?
Pipeline as Code⚠️ with custom CloudFormation or Terraform and CodeBuild action

GitHub Actions offers an outstanding developer experience. As long as you host your source code on GitHub, the solution is flexible, not only because of the integrations (aka actions) offered in the open marketplace. AWS CodePipeline integrates very well into the AWS ecosystem. Being able to use IAM roles for authentication instead of fiddling around with access keys for IAM users is a big plus.

Integrations

AWS CodePiline comes with the following pre-built integrations:

  • AWS CloudFormation deploy your Infrastructure as Code templates
  • AWS CodeBuild run any kind of build job inside a container
  • AWS CodeDeploy deploy to a fleet of EC2 instances
  • Amazon Elastic Container Service (ECS) deploy your containers with ECS
  • AWS Elastic Beanstalk deploy your app on Amazon’s PaaS platform
  • AWS OpsWorks Stacks deploy your app based on Chef cookooks and recipes
  • AWS Service Catalog deploy a product
  • Alexa Skills Kit deploy your skill
  • AWS Lambda invoke customized source code
  • AWS Device Farm run UI tests on mobile devices

It worth mentioning that the integration with AWS CodeBuild allows you to run any script inside a container based on a pre-built or customized image. This provides maximum flexibility. On top of that, a few 3rd party services are integrated as well.1

GitHub has taken a different approach: its open marketplace lists more than 2,000 integrations (aka actions)2. Well known and trusted organizations (e.g., GitHub itself also AWS), as well as individuals, publish their actions. A few examples:

  • cfn-lint-action by Scott Brenner enables arbitrary actions for interacting with CloudFormation Linter.
  • amazon-ecr-login by AWS logs in the local Docker client to one or more ECR registries.
  • cache by GitHub allows caching dependencies and build outputs to improve workflow execution time.

Be careful when adding 3rd party actions to your deployment pipeline. First of all, you need to 100% trust the code that you are adding to your deployment pipeline. In theory, someone could insert malicious code or steal your AWS credentials by publishing a trojan horse to the GitHub Marketplace. Also, a 3rd party action could be removed from the GitHub Marketplace, which will break your deployment pipeline out of a sudden.

Luckily, it is not very hard to implement your own GitHub Actions.

  • Node.js run some JavaScript code
  • Docker run anything that you have packaged into a Docker image before

The following example shows how to build a GitHub Action to deploy a CloudFormation stack. I’ve decided to use a Docker-based action, as this approach is very flexible.

First of all, you need to define a Dockerfile. The Dockerfile defines the base image, installs build dependencies, and adds the entrypoint.sh script, which will be executed on each action invocation.

Dockerfile
# Base image to start from
FROM amazonlinux:2

# Installs the AWS CLI
RUN yum install -y awscli

# Adds custom entrypoint
COPY entrypoint.sh /entrypoint.sh

# Execute custom entrypoint by default when starting the container
ENTRYPOINT ["/entrypoint.sh"]

Use the entrypoint.sh script to customize your deployment. In this simple example, all we need to do is to execute the aws cloudformation deploy command.

entrypoing.sh
#!/bin/bash
set -ex

aws cloudformation deploy ...

One tiny bit is missing. GitHub Actions requires you to describe your action in an action.yml file. The configuration file includes a name and description for your action. On top of that, the action.yml file tells GitHub to run the action inside a Docker container. GitHub builds the container on-the-fly with the help of your Dockerfile.

action.yml
name: 'Deploy CloudFormation Stack'
description: 'Deploying a CoudFormation Stack'
runs:
using: 'docker'
image: 'Dockerfile'

That is a simple way to define custom actions for your deployment pipeline.

Configuration

How to configure a deployment pipeline? Define your pipeline as code. My blog post Delivery Pipeline as Code: AWS CloudFormation and AWS CodePipeline is still relevant. A lot of know-how and learnings will be baked into your deployment pipeline. Make sure that knowledge is written down in code so that you can reproduce it whenever necessary.

GitHub requires you to define your workflow within your source code repository. The following code snippet shows the definition of the deployment pipeline used to deploy this website.

  1. Check out the source code.
  2. Read the access keys for AWS from the repository secrets.
  3. Execute the custom deploy action described in the previous section.
.github/workflows/main.yml
on:
push:
branches:
- master
name: deploy
jobs:
deploy:
runs-on: ubuntu-latest
name: 'Deploy'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: $
aws-secret-access-key: $
aws-region: eu-west-1
- name: Deploy
uses: ./.github/actions/deploy/
id: deploy

Use AWS CloudFormation or Terraform to define your AWS CodePipeline. The following example shows a CodePipeline written down as a CloudFormation template.

  1. Checkout source code.
  2. Deploy the CloudFormation stack.
pipeline.yml
# [...]
CodePipeline:
Type: 'AWS::CodePipeline::Pipeline'
Properties:
ArtifactStore:
Location: !Ref ArtifactStore
Type: S3
RoleArn: !Sub '${CodePipelineIAMRole.Arn}'
Stages:
- Name: Source
Actions:
- Name: Source
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: 1
Provider: GitHub
OutputArtifacts:
- Name: Source
Configuration:
Owner: !Ref GitHubOwner
Repo: !Ref GitHubRepo
Branch: master
OAuthToken: !Ref GitHubOAuthToken
- Name: Deploy
Actions:
- Name: Deploy
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
InputArtifacts:
- Name: Source
Configuration:
ActionMode: CREATE_UPDATE
TemplatePath: 'Source::infrastructure.yml"
Capabilities: CAPABILITY_IAM
StackName: 'example'

For me, it is most important to define your deployment pipeline as code. Both approaches are similar to my point of view.

AWS Credentials

Your deployment pipelines need administrator access to be able to deploy your application and infrastructure to AWS. In general, you should avoid IAM users with access keys wherever possible. However, using access keys to authenticate an IAM user with far-reaching authorizations is the only option to execute a deployment with GitHub Actions. Of course, GitHub offers a way to store the AWS access keys in a secure and encrypted manner. A residual risk remains. On top of that, you need to rotate the access keys regularly to follow security best practices and compliance rules.

AWS CodePipeline has an advantage here. Instead of using static access keys, make use of IAM roles, which provide short-living access keys out-of-the-box. You can even define different IAM roles for various actions in your pipeline, which allows you to implement the least privilege principle.

Vendor Lock-in

In my view, there is no significant vendor lock-in for deployment pipelines. Make sure to put the real magic to custom actions running inside Docker containers. Doing so allows you to switch between CI/CD solutions very quickly. For example, I’ve migrated the deployment pipeline for this website from Jenkins to GitHub Actions within 2 hours.

It is worth mentioning that GitHub Actions works with your source code hosted on GitHub only. AWS CodePipeline works with your source code hosted on AWS CodeCommit, GitHub, or Amazon S3 (can be used as a workaround to integrate with any source code repository).

Summary

I like the experience that GitHub Actions are providing for building deployment pipelines. The deep integration into my development workflow (e.g., pull requests) is excellent. Also, GitHub Actions are easy to use. On the other hand, I’m missing the integrations into the AWS ecosystem that I’m used to from using AWS CodePipeline. However, the main concepts behind GitHub Actions and AWS CodePipeline are similar. Therefore, the details are decisive in the selection.


  1. 1. https://docs.aws.amazon.com/codepipeline/latest/userguide/integrations-action-type.html
  2. 2. https://github.com/marketplace?type=actions

Andreas Wittig

Andreas Wittig

I’ve been building on AWS since 2012 together with my brother Michael. We are sharing our insights into all things AWS on cloudonaut and have written the book AWS in Action. Besides that, we’re currently working on bucketAV,HyperEnv for GitHub Actions, and marbot.

Here are the contact options for feedback and questions.