I’ve heard a lot of good things about Github Actions and decided to try it out myself.
My projects always include building Docker images and pushing them to a specific registry to deploy to staging or production. Before doing so I also run unit and integration tests.
I wanted to automate this process so that whenever I push to the master/main branch, Github Actions first run my tests, and if they succeed, it builds and pushes a Docker image to a privately hosted Docker registry. Which then starts up in my test/staging environment.
In this post I share what I came up with.
This example project is a monorepo that contains a server directory, which is a Nodejs API, and a frontend directory. All in the same Git repository.
This is the yaml file my research resulted in, for building the Nodejs API image. The workflow for the frontend code is very similiar so I wont get into that here.
Note that my Github Actions are running on a self hosted runner.
name: Server CI workflow
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
unit-tests:
runs-on: self-hosted
defaults:
run:
working-directory: ./server
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache-dependency-path: server/package-lock.json
- run: npm ci
- run: npm run unit
deploy:
needs: unit-tests
runs-on: self-hosted
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Login to private registry
uses: docker/login-action@v1
with:
registry: ${{ secrets.REGISTRY_URL }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
-
name: Build and push
uses: docker/build-push-action@v2
with:
context: ./server/
file: ./server/Dockerfile
builder: ${{ steps.buildx.outputs.name }}
push: true
tags: '${{ secrets.REGISTRY_URL }}/my-project/server:latest'
cache-from: 'type=registry,ref=${{ secrets.REGISTRY_URL }}/my-project/server:buildcache'
cache-to: 'type=registry,ref=${{ secrets.REGISTRY_URL }}/my-project/server:buildcache,mode=max'
Replace my-project
with the name of your project.
The first job in the yaml-file runs the unit tests, if successful, the second job runs which logins to my private docker registry, builds my docker image, and pushes it to the registry.
Using secrets
The curly brackets represent Actions Secrets, which are injected when the Actions runs. I am using three secrets: registry url, registry username and registry password which are required to login to the docker registry. Read more about actions secrets here.
Please let me know if this post has helped you by commenting or reacting to the article.