Building a GitLab CI runner Virtual Machine for iOS

Gilles Grousset
Hack Like a Pirate
Published in
3 min readDec 4, 2019

After years sticking with Jenkins as my CI/CD tool, I decided to switch to GitLab CI ! However, whatever CI tool you choose, integrating Apple technology to your CI workflow is always complicated….

Setting up a CI with iOS support

When it comes to building iOS (or macOS) software with a CI: it always seems easy at the beginning : a simple script calling xcodebuild command line is all you need to build and test your application. Like this :

However, when you start thinking about enhancing your basic pipeline, with code signing, static analysis, publication… xcodebuild alone will let you down.

Fortunately, thanks to the open source community, you will find almost all the tools you need to fill the gap with fastlane, xcpretty, swiftlint, slather

But then, you will stumble on another problem soon: how to maintain and update all those tools on your runner over time ? Especially if you have several runners and need to perform maintenance on all of them, one by one.

You will probably end up spending more time maintaining your CI than working on your projects…

Unfortunately macOS cannot be containerized…

A convenient way to manage CI runners is using Docker containers: there are easy to build, deploy, duplicate and upgrade.

The problem: macOS cannot be containerized…

However, my goal was to get as close as possible to the container philosophy to get runners as reliable and fast to deploy as I could.

No surprise here: I decided to use virtualization with VirtualBox, the popular desktop virtualization tool from Oracle.

But still I was missing the repeatable and automated way to install all the tools required for a runner.

I finally found what I needed with Vagrant. Vagrant is a tool used to create and provision virtual machines (that is: automating software installation on it) using a script (named Vagrantfile).

To start the virtual machine creation, just type (from the Vagrantfile directory):

vagrant up

Then you just have to wait… Quite a long time actually, because a macOS virtual machine is huge, and a lot of software (starting with Xcode) needs to be installed on it. But let’s stay positive: it’s automatic (once your script is fulled debugged !).

A Vagrantfile for your iOS GitLab CI runner

After explaining how easy and clean it is to use Vagrant to create a GitLab CI runner, I could not go away without sharing my own Vagrantfile, so that you can start creating your own runner in the next few minutes.

My script is here, with all the required instructions: https://github.com/zippy1978/xcode-gitlab-runner

In a few words, here is what you need to do (Homebrew is needed) :

  1. Install VirtualBox
brew cask install virtualbox
brew cask install virtualbox-extension-pack

2. Install Vagrant and its reload plugin

brew cask install vagrant
vagrant plugin install vagrant-reload

3. Clone the Github repository

git clone https://github.com/zippy1978/xcode-gitlab-runner.git gitlab-runner
cd gitlab-runner

3. Launch the Vagrant script with parameters

Note: you need to download Xcode .xip archive from Apple to somewhere on your machine.

XCODE_XIP_FILE="/path-to-Xcode.xip" \
GITLAB_URL="https://gitlab.com/" \
GITLAB_REGISTRATION_TOKEN="your-token" \
GITLAB_RUNNER_NAME="macMachine" \
GITLAB_RUNNER_TAGS="macos,xcode11" \
vagrant up

4. Configure your iOS project for GitLab CI

…By creating a .gitlab-ci.yml at the root of your repository.

Here is an example performing build, test and code analysis:

To configure the SonarQube analysis, you need to add a sonar-project.properties file at the root of the repository, as explained here

start-simulator.sh pre-launches the simulator for tests. Be careful to use the same simulator as the one defined in you sonar-project.properties.

run-sonar-swift.sh builds, tests, analyses and publishes results to a SonarQube server. SONAR_URL and SONAR_TOKEN are defined as GitLab CI/CD variables.

And now ?

Your are now ready to rule the iOS CI world :)

You can deploy as many runner as you want automatically.

You can also run one on your development machine !

I hope this will help you.

--

--