- Initial thoughts
- 1. Use a local docker image in early stages of job creation
- 2. Use the pipeline editor for minor YAML changes
- 3. Use gitlab-ci-local to run pipelines locally
- 4. Declare test branches to simulate long-lived branches and tags
- Wrapping up
- Further reading
Initial thoughts
As developers and CICD engineers, we are all too familiar with the time-consuming process of iterating on GitLab CI YAML modifications. It can be a frustrating cycle that involves multiple steps and setbacks:
- Make a change to the YAML file.
- Commit and push the changes.
- Verify that the CI YAML is valid and the graph is as expected.
- If there are any issues or errors, start the process all over again with a sense of despair.
- Wait for the entire pipeline to finish running on the current branch.
- If the pipeline fails or doesn't behave as desired, start over again with a heavy heart.
- Refactor commits to maintain a clean git graph and push with force.
- Merge multiple times to observe the behavior on long-lived branches and tags.
- If there are any issues with the merged code, start the process all over again with a sigh.
What we initially thought would only take a few minutes ends up consuming multiple days as we continuously go back and forth, all while trying to juggle other development tasks.
In this article, we aim to alleviate this pain by providing several tips that will make your life easier. Our goal is to transform the experience of tweaking your favorite pipelines from a tedious chore to an enjoyable task. So let's dive in and discover how you can streamline your GitLab CI YAML modifications!
1. Use a local docker image in early stages of job creation
When starting a new job with a new Docker image, it's natural to feel uncertain. Especially when using initially unknown public images, following the best practice Start CI with versioned public CI docker images. To accelerate the feedback loop and gain more confidence, we can try our commands directly in a local container.
Let's consider a NodeJS job as an example. The DockerHub image alpine/k8s seems to be the most suitable base image.
Before diving into the GitLab CI YAML, let's start an interactive container:
docker run -it --privileged=true node:20.5-alpine3.17 /bin/sh
Status: Downloaded newer image for node:20.5-alpine3.17
/#
You may wonder what shell GitLab is using in containers. In fact, it is a discovery process starting with bash, so best guess is to try /bin/bash
and fallback to /bin/sh
.
Now that you're inside the image, you can easily prepare and test your commands.
Although the base is alpine
, let's assume we do not have that knowledge and want to use envsubst
. If it's not available, we can try to install it with apt-get update && apt-get install envsubst
:
/# envsubst --help
/bin/sh: envsubst: not found
/# apt-get update && apt-get install envsubst
/bin/sh: apt-get: not found
Since envsubst
and apt-get
are not available, it must be the alpine
Linux package manager, apk
:
/# apk --update add --no-cache envsubst
fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/main/aarch64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/community/aarch64/APKINDEX.tar.gz
ERROR: unable to select packages:
envsubst (no such package):
required by: world[envsubst]
Ah! It seems that envsubst
cannot be installed this way. A quick internet search reveals that the package is actually named gettext
:
/apps# apk --update add --no-cache gettext
fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/main/aarch64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/community/aarch64/APKINDEX.tar.gz
(1/9) Installing libgomp (12.2.1_git20220924-r4)
(8/9) Installing libxml2 (2.10.4-r0)
(9/9) Installing gettext (0.21.1-r1)
Executing busybox-1.35.0-r29.trigger
OK: 18 MiB in 26 packages
/#
/# envsubst --help
Usage: envsubst [OPTION] [SHELL-FORMAT]
Substitutes the values of environment variables.
By going through this discovery process within a few minutes, we saved ourselves from waiting for the pipeline to fail, which could have taken several hours for a job, especially positioned in last stages.
2. Use the pipeline editor for minor YAML changes
The GitLab CI/CD Pipeline Editor is a powerful web-based tool that provides a visual representation of your pipeline configuration. Accessible from the GitLab UI, the Pipeline Editor allows you to interactively modify your .gitlab-ci.yml file directly in the browser.
The Pipeline Editor offers several advantages. Before even commiting changes, it provides real-time feedback on the validity of your YAML syntax and helps prevent common errors. Additionally, it assists in exploring available keywords and includes inline documentation for GitLab CI/CD features. This visual approach can significantly streamline the process of making and validating changes to your pipeline configuration, reducing the need for multiple iterations.
The main limitation is that it can only edit the main .gitlab-ci.yml
file.
3. Use gitlab-ci-local to run pipelines locally
Imagine being able to run your pipelines locally without the need to push, wait, or pollute the GitLab instance. Even better, what if you could achieve this without even interacting with the GitLab instance at all?
Initially, the gitlab-runner exec
command was intended to fulfill this purpose. However, over time, the code has diverged too much from an actual pipeline running, rendering it capable of handling only 20% of the keywords. As a result, it is no longer usable. There is an official issue on this matter, but progress has been minimal.
Fortunately, the open-source community has made remarkable efforts to implement a local runner, resulting in several options:
firecow / gitlab-ci-local
Tired of pushing to test your .gitlab-ci.yml?
Tired of pushing to test your .gitlab-ci.yml?
Run gitlab pipelines locally as shell executor or docker executor.
Get rid of all those dev specific shell scripts and make files.
Table of contents
Installation
Linux based on Debian
Users of Debian-based distributions should prefer the the Deb822 format, installed with:
sudo wget -O /etc/apt/sources.list.d/gitlab-ci-local.sources https://gitlab-ci-local-ppa.firecow.dk/gitlab-ci-local.sources
sudo apt-get update
sudo apt-get install gitlab-ci-local
If your distribution does not support this, you can run these commands:
curl -s "https://gitlab-ci-local-ppa.firecow.dk/pubkey.gpg" | sudo apt-key add -
echo "deb https://gitlab-ci-local-ppa.firecow.dk ./" | sudo tee /etc/apt/sources.list.d/gitlab-ci-local.list
# OR
# MUST be `.asc` at least for older apts (e.g.
鈥�div class="highlight__panel js-actions-panel">
Top comments (2)
Top ! Constat que je partage au quotidien (cf mon talk au devops d-day de 2023).
Je vais (re)-tester certains de ces outils.
Je pourrais rajouter utiliser un moteur de CI ind茅pendant de votre CI. Les options :
a) tout faire avec make et docker
b) dagger
c) earthly
Le probl猫me avec l'outillage interm茅diaire suppl茅mentaire, c'est l'effet bo卯te noire pour les d茅veloppeurs, qui viennent dire ensuite "Ta CI ne fonctionne pas" (pas de ownership).
Je pr茅f猫re consid茅rer que Maven ou NPM sont d茅j脿 des makes ! Et la CI est jouable en local avec gitlab-ci-local, comme un make.
Les autres sont aussi des abstractions suppl茅mentaires.
On rentre dans le subjectif l脿 je pense 馃槈