Pular para o conteúdo principal

GitLab Runners

Entendemos um pouco dos conceitos iniciais, agora vamos trabalhar com os runners.

Shared Runners

São runners que são compartilhados entre todos os projetos dentro de uma instância do GitLab. Eles são fornecidos e gerenciados diretamente pelo GitLab. Quando você cria uma pipeline em um repositório, o GitLab automaticamente tenta alocar um Shared Runner para executar o trabalho, se o repositório não tiver runners específicos configurados.

  • O GitLab cuida de atualizações, manutenção e escalabilidade dos runners.
  • GitLab pode escalar automaticamente para atender à demanda, alocando recursos conforme necessário.
  • Gratuito: O uso de Shared Runners é gratuito para qualquer instância pública do GitLab (GitLab.com).

Onde está a pegadinha?

  • Shared Runners são totalmente gratuitos para repositórios públicos, sem qualquer limitação de minutos.
  • Para repositórios privados, você ainda tem acesso aos Shared Runners, mas há um limite de minutos de execução por mês. No plano gratuito, o GitLab oferece um número fixo de minutos (como por exemplo, 400 minutos por mês). Após atingir esse limite, você precisaria aguardar o próximo ciclo mensal ou comprar mais minutos. 400 minutos é por conta e não por respositório.
  • Se você estiver em um plano pago (Premium, Ultimate), o limite de minutos de execução para Shared Runners é muito maior (com alguns planos oferecendo até 50.000 minutos por mês ou mais).

O Gitlab sempre desconta 1 minuto mesmo se sua pipeline rodar por 10 segundos. Se rodar por 1 minutos e 1 segundo desconta 2 minutos.

Para uma empresa que tem bastante entrega, 400 minutos não dá nem pro começo. Se sua empresa hospeda códigos no Gitlab, não paga um plano e não quer ter problema com o runner, então precisamos disponibilizar nosso próprios runners.

O Runner é um agente (serviço) que fica escutando o GitLab e aguardando ordens. Quando uma pipeline é disparada (por push, merge, manual, etc), o GitLab manda a tarefa pro Runner executar.

O que o Runner faz exatamente?

  • Recebe a instrução do GitLab CI/CD (com base no .gitlab-ci.yml).
  • Clona o repositório.
  • Lê a pipeline e executa os jobs, um a um.
  • Para cada job, ele precisa de um ambiente de execução.

Como instalar um Runner?

Se você tem um projeto em uma organização sem estar dentro de um grupo só conseguiria instalar o runner neste projeto.

O que eu quero dizer com isso? https://gitlab.com/davidpuziol/devsecops é um projeto no namespace pessoal davidpuziol, ou seja, não está dentro de um grupo.

O que daria para fazer é registrar um runner em um projeto, marcá-lo como locked: false e run: untagged: true e em cada um dos projetos que você quisesse usar iria em projeto > Settings > CI/CD > Runners e ativa esse runner manualmente (vai aparecer na lista de "available runners").

Não é a melhor coisa a se fazer. A melhor seria criar um grupo, configurar o gitlab-runner para esse grupo e liberar que o runner seja usado por todos os projetos dentro desse grupo.

Como davidpuziol é o meu namespace pessoal, eu vou criar um group chamado puziol.

alt text

Se fossemos pensar em nível de empresa, agora criaríamos outros subgroups dentro deste grupo, não mais por causa do runner, mas por questões de permissões, variáveis, etc.

Para instalar um runner para todo esse grupo vamos em Build > Runners e criar um novo runner para esse grupo.

alt text

Podemos referenciar o runner mais tarde pelas tags. É bom colocar.

alt text

A primeira coisa que vamos fazer é instalar o gitlab-runner que na verdade é um agente, o método com que ele irá executar alguma coisa vem depois. Se fossemos instalar isso dentro da nossa própria máquina de desenvolvimento o runner só estaria disponível quando a máquina tivesse ligada. Você desenvolvendo algo no seu repositório, tudo bem, mas e se outra pessoa quiser usar o runner e sua máquina não tiver online?

Vamos fazer isso para que entenda.

Como estou no Mac no momento eu vou seguir o fluxo do Mac.

# Mude para o o seu sistema operacional
sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-arm64

sudo chmod +x /usr/local/bin/gitlab-runner

cd ~
gitlab-runner install
gitlab-runner start

O que temos até agora é só o gitlab-runner, mas precisamos registrar ele no GitLab.

alt text

Ao executar teremos algumas perguntas

❯ gitlab-runner register  --url https://gitlab.com  --token glrt-xxxxxxxxxxxxxxxxxxxxx
Runtime platform arch=arm64 os=darwin pid=84345 revision=0f67ff19 version=17.11.0
WARNING: Running in user-mode.
WARNING: Use sudo for system-mode:
WARNING: $ sudo gitlab-runner...

# Se estiver usando o gitlab.com e não for auto hospedado então pode apertar enter
Enter the GitLab instance URL (for example, https://gitlab.com/):
[https://gitlab.com]:
Verifying runner... is valid runner=yG54yKH4o
Enter a name for the runner. This is stored only in the local config.toml file:
[MacBookPro.localdomain]: mac-general # Ponha um nome para esse runner que seja facil identificar de onde veio

#Nesse momento que avisaremos qual será o executor. Onde será executado o código. Como eu não quero um ambiente isolado vou colocar docker. Observe que poderia ser até um virtual box.

Enter an executor: ssh, parallels, docker-windows, docker+machine, kubernetes, instance, custom, shell, docker-autoscaler, virtualbox, docker:
docker

# Qual será a imagem padrão caso não seja especificada no .gitlab-ci.yml?
Enter the default Docker image (for example, ruby:2.7):
debian:bullseye-slim # Essa é a minha escolhida e já vamos falar sobre ela.

Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

Se não definirmos uma imagem no arquivo de configuração de pipeline então vamos usar esta, mas por que esta?

Existem duas imagens que eu gosto muito de manter como padrão. Antigamente eu gostava de usar alpine, mas hoje tenho pensado mais em trabalhar com algo de base debian que fica mais fácil para os desenvolvedores encontrar documentação na internet.

Por que usar debian:bullseye-slim?

  • Mais leve que o Ubuntu: O slim remove tudo que é desnecessário (como docs, dev tools, etc.) ficando mais rápida para pra baixar e subir na pipeline.
  • Compatível com a maioria dos pacotes: Tudo que funciona no Debian padrão ou no Ubuntu provavelmente vai funcionar aqui.
  • Menos dor de cabeça que o alpine, que quebra builds por usar musl em vez de glibc.
  • Mais fácil de debugar: Vem com utilitários básicos que você não precisa instalar na unha, tipo bash, coreutils, etc.
  • Base confiável e segura: O Debian tem manutenção de segurança forte e a versão bullseye é uma das estáveis mais recentes (ainda com updates).

Então voltando ao nosso grupo o que temos?

alt text

Importante... Se definimos que o docker será o nosso executor, é necessário que o docker esteja instalado no host.

Isso foi mostrado só para que você entenda como gitlab-runner funciona mas não é assim que trabalhamos em uma empresa. O melhor modo de disponibilizar o runners é através de um cluster kubernetes, principalmente se a quantidade de pipelines é muito alta.

Poderíamos instalar via docker também. Eu faço isso para projetos pessoais rodando um docker em um homelab que eu tenho aqui.

mkdir -p $HOME/gitlab-runner/config
docker run -d --name gitlab-runner --restart always \
-v $HOME/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest

O que o container salvar em /etc/gitlab-runner será exposto em ~/gitlab-runner/config. Temos o gitlab-runner rodando, mas precisamos configurar, então vamos rodar o register dentro do container com o comando exec. e seguir o mesmo fluxo.

docker exec -it gitlab-runner gitlab-runner register
Runtime platform arch=arm64 os=linux pid=13 revision=0f67ff19 version=17.11.0
Running in system-mode.
Enter the GitLab instance URL (for example, https://gitlab.com/):
https://gitlab.com/
Enter the registration token:
glrt-xxxxxxxxxxxxxxxxxxxxxx # cole o token aqui que irá aparecer na página
Verifying runner... is valid runner=N9u4maijw
Enter a name for the runner. This is stored only in the local config.toml file:
[67245dbfb3fa]: docker-mac-general
Enter an executor: custom, parallels, docker, docker-windows, instance, shell, ssh, virtualbox, docker+machine, kubernetes, docker-autoscaler:
docker
Enter the default Docker image (for example, ruby:2.7):
debian:bullseye-slim
Runner registered successfully. Feel free to start it, but if its running already the config should be automatically reloaded!

Configuration (with the authentication token) was saved in "/etc/gitlab-runner/config.toml"

# O arquivo que está em /etc/gitlab-runner/config.toml é este.

cat ~/gitlab-runner/config/config.toml
concurrent = 1
check_interval = 0
shutdown_timeout = 0

[session_server]
session_timeout = 1800

[[runners]]
name = "docker-mac-general"
url = "https://gitlab.com/"
id = 47095881
token = "glrt-xxxxxxxxxxxxxxxxxxxxxx"
token_obtained_at = 2025-04-21T18:28:10Z
token_expires_at = 0001-01-01T00:00:00Z
executor = "docker"
[runners.cache]
MaxUploadedArchiveSize = 0
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
tls_verify = false
image = "debian:bullseye-slim"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0
network_mtu = 0

Quando você define privileged: true no runner Docker executor, você está basicamente dizendo:

“Esse container pode fazer quase tudo que o host pode.” Ou seja:

  • Ele pode montar volumes do host.
  • Pode acessar dispositivos.
  • Pode controlar a rede.
  • E o mais importante: pode escapar do isolamento do container, se mal utilizado.

Porém veremos mais pra frente que algumas vezes isso é necessário, principalmente no uso de services.

alt text

Se quiser deletar é só ir no X e deletar. Aqueles que você não quiser. Isso irá deletar este runner do repositório, mas é bom remover também o que fizemos.

Para remover o que criamos via docker.

docker rm gitlab-runner --force

docker rmi gitlab-runner:latest
Untagged: docker.io/gitlab/gitlab-runner:latest
Deleted: b717673dd24a18fcc29ea4ca8eee0f3fdfe1563b0393ecd16d11755c5542f01b

rm -rf ~/gitlab-runner/config/config.toml

Para remover o gitlab-runner no host

gitlab-runner uninstall
rm -rf /usr/local/bin/gitlab-runner

Se fossemos instalar o gitlab-runner em um cluster kubernetes poderíamos utilizar o seguinte.

helm repo add gitlab https://charts.gitlab.io
helm repo update
helm show values gitlab/gitlab-runner > values.yaml

Altere os seguintes campos do values.yaml. Para ajustes mais finos é bom estudar mais a fundo sobre isso.

gitlabUrl: https://gitlab.com/
concurrent: 10 # Quantos pods serão executados ao mesmo tempo. Depende do tamanho da empresa e de quanto você tem de recurso no seu cluster.
rbac:
create: true
rules:
# - apiGroups: [""]
# resources: ["*"]
# verbs: ["*"]
# Analise as rules que você precisa. Descomentar o que esta acima daria total poder a este runner.
- resources: ["events"]
verbs: ["list", "watch"]
- resources: ["namespaces"]
verbs: ["create", "delete"]
- resources: ["pods"]
verbs: ["create","delete","get"]
- apiGroups: [""]
resources: ["pods/attach","pods/exec"]
verbs: ["get","create","patch","delete"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list"]
- resources: ["secrets"]
verbs: ["create","delete","get","update"]
- resources: ["serviceaccounts"]
verbs: ["get"]
- resources: ["services"]
verbs: ["create","get"]
serviceAccount:
create: true
name: "gitlab-runner-sa"
runners:
# Aqui definimos a imagem padrão.
config: |
[[runners]]
[runners.kubernetes]
namespace = "{{.Release.Namespace}}"
image = "debian:bullseye-slim"
tags = "general-debian"
secret: gitlab-runner-token

A secret abaixo estaria definido o que se espera de valores dentro desta secret. O valor runner-registration-token precisa existir mesmo que não definido.

Crie o arquivo secret.yaml com o seguinte conteúdo.

apiVersion: v1
kind: Secret
metadata:
name: gitlab-runner-token
namespace: gitlab
type: Opaque
stringData:
runner-token: "glrt-xxxxxxxxxxxx" # Altere para o seu token
runner-registration-token: ""
kubectl create ns gitlab
kubectl apply -f secret.yaml
helm upgrade --namespace gitlab -f values.yaml gitlab-runner gitlab/gitlab-runner

Só um pod existirá no seu cluster. Esse é o pod que recebe as chamadas não o que executa. Toda vez que algo for executado um novo pod acontecerá será criado no futuro, por isso temos o concurrent: 10 para dizer que podemos ter até 10 pods ao mesmo tempo executando jobs.

Hosted Gilab Runner

Em alguns casos, seu projeto precisa rodar em uma máquina com uma arquitetura específica — algo que pode não estar disponível na sua infraestrutura atual. Para isso, o GitLab oferece Hosted Runners, que permitem executar jobs em ambientes gerenciados por eles, com diferentes sistemas operacionais e configurações.

Você pode usar tags específicas para escolher o tipo de runner necessário, como máquinas com GPU, arquitetura ARM, macOS, ou até mesmo Windows (em planos pagos).

Confira abaixo algumas opções disponíveis:

Runners Linux

Runners com GPU

Runners macOS

⚠️ Se nenhuma tag (veremos mais adiante) for especificada, o GitLab usará por padrão uma máquina Linux x86-64 Small. Dependendo do tipo de build ou workload, isso pode impactar bastante no tempo de execução dos seus jobs.

Um exemplo clássico é o deploy de apps iOS na App Store, que exige um ambiente macOS. Se toda sua infra for baseada em Linux, os hosted runners do GitLab podem resolver isso de forma simples e integrada.

Geralmente as tags aparecem da seguinte forma:

  • saas-linux-small-amd64
  • saas-linux-medium-arm64
  • saas-linux-medium-amd64-gpu-standard
  • saas-macos-medium-m1
  • saas-macos-large-m2pro
  • macos-14-xcode-15
  • macos-15-xcode-16
  • saas-windows-medium-amd64

Apesar de eu não usar, é bom sabe que existe caso tenha necessidade.