GitLab Runner self-hosted: od instalacji do produkcyjnego pipeline
Opublikowano: 9 kwietnia 2026 · Kategoria: DevOps
GitLab Runner to agent CI/CD, który wykonuje joby zdefiniowane w pliku .gitlab-ci.yml. Możesz korzystać z runnerów SaaS udostępnianych przez GitLab.com (2000 minut/miesiąc za
darmo) albo postawić własnego runnera na VPS — co jest tańsze przy intensywnym CI i daje
pełną kontrolę nad środowiskiem. W tym artykule pokażemy pełny proces: instalację, wybór
executora, rejestrację, stages, artifacts i cache.
Instalacja GitLab Runner na Ubuntu
GitLab Runner jest dostępny jako pakiet .deb dla Ubuntu/Debian. Oficjalne repozytorium GitLab ma zawsze najnowszą stabilną wersję, więc lepiej używać go niż Snap czy apt z default repozytoriów.
# Dodaj oficjalne repozytorium GitLab
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
# Zainstaluj runner
sudo apt-get install gitlab-runner
# Uruchom jako serwis
sudo systemctl enable gitlab-runner
sudo systemctl start gitlab-runner
# Sprawdz wersje
gitlab-runner --version
# Status serwisu
sudo systemctl status gitlab-runner
Po instalacji runner działa jako serwis systemd, a konfiguracja znajduje się w
/etc/gitlab-runner/config.toml. Domyślny użytkownik to gitlab-runner, który ma własny katalog domowy i nie powinien być rootem.
Shell executor vs Docker executor
Wybór executora to najważniejsza decyzja przy konfiguracji runnera. Shell executor wykonuje komendy bezpośrednio w shellu użytkownika gitlab-runner — jest najszybszy, ale nie daje izolacji. Docker executor tworzy osobny kontener dla każdego joba — wolniejszy, ale zapewnia czyste środowisko i łatwy rollback.
| Cecha | Shell executor | Docker executor |
|---|---|---|
| Szybkość startu | Natychmiast | 2-5 sekund (pull image) |
| Izolacja | Brak | Pełna (container) |
| Konflikty wersji | Tak (global install) | Nie (per image) |
| Bezpieczeństwo | Niskie | Wysokie |
| Cleanup | Ręczny | Automatyczny |
Rejestracja runnera
Po instalacji runnera musisz go zarejestrować w GitLab. W GitLab idź do Settings > CI/CD > Runners i skopiuj token rejestracyjny. Rejestracja jest interaktywna, ale możesz też przekazać wszystkie parametry w linii komend (np. w skrypcie provisioningu).
# Rejestracja non-interactive z docker executor
sudo gitlab-runner register \
--non-interactive \
--url "https://gitlab.com/" \
--registration-token "TWOJ_TOKEN" \
--executor "docker" \
--docker-image "alpine:latest" \
--description "vps-runner-1" \
--tag-list "docker,vps,linux" \
--run-untagged="true" \
--locked="false" \
--access-level="not_protected"
# Lista zarejestrowanych runnerow
sudo gitlab-runner list
# Weryfikacja polaczenia
sudo gitlab-runner verify Stages, artifacts i cache w .gitlab-ci.yml
Plik .gitlab-ci.yml definiuje pipeline: stages (fazy), joby w każdym stage, zmienne,
cache, artifacts i warunki uruchomienia. Stages są wykonywane sekwencyjnie, a joby w obrębie tego
samego stage — równolegle (jeśli masz wystarczającą liczbę runnerów).
stages:
- test
- build
- deploy
variables:
NODE_VERSION: "20"
# Cache wspoldzielony miedzy jobami
.node_cache: &node_cache
cache:
key:
files:
- pnpm-lock.yaml
paths:
- node_modules/
- .pnpm-store/
test:unit:
stage: test
image: node:${NODE_VERSION}
<<: *node_cache
script:
- corepack enable
- pnpm install --frozen-lockfile
- pnpm test:unit
artifacts:
when: always
reports:
junit: reports/junit.xml
expire_in: 1 week
build:production:
stage: build
image: node:${NODE_VERSION}
<<: *node_cache
script:
- pnpm install --frozen-lockfile
- pnpm build
artifacts:
paths:
- dist/
expire_in: 1 day
only:
- main
deploy:production:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache openssh-client rsync
script:
- rsync -az dist/ deploy@vps:/var/www/app/
only:
- main
when: manual Optymalizacja wydajności runnera
Self-hosted runner pozwala na agresywne optymalizacje, które nie są dostępne na runnerach
SaaS. Pierwszą rzeczą jest ustawienie concurrent w /etc/gitlab-runner/config.toml
— ile jobów może być wykonywanych równolegle. Domyślnie 1, co dla maszyny z 4 vCPU jest marnowaniem
zasobów.
Druga optymalizacja to konfiguracja wolumenów cache dla Dockera. Domyślnie każdy job zaczyna
z pustym volume, ale możesz zmapować wolumen hosta, żeby cache npm/pnpm/composer był
utrzymywany między runami. Dodaj w sekcji runners.docker: volumes = ["/cache", "/var/cache/pnpm:/root/.pnpm-store"].
Trzecia to użycie BuildKit w Dockerze — włącz DOCKER_BUILDKIT=1 w variables pipeline,
a czas buildów skróci się o 30-60%. Dodatkowo BuildKit obsługuje parallel layer builds i inline
cache mount, czego klasyczny docker build nie potrafi.