CI Pipeline with Github actions

makefile, build, test, publish image

Joel Lim
Sapere
4 min readMay 30, 2021

--

Not starting features before there’s CI. I’m a strong advocate for this. With open source/ free/ cloud options — Github, Docker there is really no excuse. It’s relatively easy to set up, cheap. The later it’s delayed the harder it is to figure out from scratch. With the environment set up, there’s less friction in writing code that’s testable and refactoring.

The PR is merged! https://github.com/aljorhythm/sapere-server/pull/2. Here is a journal of the decisions and lessons learnt. Some of these are documented in the changes of the PR.

https://github.com/aljorhythm/sapere-server/actions

The repo effectively has CI, and can be slowly evolved. On branches where work is done the pipeline is run and when it’s successful deployable app is publish. There are countless features and things to implement. Logging, configuration loading, docker compose/k8s etc… I’m happy with this progress.

Steps

  1. lint
  2. unit test
  3. build image
  4. run container
  5. service test
  6. stop container
  7. publish image

As far as possible, all discrete steps are executable in any machine — including local. CI providers — Jenkins, Github, CircleCI etc. should just be orchestrators. This makes it easy to test the discrete steps themselves and makes the application more provider agnostic.

CI_PLAT

This variable is used to differentiate where the pipeline was run. The most obvious use case is choosing which image to deploy. Steps run in local cannot really be trusted even as much as we’d like to. As an example in this design images which begin with local. will not be deployed to production.

Service Tests (some call this Functional tests)

No framework has been chosen yet, it’s only a simple curl command. It takes in a host. It’s important to have this step. In the future databases in this service can also be spun up. There’s a level of tests that do not require deployment into a shared environment. Even in an shared environment, this structure can be reused.

Trunk-based development

Pipeline runs on source branches. If all is good an image will be published. There’s no deployment for now, so it’s mainly CI.

Github: Actions

That’s it. Orchestrating the flow on the CI server.

TBD with Github: PR Mergeability

Branches have to be up to date before merging. This also ensures no merge commit is created on the trunk branch after merging, which represents a different state of information.

Changelog

Changelog is version controlled just like code. All information within the repository should be treated as seriously as code. There won’t be combining of changelog files after merging a PR which creates a new commit. Everyone works on changelog like working with code. Deal with any conflicts early.

Image Tagging Convention

Images are tagged with enough information such that they can be traced back to version control and also be easily looked up for deployment. Although commit is sufficient for associating with state of information, with trunk-based development there is still a concept of a trunk. Say we want to deploy the latest on trunk, we should be looking for something like main-latest. Ended up with 3 data points that can be associated with an image: where it was built, branch name and commit hash.

Multiple tags for the same image
  • Where it was built: g-actions/ local tells us where this was built from.
  • Branch: change-dockerize
  • Commit: 8a7822a
Shell script that pushes an image with different tags

What’s next?

Deployment. Compose. Config. Security.

--

--