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.
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.
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
.
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.
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.