DEV Community

Cover image for Deploying a Jekyll Page to AWS S3 with GH Actions
Matthias Keim
Matthias Keim

Posted on

Deploying a Jekyll Page to AWS S3 with GH Actions

My Workflow

The name of my workflow is: jekyll-build-deploy-aws-s3-cloudfront

My workflow builds a jekyll page, uploads it to a AWS S3 bucket
and creates an invalidation for AWS CloudFront with a custom python script.
As part of the #ActionsHackathon i made some improvements on the Workflow .yml itself and also on the custom invalidation file creator written in python.

Although there exists some GH Actions which can be used to create CloudFront invalidations none of theme satisfied me.
In future I also plan to release my own GH Action which uses this python script.

I use this workflow for the webpage of a project which raises funds for children in Kenia.

Webpage for Malaika

Build Status CI/CD production

Malaika is a charity organisation which organises events to collect donations in order to help orphan children.

Technology

  • This page is build with jekyll.
  • It is hosted on AWS S3 and served over CloudFront

How to contribute

Everyone is welcome to contribute. You can create a merge request or just write us.

Text

All the text of the homepage is stored under _data/text.yml The structure of the yml file should be self explaining. You are welcome to help with the translation or to correct spelling.

CSS HTML

You are also welcome to propose improvements on the side in general.




Submission Category:

DIY Deployments

Yaml File or Link to Code

This is the Action Workflow

name: jekyll-buld-deploy-aws-s3-cloudfront

on:
  push:
    branches: [master]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - uses: actions/setup-ruby@v1
        with:
          ruby-version: "2.6"

      - uses: actions/setup-python@v2
        with:
          python-version: "3.x"

      - uses: chrislennon/action-aws-cli@v1.1

      - name: Build and deploy
        run: |
          rm -f Gemfile.lock
          bundle install
          bundle exec jekyll build
          aws s3 sync _site s3://<S3 bucket>
          python3 create_invalidation_json.py _site > invbatch.json
          aws cloudfront create-invalidation --distribution-id <distribution id> --invalidation-batch file://invbatch.json
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: <AWS Region>

This is the custom invalidation script:

from os import listdir
from os.path import isfile, isdir, join
from urllib.parse import quote
from datetime import datetime
import sys
import random


def recursive_file_lister(root_path, actual_path, all_files):

    full_path_of_dir = join(root_path, actual_path)

    content_of_dir = listdir(full_path_of_dir)

    for i in content_of_dir:

        full_path_of_file = (join(root_path, actual_path, i))
        relative_path_of_file = (join(actual_path, i))

        if isfile(full_path_of_file):
            aws_path_for_file = quote("/"+relative_path_of_file)
            all_files.append(aws_path_for_file)
        elif isdir(full_path_of_file):
            recursive_file_lister(root_path, relative_path_of_file, all_files)


def create_json_for_invalidation(all_files, refernece):

    print("{")
    print(" \"Paths\": {")
    print("     \"Quantity\":", str(len(all_files))+",")
    print("     \"Items\": [")

    for i in range(len(all_files)):
        if(i < (len(all_files)-1)):
            print("         \""+all_files[i]+"\",")
        else:
            print("         \""+all_files[i]+"\"")
    print("     ]")
    print("   },")
    print("  \"CallerReference\": \""+refernece+"\"")
    print("}")


if len(sys.argv) != 2:
    print("Usage")
    print("create_invalidation_json.py dir")
else:
    all_files = ["/"]
    recursive_file_lister(sys.argv[1], "", all_files)

    create_json_for_invalidation(all_files, "auto_deploy_script_"+str(
        datetime.now().strftime("%I_%M%p_%B_%d_%Y_"))+str(random.randint(1, 999999999999)))

Additional Resources / Info

This Action Workflow is used by the malaika homepage:
Malaika

Top comments (0)