Serverless CI/CD Using Github Actions

FeedMeCompute
6 min readOct 23, 2019

--

Interested in having an automated CI/CD pipeline ready at your fingertips for any new serverless project? One that can automatically build, test, deploy, provision/de-provision new stacks for pull-requests, and be highly customizable to support a wide range of demands. The power of Serverless Framework and Github Actions (beta) removes the infrastructure hurdles this pipe-dream once imposed. Follow below and we’ll walk through getting everything set up so that you can have this in your tool-belt for future projects you dream up.

The Sample Project

For this project, we will be using Nuxt.js to generate a static site that will be hosted in a public AWS S3 bucket. As mentioned above, Serverless Framework and Github Actions will be used to support our CI/CD pipeline that will have the following features:

  • CI: Commits will trigger dependency installation, linting, and running unit tests to validate changes
  • CD on master: Following a successful test run, the static site is generated and deployed
  • CD on Pull-Requests: A dedicated stack is created for each pull-request where new changes can be seen by yourself and other team members (e.g, QA, Product, Managers, etc). Closing the PR results in de-provisioning of the one-off stack

If you’d like to jump in the code, take a look at the repo on Github.

Getting Started

Using the documentation on Nuxt.js’s website, run the following command to create a new Nuxt app:

yarn create nuxt-app <project-name>

The cli will prompt you for configuration options. Make selections as highlighted below (note: for all others choose the default(s)):

  • Linting tool: ESLint
  • Test Framework: Jest
  • Rendering Mode: Universal
  • Development Tools: jsconfig.json

Nuxt will scaffold out everything you need to get started building a new site.

Spin the site up:

yarn dev

And navigate to http://localhost:3000

Page rendered using nuxt.js

Nuxt is a powerful framework and can be used to create a wide range of web applications. For our project, we are going to use it to generate a static site using the conveniently placed generate script in package.json:

yarn generate

Once this completes, take a look in the dist folder and you’ll see all the assets needed to host this site in an AWS S3 bucket.

Output from running nuxt’s generate command

Keep in mind that other static site generators like Gatsby, React’s Next.js, and so on can be swapped out in this tutorial. Most important is that we end up with static site assets that can be hosted in S3.

Go ahead and commit your local changes.

Serverless Framework Setup

Serverless Framework offers a robust toolset for deploying serverless applications to AWS, Azure, Google Cloud, etc. We’ll start by deploying the site we generated above to AWS using our local environment.

Prerequisites:

  • Follow this article for setting up Serverless Framework and configuring AWS Credentials. When creating AWS access keys, skip the section covering setting up Access Roles in the Serverless Dashboard.

Create an empty file called serverless.yml in your root directory and copy in the following configuration:

https://github.com/stewartnoll/serverless-ci-cd/blob/master/serverless.yml

Replace the service name with <your-name>-<project-name>. This ensures things are unique enough to satisfy S3’s global naming requirements.

Install serverless-s3-sync using yarn

yarn add serverless-s3-sync --dev

This is a serverless plugin which will sync your dist folder with the S3 bucket defined at the bottom of serverless.yml

This is one of many plugins to choose from in the Serverless Framework ecosystem. Before you write your own customization in the future, look around and see if anyone has already done it, you’d be surprised.

Confirm serverless is wired up correctly:

serverless info

Output should tell you that no stack with your service name has been deployed. This is good because we’re going to deploy it next using the following command:

serverless deploy

That’s it, give it a few and you will have a new s3 bucket configured to host a static site, and with the dist folder uploaded to it.

To find your site URL, navigate to S3 in the AWS Console and click on the S3 bucket with the name dev-<your name>-<project-name>. Navigate to the Properties tab → Static website hosting → Endpoint and click. And voila, your site is publicly available. Note: this endpoint will remain the same going forward because Serverless Framework keeps track of the stack and coordinates future deployments over it (with the help of CloudFormation).

Commit your changes to your local master branch.

Github Action Setup

First, you’ll need a new Github repo to host your code and run your actions. Create a new repo (public or private) and associate it with your local repo, e.g:

git remote add origin git@github.com:<github-username>/<github-repo-name>.git

Now we’re going to wire up a workflow that will install dependencies, run tests, generate the site, and deploy whenever a commit is made on the master branch in Github.

Run the following to create the directory structure for hosting your Github workflows:

mkdir -p .github/workflows

And add the following file:

https://github.com/stewartnoll/serverless-ci-cd/blob/master/.github/workflows/master.yml

Notice, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY . We’ll need to configure these in our Github repository secrets section with the corresponding values we wired up when walking through the credential setup. Navigate to your repository in Github → Settings → Secrets and create secrets for those two keys. Those new secrets are now available to any workflow we define going forward.

Commit your changes to master and push them up to Github.

Navigate to Actions under your repo and you’ll see the workflow running, yay! Assuming everything has been set up correctly, you should see the following:

A successful run of the Master CI/CD workflow

And there you have it, full CI/CD using Serverless Framework and Github Actions. Pretty cool, right?

One last thing on the agenda; CI/CD configuration for pull-requests. This is closely related to the master workflow, with a few exceptions.

Create a new branch

git checkout -b pr-cicd

And add the following two files to the .github/workflows directory.

https://github.com/stewartnoll/serverless-ci-cd/blob/master/.github/workflows/pull-request.yml

https://github.com/stewartnoll/serverless-ci-cd/blob/master/.github/workflows/pull-request-cleanup.yml

A few key differences with pull-request.yml :

  • on: pull-request this tells Github to only trigger this workflow when a pull-request is opened , synchronized , or reopened (see documentation)
  • npx serverless deploy --stage pr$(jq --raw-output .number "$GITHUB_EVENT_PATH") this tells serverless to name the stack with the pull request # as defined in the event json file located at $GITHUB_EVENT_PATH (see documentation)

pull-request-cleanup.yml is self-explanatory in that it removes the stack when a pull request is closed.

Push the branch up to the repository in Github and create a PR from the commit. This will start the workflow which will eventually deploy a stack for the PR. Navigate to S3 and locate the PR specific bucket and find the static website endpoint.

Now, squash and merge the commit using the Github UI. This will kickoff two workflows: one for master CI/CD and another for the PR cleanup. Once the PR cleanup is done your PR specific stack will have been removed.

There you have it. Hope this helps you get up and running with a powerful CI/CD pipeline that only takes 30 min to set up. Keep in mind that there are many things I didn’t dig into so be sure to take a look around in the Serverless Framework & Github Actions documentation for more information and comment below if you have any questions.

--

--