Registering a GitLab CI runner is more than just an installation; it’s about making a specific machine available to execute your Continuous Integration jobs, and the most surprising thing about it is how flexible and granular that availability can be.
Let’s see a runner in action. Imagine we have a simple .gitlab-ci.yml file:
stages:
- build
build_job:
stage: build
script:
- echo "Hello from my runner!"
- hostname
- pwd
Now, we need a runner to pick this up. We’ll set up a shared runner on a dedicated Linux VM.
First, install the GitLab Runner binary on your machine. On Ubuntu, this is typically:
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get update
sudo apt-get install gitlab-runner
Once installed, you need to register it with your GitLab instance. Navigate to your GitLab project, then go to Settings > CI/CD. Expand the Runners section. You’ll see a URL and a registration token.
Now, on the machine where you installed the runner, execute the registration command:
sudo gitlab-runner register
The command will prompt you for several pieces of information:
- GitLab instance URL: Paste the URL provided in your GitLab project’s CI/CD settings. For example,
https://gitlab.example.com/. - Registration token: Paste the token from the same settings page.
- Description for this runner: Give it a descriptive name, like
my-docker-runner-on-vm. This will appear in your GitLab UI. - Tags for this runner: This is crucial for controlling which jobs this runner picks up. You can enter comma-separated tags like
docker,linux,build. If you leave this blank, it will be a shared runner for all jobs in your project (or instance, depending on runner scope). - Executor: This defines how the runner executes jobs. Common options include
shell,docker,kubernetes, andvirtualbox. For this example, we’ll usedocker. - Default Docker image: If you chose
dockeras the executor, you’ll be asked for a default image.alpine:latestis a good, lightweight choice.
After registration, the runner will be listed in your GitLab project’s CI/CD settings. You can then configure your .gitlab-ci.yml to use specific tags:
stages:
- build
build_job:
stage: build
script:
- echo "Hello from my runner!"
- hostname
- pwd
tags:
- docker # This job will only run on runners with the 'docker' tag
When a pipeline runs, GitLab’s CI dispatcher looks for available runners that match the tags specified for each job. If our build_job has the tag docker, only runners with that tag will be considered.
The runner service needs to be started and enabled to run automatically on boot:
sudo gitlab-runner start
sudo gitlab-runner enable
You can check the status of your runner with:
sudo gitlab-runner status
Internally, the gitlab-runner process polls the GitLab API for pending jobs. When it finds a job that matches its configuration (tags, project scope), it downloads the job’s configuration and scripts. If using the docker executor, it spins up a new Docker container based on the specified image (or the job’s image directive), mounts the project’s code into it, and executes the script commands within that isolated environment. Once the job completes, the container is usually removed, and the runner reports the status back to GitLab.
The most powerful aspect of runners is their scope: you can register them as instance runners (available to all projects on your GitLab instance), group runners (available to all projects within a specific group), or project runners (available only to a single project). This allows for fine-grained control over who can use which runners, ensuring that sensitive jobs only run on trusted infrastructure.
To see the runner in action, push a change to your repository. You’ll see the pipeline start, and your build_job should be picked up by the runner you just configured. The output in the job log will show the echo command, the hostname of your runner machine, and the current directory within the runner’s execution environment.
The next concept to explore is how to manage runner configurations, particularly the config.toml file, and how to define more complex executor setups for different job requirements.