SwiftUnwrap

Discover about Swift, iOS and architecture patterns

Building a blog: Deploying using Github Actions and AWS

April 20, 2021

In Building a blog with Publish we saw how to make a website using Publish. Today let's see how we can automate its deployment using Github Actions and AWS.

Github Actions

Github Actions is quite new compared to other solutions as it was made available back in... 2020 😯.

To use it all you need to do it is create Yaml files into a .github/workflows root directory. Each one define a workflow that will be automatically executed on your repository based on some events you defined.

When starting the blog I first decided to have one workflow (deployment) handling both preproduction and production environments. While appealing at first because avoiding some code duplication you quickly end up with lots of conditions inside it making very hard to maintain.

So after some try and learn I actually decided to have 2 workflows hence 2 Yaml files:

  • preproduction.yaml
  • production.yaml

Events

First thing to define is events. Events are activity triggering your workflow like pull requests, pushes and so on. I decided to trigger preproduction when opening a pull request or pushing on master while production is triggered on every Tuesday or manually.

# Preprod
on:
  pull_request:
    branches: [master]
  push:
    branches: [master]

# Prod
on:
  # Deployment is scheduled to be trigged on every Tuesday at 14h45 UTC
  schedule:
    - cron: "45 14 * * TUE"
  # This allow me to manually trigger the workflow from Github interface  
  workflow_dispatch: { }

Jobs

Our Yaml next entry is jobs. You can have multiple jobs in a workflow but mines only use one: deploy. It define two things:

  1. A Runner (no link with Cyberpunk 2077) to set the host machine we want to use
  2. The actions we want to run

For now all we need is to checkout the repository, install swift and build our project:

#Preprod
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout repo
      uses: actions/[email protected]

    - name: Install swift
      uses: YOCKOW/Action[email protected]
      with:
        swift-version: "5.3.3"

    - name: Generate site preview
      run: swift run SwiftUnwrap --upcoming-articles

#Prod
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout repo
      uses: actions/[email protected]

    - name: Install swift
      uses: YOCKOW/Action[email protected]
      with:
        swift-version: "5.3.3"

    - name: Generate site
      run: ENV=PROD swift run      

We don't use a macOS runner because there's no really need for it. Beside Github Actions is limited to 2,000 mins/month on Linux and only 200 mins/month on macOS.

Deployment

Now that our workflow run and build our project we need to deploy it. You get multiple choices to deploy your website: AWS, Scaleway, Heroku,... and Netlify.

I did test Netlify but ended up with AWS for two reasons:

  1. Configuration is very limited and the whole thing felt too much "magic" to me
  2. Previous deployments are not deleted. Meaning deploying 300 times would result in having 300 times my project on servers. It might seem ridiculous to some but to me it is a very negative ecological aspect 🌳🌎.

Netlify being a NoGo I went to use AWS buckets.

AWS

You'll first need to create a AWS S3 bucket on Amazon and configure it for being accessible as a website.

Once done we then need to add a step in our Github Workflow to deploy our built website on AWS. Github Actions already come with AWS CLI installed so we won't need extra step to download those.

# Preprod
- name: Deploy to Preprod
  run: |
    aws s3 sync Output $AWS_S3_URI --delete
    aws s3 cp robot.txt $AWS_S3_URI
  env:
    AWS_S3_URI: ${{ secrets.AWS_S3_URI_PREPROD }}
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

# Prod
- name: Deploy to Prod
    run: aws s3 sync Output $AWS_S3_URI --delete
    env:
      AWS_S3_URI: ${{ secrets.AWS_S3_URI_PROD }}
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}    

If your deployment fail and you have 'botocore.utils.BadIMDSRequestError' error, change your runner to ubuntu-18.04.

You should now have a running blog on the web. Congratulations! 🎉