Table Of Contents
Introduction
In this article series, I'll show how you can use Github Actions to setup a simple workflow that after every push to your Github repository will build and publish your code as a docker image and then deploy it to your VPS running Traefik with zero downtime.
If the above made your head spin, might be worth brushing up on a few topics first:
Why?
Because running a fancy Kubernetes cluster might be all the rage, but it's overkill for most things. Not to mention really expensive. If all you've got is a bunch of small (static?) websites or low traffic hobby projects, you'll be better off just running them all in a cheap Virtual Private Server (even a free one - e.g. GCP Free Tier).
That's where Traefik comes in, letting you run multiple domains/subdomains on the same host, each of them running nice and isolated in a Docker container.
And Github Actions takes care of deploying everything automatically, so you don't have to do anything other than push your code to the master branch (and maybe throw in a SemVer tag to keep things organised). You can even do zero downtime deployments! Neat, huh?
How?
I guess the flowchart was inevitable then. It goes something like this:
Let's push that docker image to the registry
Right, so now that the how and the why are clear as a whistle, let's push that docker image to the registry! We'll do that by creating a GitHub Actions Workflow in our GitHub repository:
name: CI
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [ master ]
# Publish `v1.2.3` tags as releases.
tags:
- v*
# TODO: file paths to consider in the event. Optional; defaults to all.
paths:
- 'path/to/code/that/triggers/this/workflow/*'
# Run tests for PRs into master branch
pull_request:
branches: [ master ]
# TODO
paths:
- 'path/to/code/that/triggers/this/workflow/*'
# Define enviornment variables for the workflow
env:
# TODO: Change variable to your image's name.
IMAGE_NAME: image-name
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# Run tests.
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: |
# TODO: Run a Dockerized testing script, or just build the docker image if no such script exists
if [ -f docker-compose.test.yml ]; then
docker-compose --file docker-compose.test.yml build
docker-compose --file docker-compose.test.yml run sut
else
docker build . --file path/to/Dockerfile
fi
# Build and push image to Docker Registry
push:
# Ensure test job passes before pushing image.
needs: test
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Only run this job for push events
if: github.event_name == 'push'
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# TODO: Builds the docker image (path relative to api root)
- name: Build image
run: docker build . --file path/to/Dockerfile --tag $IMAGE_NAME
# Login to the docker registry using the default GITHUB_TOKEN environment variable and github.actor (The login of the
# user that initiated the workflow run)
- name: Log into registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login docker.pkg.github.com -u ${{ github.actor }} --password-stdin
# Push the image to the Docker Registry
- name: Push image
run: |
IMAGE_ID=docker.pkg.github.com/${{ github.repository }}/$IMAGE_NAME
# Strip git ref prefix from version
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# Strip "v" prefix from tag name
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# Use Docker `latest` tag convention
[ "$VERSION" == "master" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION
Please note a few things:
- I've used GitHub Packages as the Docker Registry for convenience, you can use any Docker Registry you want
- Pay attention to the TODO comments, you'll need to change those to suit your app - like the paths and image name
- You can use any name and filename for the yml workflow file, but you need to place the file under .github/workflows folder in your repository
That was easy, is that it?
Sure, if all you needed was a way to automatically push a docker image to the registry once you push your code and you're happy enough to manually deploy that to your server. If not, and you want to automate everything like the nice flowchart showed you, tune in for Part 2.
Thanks!
Top comments (1)
Where can we find "Part 2"?
Thanks anyway for part 1, really interesting.