Serverless CMS Deployment Using CircleCI

Recently I’ve blogged a few times about building a serverless CMS using Hugo and AWS tech, but I haven’t talked at all about deploying it yet.

I’ve been having a look at CircleCI, especially since the release of 2.0 of the CircleCI platform about a year ago (well, once it came out of beta anyway!).

The following was all tested using the “free” version of CircleCI: that is, you can run up to 1 Linux container for a private repo for free. Additional containers cost $50USD per month, but I haven’t had to try that yet. Instead, I rely on my patience while CircleCI does it’s thing.

Also, I haven’t got heavy investment into the CI (continuous integration) side of things, so I’m focusing on CD (continuous deployment) actions. This is mainly due to time constraints and my huge team (ie just me). So maybe it’s more like CircleCD at the moment.

Screenshot of Serverless CMS Deployment using CircleCI

Core Components

Back to the serverless CMS, Koi CMS. It has a few different components, so I’ll cover the most important ones in today’s blog:

  • Static HTML/JS editor called Ed, hosted on an S3 bucket and delivered using CloudFront
  • A bunch of Lambda functions

Additional Components

There are a few more components which are not modified very often, so they won’t be the focus of this blog. These are:

  • DynamoDB tables
  • SNS Topics (for aysnc publishing)
  • AWS API Gateway

Some notes

The config.yml file, in the .circleci folder is the heart of everything that CircleCI does. The nice thing is you can branch this file and control exactly what gets deployed where using workflows. You can also easily disable builds for specific branches all within the source code: this I really like.

I’ve skipped the workflows section of the config.yml file for simplicity, but this can be used to control the order of build jobs, dependencies and also filtering to branches.

These scripts are heavily simplified for testing purposes - so keep that in mind!

Static HTML/JS Deployed to S3 Bucket

Deploying to an S3 bucket is one of the easiest things you should be able to do! I use the –delete flag to clean up files in the target bucket which I no longer require to keep things neat. The script will also flush the cache on CloudFront so that the deployed files are served to clients.

version: 2
jobs:
  deploy-s3:
    machine:
      enabled: true
    steps:
      - checkout
      - run:
          name: Deploy to S3 bucket
          command: aws s3 sync $SOURCE_FOLDER s3://$BUCKET_NAME/ --delete
      - run:
          name: Invalidate Cloudfront distribution
          command: aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_ID --paths '/*'

Deploying a basic Lambda function

The following v2 snippet for CircleCI will checkout, compress and deploy a Lambda function to AWS. Take note of a few things to configure, preferably with environment variables, such as AWS account number and AWS region.

(This assumes your function can be found in it’s own folder and is called index.js)

version: 2
jobs:
  deploy-lambda-fn:
    machine:
      enabled: true
    steps:
      - checkout
       - run:
          name: Zip function FUNCTION123
          command: cd PATH_TO_LAMBDA/FUNCTION123 && zip -r index.zip node_modules index.js
      - run:
          name: Update Lambda function FUNCTION123
          command: aws lambda update-function-code --region $REGION --function-name 'arn:aws:lambda:ap-southeast-2:$ACCOUNT_NUMBER:function:FUNCTION123' --zip-file fileb://PATH_TO_LAMBA/FUNCTION123/index.zip
      - run:
          name: Update Lambda configuration for FUNCTION123
          command: aws lambda update-function-configuration --region $REGION --function-name 'arn:aws:lambda:ap-southeast-2:$ACCOUNT_NUMBER:function:FUNCTION123' --timeout 30 --memory-size 1024 --runtime 'nodejs8.10' --environment 'Variables={VAR1=$VALUE1}'

Some Thoughts

Deploying Lambda using the snippet above is fantastic… if you only want to deploy one function. At the moment, Koi CMS has 57 functions, so it takes about 5 minutes to run through sequentially. To make it fast (and if you’re lazy and rich) you could just spin up more CircleCI instances and run them in parallel. The better option would be to shell out to a Node script and run the deployments in an async (or parallel) way.

Native support for the AWS CLI is quite nice and it means you can get to deploying code very quickly without having to set up the CI/CD instance first before moving any code.

Want to know more? Read the CircleCI doc.