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, and virtualbox. For this example, we’ll use docker.
  • Default Docker image: If you chose docker as the executor, you’ll be asked for a default image. alpine:latest is 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.

Want structured learning?

Take the full Gitlab-ci course →