GitLab CI Runner können entweder auf eigener Hardware, oder kostengünstig und automatisch skalierend auf Googles Compute Engine laufen gelassen werden. Letzteres ist mit wenig Aufwand und in den ersten 12 Monaten sogar kostenfrei möglich.

Das Prinzip ist das folgende: ein einfacher GitLab CI Runner läuft neben der eigentlichen GitLab-Installation auf der gleichen Hardware (in diesem Fall als Docker-Container). Wenn nun ein neuer CI-Job gestartet werden soll, spawnt der Runner eine VM in der Google Compute Engine, installiert dort die nötige Software und führt das CI-Skript durch. Anschließend wird die angelegte VM wieder beendet und gelöscht.
Dadurch können die Kosten gering gehalten werden, während gleichzeitig praktisch beliebig viel Rechenleistung zur Verfügung steht.

1. Google Cloud Platform

Öffnen Sie zunächst die Google Cloud Platform unter diesem Link und melden Sie sich mit Ihrem Google-Konto an.
Erstellen Sie anschließend ein neues Projekt (z.B. “GitLab CI”; nachfolgend wird gitlab-ci-123456 als Projekt-ID angenommen) und Sie gelangen automatisch auf das Dashboard.
Wechseln Sie nun über das linke Menü auf den Abschnitt “Abrechnung” und legen Sie ein neues Rechnungskonto an, falls noch keines exisitert. Anderfalls weisen Sie diesem Projekt ein bestehendes Rechnungskonto zu.
Sollte dies Ihr erstes Projekt in der Google Cloud Platform sein, starten Sie damit gleichzeitig das kostenfreie Probejahr. Dieses beinhaltet 300$ Credits, die Sie in den nächsten 365 Tagen verbrauchen können. Erst im Anschluss erhalten Sie tatsächliche Abbuchungen auf Ihrer Kreditkarte.
Es empfiehlt sich, eine Budget-Benachrichtigung einzurichten, damit Sie nicht von zu hohen Kosten überrascht werden.

1.1 Kostenübersicht

Eine grobe Kalkulation der Kosten kann anhand der Preisübersicht und des Preisrechners ermittelt werden.
Ausgehend von ~30 Stunden Laufzeit im Monat einer n1-standard-2-VM (präemptiv) in Frankfurt belaufen sich die Kosten monatlich auf rund 0,75$.
Präemptiv bedeutet in diesem Fall, dass die VM maximal 24 Stunden lang laufen wird und zudem jederzeit von Google beendet werden kann. Im Falle von CI-Arbeiten kann dieser Kostenvorteil gegenüber der möglichen Nachteile in Kauf genommen werden. Weitere Details zu diesem Modell finden sich hier.

1.2 Zugangsdaten erhalten

Damit der GitLab CI Runner auf die Google Cloud Platform zugreifen kann, muss dieser über entsprechende Zugangsdaten verfügen. Diese können Sie lokal mittels des Google Cloud SDKs erhalten. Folgen Sie dazu (unter Linux) der Anleitung unter https://cloud.google.com/sdk/docs/quickstart-linux.

Anschließend erzeugen Sie sich die Zugangsdaten mit dem Befehl gcloud auth application-default login.
Diese werden standardmäßig unter /home/user/.config/gcloud/application_default_credentials.json abgelegt und sollten nach /srv/gitlab-runner/config/client_secret.json verschoben werden. Falls Sie hier ein anderes Verzeichnis wählen, müssen Sie dieses auch im nächsten Schritt anpassen.

2. GitLab CI Runner

Um einen GitLab CI Runner mittels Docker (in diesem Fall durch docker-compose) zu starten, werden die folgenden Zeilen in einer bestehenden docker-compose.yml-Datei benötigt:

gitlab-runner:
  image: "gitlab/gitlab-runner:alpine-v10.6.0"
  volumes:
    - "/srv/gitlab-runner/config:/etc/gitlab-runner"
    - "/srv/gitlab-runner/docker-machine:/root/.docker"
  environment:
    - "GOOGLE_APPLICATION_CREDENTIALS=/etc/gitlab-runner/client_secret.json"
  depends_on:
    - "gitlab"
  restart: always

Die Verzeichnisse, die als Volume angegeben sind, enthalten später die Konfiguration des Runners und die der von ihm verwalteten VMs. Zudem wird auf die zuvor angelegten Zugangsdaten für die Google Cloud Platform verwiesen.

2.1 Runner einrichten

Folgen Sie der Anleitung der GitLab-Dokumentation, um den GitLab CI Runner erstmalig einzurichten. Verwenden Sie hierbei als executor die Einstellung docker+machine.

Anschließend müssen Sie erstmalig eine VM aus dem Runner heraus erzeugen, um möglich Fehler beim ersten Start eines Jobs zu verhindern. Dies geschieht durch Docker Machine. Mit diesem Tool, welches das Anlegen und Verwalten von Docker-Hosts ermöglicht, werden auch später vom CI Runner die VMs gestartet.

Shell innerhalb des Runners öffnen:

root@gitlab:~# docker exec -it gitlab-runner /bin/sh

VM anlegen und starten:

/ # docker-machine create --driver google --google-project gitlab-ci-123456 test
Running pre-create checks...
(test) Check that the project exists
(test) Check if the instance already exists
Creating machine...
(test) Generating SSH Key
(test) Creating host...
(test) Opening firewall ports
(test) Creating instance
(test) Waiting for Instance
(test) Uploading SSH Key
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with ubuntu(systemd)...
Installing Docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env test

Liste der laufenden VMs anzeigen:

/ # docker-machine ls
NAME   ACTIVE   DRIVER   STATE     URL                        SWARM   DOCKER        ERRORS
test   -        google   Running   tcp://35.184.67.125:2376           v18.03.0-ce

Test-VM löschen:

/ # docker-machine rm test
About to remove test
WARNING: This action will delete both local reference and remote instance.
Are you sure? (y/n): Y
(test) Deleting instance.
(test) Waiting for instance to delete.
Successfully removed test

Shell innerhalb des Runners beenden:

/ # exit

2.2 Runner Konfiguration

Zuletzt muss der GitLab CI Runner noch eine angepasste Konfiguration erhalten, damit die VMs passend erzeugt werden können. Öffnen Sie dazu die Konfigurationsdatei unter /srv/gitlab-runner/config/config.toml und fügen Sie die entsprechenden Stellen im Abschnitt [runners.machine] (mit Ihren Anpassungen versehen) ein:

concurrent = 5
check_interval = 0

[[runners]]
  ...
  executor = "docker+machine"
  limit = 5
  [runners.docker]
    ...
  [runners.cache]
  [runners.machine]
    IdleCount = 0
    IdleTime = 30
    MachineDriver = "google"
    MachineName = "%s"
    MachineOptions = [
      "google-project=gitlab-ci-123456",
      "google-machine-type=n1-standard-2",
      "google-machine-image=coreos-cloud/global/images/family/coreos-stable",
      "google-preemptible=true",
      "google-zone=europe-west3-a"
    ]

Die wichtigsten Stellen, die Sie eventuell ändern möchten, lauten:

  • concurrent = 5: erlaubt maximal 5 gleichzeitig laufende CI Jobs auf diesem Runner
  • limit = 5: erlaubt maximal 5 gleichzeitig laufende VMs
  • IdleCount = 0: keine der VMs soll ohne Arbeit laufen; ermöglicht einen schnelleren Start der CI-Jobs
  • IdleTime = 30: nach 30 Sekunden ohne Arbeit wird die VM beendet
  • google-machine-type=n1-standard-2: legt die verwendete Art der VM fest; eine Liste ist hier zu finden
  • google-zone=europe-west3-a: legt das verwendete Rechenzentrum fest; eine Liste ist hier zu finden

Eine genauere Anleitung zur Konfiguration des GitLab CI Runners finden Sie hier, weitere Konfigurationsmöglichkeiten als MachineOptions sind hier verfügbar.

Starten Sie nun den GitLab CI Runner neu, damit die geänderte Konfiguration übernommen werden kann.

3. Abschluss

Starten Sie nun einen CI-Job durch das GitLab Web-Frontend. Dadurch wird der CI Runner eine VM starten, den Job ausführen und die VM wieder beenden. Während der erste Schritt noch bis zu 60 Sekunden dauern kann, werden die Jobs selbst sehr schnell durchgeführt. Gerade bei aufeinanderfolgenden Jobs ist dies deutlich spürbar.
Im Falle von fehlender Leistung sind ein Wechsel auf stärkere VMs oder ein anderes Rechenzentrum (s.o.) innerhalb der Google Cloud Engine einen Versuch wert.