ARM your continuous integration system with fruits! 🍌
The goal of this howto is to show you how to add your own ARM Gitlab runner to your Gitlab instance Runners herd.
Let me introduce quickly the concepts.
Continuous integration with Gitlab
Continuous integration allows the developers on a project to check that each change they made did not introduce any regression. Each commit will be followed by a build of their application, and by a run of their test suite. If every test runs still the same way after the commit, then all is fine.
Today, we’ll be only interested in their continuous integration feature.
Starting Continuous Integration (i.e. CI) is really straightforward with Gitlab. Just create a
.gitlab-ci.yml file in your repository hosted in Gitlab, populate it with the commands needed to build your application, and you’re good to go!
But wait… Where does that build and test execute? That’s where the runners enter.
Runners are machines linked to Gitlab that will execute the builds. These can be real machines, virtual machines or containers. By default, you have access to shared runners on gitlab.com, or even on your company Gitlab instance.
These runners are tagged so that you can also tag your builds accordingly. If you need a runner that will build a Docker image, it could be tagged
docker for example, and so would be your build step in your
Your builds can now easily be customized without ruining your own machine configuration… and even use Docker.
Why would you add a Runner?
If you are using the main Gitlab shared instance, chances are that you will have to be patient to get the results of your build. The Shared Runner concept is really cool, as it allows to share the load, but… you’re not alone waiting in that queue… And the same could be true for your company’s Gitlab instance, as it will soon become popular. So you could add your own machine to the Gitlab Runners herd, just for your project. Pretty neat if you’re tired to wait for other people builds to finish.
The problem is a new machine is not cheap. That’s way cool to have your own Gitlab Runner running in your office, but have a quick look at your pockets contents. Do you have enough cash to buy a new machine? Maybe not…
But wait… In the introduction, I was talking about ARM Runners. Why would you need to add an ARM processor machine as a Gitlab Runner?
If your code does not depend on a specific family of processors, there is no other cheaper alternative to build a new Gitlab Runner.
$15 for an OrangePi Zero machine able to run Docker and Gitlab Runner can’t be beaten.
And… if you want to develop for that kind of architecture (ARMV7, aarch64…), you will need that kind of runner.
I am trying to port software to the ARM processor, and these ARM Gitlab Runners have proven to be really useful. I can develop on my favorite IDE (on a X86 machine for example), commit, and automagically, my modified code will be compiled and tested on an ARM machine.
I have to admit all of this could also be done with X86 Runners, as QEMU is able to emulate ARM processors. And even the build of ARM Docker image can be done on X86 Gitlab Runners, thanks to the amazing work of guys at Resin.io.
But where’s the fun?
And furthermore… We all have a Raspberry Pi taking layer after layer of dust. Who has not been bored after having his first led blink?
Why not put it back to work?
Let’s go then for a cheap and fun solution.
Choose your preferred fruit
In this article, we’re not going to install Gitlab Runner on an Orange Pi, but on a Raspberry Pi (because we had one laying around), but this should work on any fruit (aka ARM Docker capable device), as Banana Pi or Orange Pi.
This version of Gitlab Runner we’ll use needs Docker, that’s why we need a Linux distribution which supports Docker.
We’re using an Hypriot distribution because of the Raspberry Pi. We could have used Raspbian, but HypriotOS is the best Docker-oriented distribution for the Raspberry Pi. From downloading the image to the first
docker command will take only five minutes.
There is also a 64bits fork (as lots of Raspberry Pi distributions are not available for 64bits, that’s a nice plus).
To me, that’s the first choice if you want to use Docker on a Raspberry Pi out of the box.
First of all, let’s download the latest Hypriot distribution.
Downloading and installing the Hypriot Distribution
Go to the Hypriot download page and choose the latest distribution.
- Current image available on 09/25/2018 is 1.9.0 : https://github.com/hypriot/image-builder-rpi/releases/download/v1.9.0/hypriotos-rpi-v1.9.0.img.zip
Next go to your Download folder and extract the downloaded zip file by right-clicking on the file and then clicking on 7-zip -> extract here…. if you use 7-zip. Whatever your unzipping tool may be, right-click and choose the right option to uncompress the file.
After 7-zip is finished with extracting you will have a file with a
It’s almost the same as for Windows, except that the tool could be Keka.
Just use 7z.
Writing the image
In the next step we will flash this file onto your SD card.
We have to use the finest piece of sofware able to write CORRECTLY and CHECK the written image (i.e. Etcher) on any platform. Current version is 1.4.4.
Too bad it does not exist for armv7.
I do insist on the use of Etcher, because lots of supposed Linux bugs are because of a badly written image, or to a faulty SDCard. Etcher will take care of these issues.
If possible, do not use any USB Dongle or gizmo to host the SDCard, prefer your laptop own SDCard reader. And for the SDCard, prefer a REAL and GENUINE SDCard.
How can you differentiate a real one from a bad copy? Well, you can’t, or not easily…
Anyway, unzip the image, and write it with Etcher to your SDCard. In the latests versions of Etcher, you don’t even need to unzip the image file beforehands.
Upon completion, close Etcher and eject the SD card before removing it from its slot. In order to eject the SD card, use the secure eject function in the menu next to your system clock. This is usually in the very bottom right corner of your screen.
Now it’s time to start your Raspberry Pi with the SD card
Boot your Raspberry Pi
- Connect the Raspberry Pi to your local network via an ethernet cable
- put the SD card into the designated slot
- plug in the power adapter
After finishing the last step your Raspberry Pi will boot and the LEDs should start blinking. The very first boot will take one to three minutes as the file system will be resized.
Find its IP on the network
After booting, you can find the Raspberry Pi at your network with a simple
ping black-pearl.local — no more searching for IP addresses required thanks to the integrated Avahi service discovery.
As you can see in the following
ifconfig command, the MAC Address of the Raspberry always starts with
B8. That could prove useful if ever this first method does not work.
So, what shall we do if the very first
ping/ssh does not work with
black-pearl? Well, as the Raspberry Pis MAC Address always start with
B8 we can use nmap and keep only the IPs whose attached MAC Address sport a
B8(yes, it’s gross).
If your network starts at
10.XX.30.XX and ends at
ip_start would be 30 and
ip_end would be 50.
This will give you a list of Raspberry IPs on which you will then be able to try to connect with
Machine name and user password
The default user “pirate” (password “hypriot”) can be changed or removed before the first boot. Everything happens in
/boot/user-data. You can add your public SSH key, disable password logins and specify a different user account before booting your Raspberry Pi. WiFi can be customized and enabled to have Docker up and running through the air without attaching a keyboard and monitor. How cool is that?
You can also change the name of the machine later on with
sudo raspi-config. The changes will have to be made in
Once it’s done, reboot and enjoy your new machine name:
If you have to work behind a corporate proxy, you will have to set a few things before being able to update your machine and run Docker.
/etc/apt/apt.conf.d/10proxy and add your proxy (create it if it doesn’t exist yet):
sudo apt-get update should prove that the configuration is working
While you’re there, update the machine with
sudo apt-get upgrade to have the freshest Docker environment available.
If you try to download a Docker image with
docker pull … it will fail because Docker doesn’t use the same proxy settings as
So you will have to create a few directories and files to let Docker know it should use your proxy:
/etc/systemd/system/docker.service.d/https-proxy.conf will contain:
http version of this file will have the same proxy settings (just remove the
Once you’re done with the modifications, you will have to tell Docker to restart to take this into account:
Then you’ll be able to check that your modifications are correct:
Check that the date on your machine is correct by issuing date in the terminal. If it’s not correct, you will have some troubles with getting a Docker image.
So, if the date/time are not right, you can set them up with:
You already know Gitlab Runner, I’m sure you are already using some shared runners with your CI on your company’s gitlab.
Most of the time, you don’t need to setup your own, but as there aren’t that many ARM gitlab runners for the time being…
Note: there are two versions available. Alpine and Ubuntu. As Alpine is the default image, when you run docker pull klud/gitlab-runner Alpine version will be downloaded.
About the image
This image is built for ARM devices, based on the official repo of the GitLab Runner. That’s a fantastic work that made my daily work really more enjoyable.
Runner container setup
You need to mount a volume into the gitlab-runner container in order to share the configuration. This could be done this way:
As we want to use the Docker executor, it is necessary to mount the Docker socket this way. Don’t forget to create
/etc/gitlab-runner directory ahead of time:
Once the container is up and running, you can then register the runner on your GitLab server.
Go to your project on your Gitlab instance, click on Settings, then on CI/CD, and click on Expand next to Runner settings.
Scroll down to Setup a specific Runner manually, and note the information regarding the URL and the token.
- Specify the following URL during the Runner setup: https://gitlab.com/.
Use the following registration token during setup:
So once you have the information you need (URL and token), you can then do this:
Let’s check if this new runner can now be seen. Refresh your CI/CI settings, expand Runner settings, and go down. You should now be able to see your brand new Gitlab-ci runner proudly sporting its ARM tag!
You could also do it this way:
So now you have your own ARM runner, ready to work.
If you’re going to build images on this runner you can use the standard multi-arch Docker image, because it now has the armv6 binaries in it now (it used not to be the case until 18.0.2). Dockerfiles and info about Docker in Docker images for ARM for earlier versions are here.
In case you’re using docker in docker in the runner, you may experience some issues
So in order to address this issue you need to look within the config folder you mounted in the runner container. There is a config file which is
/etc/gitlab-runner/config.toml. You need to add two lines (regarding the
volumes)and then restart the runner with
docker restart arm-runner.
If you can’t find the file, it is maybe in
~/.runner/config.toml/; copy it in
/etc/gitlab-runner after editing it and restart docker.
So now you can enjoy your first ARM Gitlab build!
Next step, make your Runner available for any project!