I’ve just released this open source build framework: https://gitlab.com/smcphee/build-flow-example.
It is an example of a CI/CD pipeline for gitlab.com projects, it uses the .gitlab-ci.yaml
CI/CD file to build projects on gitlab CI runners and deploy the resulting docker images to gitlab’s internal docker registry (other repositories are possible to configure).
It implements a preferred workflow for CI/CD that we (at my work) have developed over some time using a self-hosted gitlab. We developed this workflow using Makefiles. The goal of the new project was to take the concepts we use there and completely re-implement them from scratch, in my spare time (and thus freeing them of any work-related copyright claims), and all the while completely eliminating the need for a Makefile
(personally, I don’t mind Makefiles but some people hate them). Instead this example uses pure .gitlab-ci.yml format.
It results in your production Docker images being created as repo:1.1.1
, i.e. with semver tags. The version number generation for production releases is achieved by using the python library bumpversion. Gitlab really needs to add some type of native semver generation into its build pipeline, if it did, then half of this project would never have been necessary, however, until then, here it is.
npm install
). Who thought that was a great idea? Let yourself out, thanks.There are a number of features to this CI/CD pipeline example.
develop
and master
.
develop
.develop
is merged to master
(more on this in a minute).v*
is a version tag for a production release and also protected.prd
(production) and npr
(non-production).
prd
runs the master
branch artefact.npr
runs the develop
branch artefact.npr
-environments are created from feature branches.develop
branch to the local development environment.git checkout -b my-awesome-feature
repo:my-awesome-feature-abcdef09
(where my-awesome-feature
is the branch name and abcdef09
is the short git hash of the commit).4.3
and 4.4
until complete.develop
. Typically, a repository Maintainer, or at least a different Developer, would do this, and review the code before accepting the merge request.develop
branch will create repo:develop-abcdef09
and repo:develop-latest
tags for the Docker artefact.develop
into master
.mvn clean compile test
, and;vN.N.N
where N.N.N
is a semver compliant version number.repo:vN.N.N
and repo:stable
.develop
branch)..bumpversion.cfg
file controls what files bumpversion changes (itself included!). Currently it changes itself and .mvn/maven.config
(which tells maven what version it is building).Both tagging the release from master and pushing the updated semver into the develop branch from the tag are done with gitlab api calls. The neat thing about this is that you do not need to escalate git privileges inside the running docker builder image, which is what you’d have to do in order to perform a git push
from inside the running build. What you do need to do is to create a protected, masked variable inside your build (or its parent group) called API_ACCESS_TOKEN
. This token requires full API access to your gitlab project (you create this token in gitlab).
Currently the docker artefacts are published to the gitlab registry. In order to build the images and publish them I have used the Kaniko project image gcr.io/kaniko-project/executor:debug
. This is all documented on gitlab as a sensible alternative to using docker-in-docker. The latter method is a frightful way to build docker images.
Please clone and detach the repository and then modify to your heart’s content.
If you are using it on gitlab.com, and publishing the images back into the projects’ gitlab-hosted docker registry, you can use it almost unchanged. You will have to modify the process of compiling the software (it’s Java 11 and uses maven 3.6). You’ll have to modify the Dockerfile to suit your application.
In the gitlab-ci.yml
you may have to modify the following lines:
line 11, 12, 13. This is only needed for maven. Even if you are using Java and maven you might want to change them.
line 14. If you want some branch other than develop
to get the new version pushed into it after the production release container is created.
line 20. This caches the local maven repository between runs. You may want to cache something else, or nothing.
line 27 to 32. This specifies the custom container (based off the Amazon Linux Corretto11 container) that I use for compiling the software. If you’re not using Java, use some other container and alter these lines appropriately. It also specifies the jar
files as build artefacts which are attached to each build run. If you not using Java you’ll want some other artefacts.
echo "{ \"branch\":\"$PBRANCH\", \"commit_message\":\"$COMMITMESSAGE\", \"actions\":[ \
{ \"action\":\"update\", \"file_path\":\".bumpversion.cfg\", \"encoding\":\"base64\", \"content\":\"$CONTENT_BUMPVER\" }, \
{ \"action\":\"update\", \"file_path\":\".mvn/maven.config\", \"encoding\":\"base64\", \"content\":\"$CONTENT_MVNCFG\" } \
] }" > payload.log
This line specifically creates a json payload which commits two files into the $PBRANCH
branch (default is develop
) of the git repository using the gitlab API. It’s currently the ugliest part of the entire pipeline (look at all that horrific quote escaping!) and the part I am most likely to change. If you’re not using Java you will definitely not require .mvn/maven.config
.
Also look at line 161 and line 162 which gather the new content (and base64 encode it) of those two files respectively and put them into the environment variables $CONTENT_BUMPVER
and $CONTENT_MVNCFG
for inclusion in the API call.
The following lines invoke mvn
to compile the Java:
This code is released with the GNU GENERAL PUBLIC LICENSE, Version 3
(GPL3) license.
See the LICENSE.
If you have issues or suggestions please raise an issue, or preferably submit a merge request.