CI pipelines often start simple – a single job building a binary and pushing it to an artifact repository or to some production environment. Ever-changing software requirements introduce more complexities, such as adding more jobs to perform certain checks and reviewing the output before the final build job is executed.
These complexities increase exponentially when builds are expected to target varying systems with different system architectures or resource needs. This is evident in projects like operating systems, mobile apps, or software distributions that support multiple deployment platforms. To account for the varying needs of builds in these types of environments, having multiple runners that match needed requirements is key, and that's where GitLab Runner tags come in. If you are coming from Atlassian's Bamboo, they are called "agent capabilities."
Runner tags allow organizing runners by a tag that signifies a specific use case they support; these tags are then used to make sure CI jobs run on a runner that meets their requirements. A job can require GPU resources that are only available on a handful of runners; tagging the job to the tags of the runner allows it to be scheduled on the runner with GPUs.
Agent capabilities on Bamboo are used to achieve the same functionality by specifying binaries or custom identifiers that must be matched or available for a job to run on a Bamboo agent. In this blog post, we will be looking at how to translate Bamboo agent capabilities to GitLab Runner tags.
Bamboo has varying agent capabilities:
- Executable capability specifies executables that are available on an agent.
- JDK capability specifies that the Java Development Kit is installed and available for builds.
- Version Control capability lets Bamboo know the version control systems set up on an agent and where the client application is located.
- Docker capability is used to define the agents where Docker is installed for Docker tasks
- Custom capability uses key/value identifiers to identify a unique functionality an agent provides.
GitLab makes the process easier by using tags to identify Runners, some of which can be assigned multiple tags to denote the varying functionalities they can provide to jobs. Let's look at how you can use Runner tags in GitLab.
Adding tags to GitLab Runner
When registering a runner after installation, one of the steps requires providing a list of comma-separated tags that can be used. If none are provided at this stage, you can always edit the /etc/gitlab-runner/config.toml
file and add any missing tags.
You can also manage the tags of a runner in GitLab by accessing the runner's edit page and updating the Tags
field. You have the option for the runner to be exclusive to jobs that are tagged appropriately, or when there are no tagged jobs to run, it should run untagged jobs, too. Checking Run untagged jobs
enables this behavior.
Using tags in .gitlab-ci.yaml file
To run a job on a specific runner, add the relevant tags to the job's configuration, as shown below:
build_ios:
image: macos-13-xcode-14
stage: build
script:
- bundle check --path vendor/bundle || bundle install --path vendor/bundle --jobs $(nproc)
- bundle exec fastlane build
tags:
- saas-macos-medium-m1
In the example above, the job builds an iOS application only on runners operating on a macOS device with an M1 chip and tagged saas-macos-medium-m1
.
Using multiple tags
A job can specify multiple tags to target a diverse range of runners, especially in organizations that run several fleets of runners as part of their software development lifecycle. A job will only run if a runner is found that has all the tags the job has been tagged with. For example, if a job has [linux, android, fastlane]
tags, a runner with [ android, fastlane]
or [ linux, android]
will not execute the job because the full set of tags does not match the runner.
Dynamic jobs with tags and variables
You can use variables to determine the values of tags and thus dynamically influence which runners pick up the jobs. For example:
variables:
KUBERNETES_RUNNER: kubernetes
job:
tags:
- docker
- $KUBERNETES_RUNNER
script:
- echo "Hello runner selector feature"
In this example, only runners tagged with kubernetes
will execute the job. You can take this further in more complex pipelines with parallel: matrix
. Here is an example:
deploystacks:
stage: deploy
parallel:
matrix:
- PROVIDER: aws
STACK: [monitoring, app1]
- PROVIDER: gcp
STACK: [data]
tags:
- ${PROVIDER}-${STACK}
environment: $PROVIDER/$STACK
This example ends up with three parallel jobs with three different tags for each: aws-monitoring
, aws-app1
and gcp-data
, thus targeting possibly three different runners.
Using tags in your GitLab CI configuration gives you the flexibility to determine where and how your applications are built, to use resources more efficiently as scarce resources can be limited to certain runners, and to determine how jobs are allocated to those runners.
Learn more about how to make the move from Atlassian to GitLab.