Dependency between job services in Gitlab CI

Inspired from zanechua.com/blog: Dependency between Services in GitLab Pipelines


Service in Gitlab CI is a way to add sidecar container inside a Gitlab Runner job. This is helpful when you need to have a daemon running in parallel of your job tasks. For exemple you could need a Redis database running in parallel of a script.

I needed to do some testing that required using Apache's Guacamole. Unfortunately the tool is broken down into several services that have to be deployed in order to use it. In fact the tool is not necessarily designed to be launched temporarily.

Apache Guacamole is a free and open-source HTML5 web application that enables users to access their remote servers, desktops, and devices through a web browser. It provides a simple and intuitive interface for remotely connecting to and controlling various types of systems, including Linux and Windows servers, virtual machines, and cloud environments.

Guacamole service architecture (https://guacamole.apache.org/doc/gug/guacamole-architecture.html)

So, Guacamole need all the three bricks in green. The frontend application Guacamole client with their database (here PostgreSQL). And the backend application Guacamole server. But fortunately there are docker images for each of the bricks. No need to create your own.

When starting the Guacamole frontend service it need to connect to his database. So, the service postgre need to be started before guacamole. We can't do that natively with Gitlab CI. Because by Gitlab CI will launch all the three service at the same time. And it will wait that service port respond before start the script job. Also by default, if you are using the Docker executor, service can't connect to other service. This is because the hostname of the service is not resolvable now.

If you using the Kubernetes executor, you will not have the network issue. Because in Kubernetes all services, gitlab runner helper and build container run on the same pod! The hostname is already manage by Kubernetes via HostAliases.

To start correctly the three service we need to customise the entrypoint commands from the container:

  1. Start Guacd
  2. Inside the Guacamole container, generate the init db file, and then, inside the postgre container, copy the file inside the init directory.
  3. Start Postgre
  4. Wait Postgre finish to boot
  5. Start Guacamole

Solution: using feature flags

Add feature flag to enable creation of a network per build

Feature flags are toggles that allow you to enable or disable specific features. Here we enable a feature for Docker which create a network for each job we start. When creating a network, docker will create a localhost DNS resolver. Docker will resolve hostname of each docker container. And so we can communicate with other service.

Here the .gitlab-ci.yml:

We use the shared CI_PROJECT_DIR to share the database initialization file. We must be sure that the CI_PROJECT_DIR directory is correctly mounted before using it. We wait for the git repository clone/fetch to finish.

Here how the resolv.conf file and hosts file look like:


In Kubernetes, the feature flags is ignore, and the resolv.conf file and hosts file look like: