How I started deploying my jekyll blog with Github Actions in 15 minutes

This week I decided to take a look at Github Actions, and found out that the free tier includes 2k minutes of free build time.

In the past I deployed this jekyll blog by triggering some commands with a pre-push git hook. My blog is hosted in cloudfront and deploying it is as simple as running a s3 cp command with awscli.

#!/bin/bash

# deploy
if [[ -n $AWS_ACCESS_KEY_ID ]] && [[ -n $AWS_SECRET_ACCESS_KEY ]]; then
    cd site
    bundle exec jekyll build
    aws s3 cp _site/ s3://dimmaski/ --recursive
    echo "Finished deploy"
    exit 0
else
    echo "AWS creds not set."
    exit 1
fi

I had the following git hook.

# .git/hooks/pre-push
protected_branch='master'
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

if [ $protected_branch = $current_branch ]; then
    ./deploy
    exit $?
else
    exit 0
fi

In case you are not familiar with git hooks, they are pretty straight forward. You tie a script (e.g a series of commands) to a given git action, pre-push pre-commit, etc. (ls .git/hooks to find all the triggers). Git hooks got me going initially, but it’s not the best option since it forces me to load my AWS credentials into my running shell every time I want to commit, plus it makes it annoying if I want to write a post in another machine. So I found the right alternative that is working for me, at least for now.

Github Actions

What you got here for. Github allows you to define a yaml file that lives inside your repo and contains all the steps necessary to build and deploy your app. You can find lots of plugins in the marketplace. To achieve the purpose of this post I only needed to look for one specific action: jakejarvis/s3-sync-action. Since I decided to run my build step inside a docker container.


name: Jekyll site CI

on:
  push:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Build the site in the jekyll/builder container
      run: |
        docker run \
        -v ${{ github.workspace }}/site:/srv/jekyll -v ${{ github.workspace }}/_site:/srv/jekyll/_site \
        jekyll/builder:latest /bin/bash -c "chmod 777 /srv/jekyll && jekyll build --future"
    
    - uses: jakejarvis/s3-sync-action@master
      name: push site to s3 bucket
      with:
        args: --follow-symlinks --delete
      env:
        AWS_S3_BUCKET: 'dimmaski'
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        AWS_REGION: 'us-west-1'
        SOURCE_DIR: '_site'

The CI/CD workflow, if we can even call it that, for a jekyll site deployed in s3 is quite straight forward. Even more when described in yaml. The only tricky part is that two-line docker run command, that looks horrendous, but is doing its job. We are setting two volumes: ${{ github.workspace }}/site mounts our repo inside the container; and ${{ github.workspace }}/_site allows us to retrieve our static files generated inside the container back to our workspace. (Note that I have a folder called site in my repository where my jekyll files live. If you’re hosting your files in the root of your repo you should only specify ${{ github.workspace }}). The deploy step is encapsulated in the jakejarvis/s3-sync-action. The secrets live inside the repository settings. Go to Settins > Secrets > Add a new secret.

That’s it. Simple!

· jekyll, CICD, github actions