GitLab Runner: Budowanie obrazów Docker

Buduj i wysyłaj obrazy Docker bezpośrednio z pipeline’ów GitLab CI/CD, korzystając z własnego Stackhero runnera i Docker-in-Docker

👋 Witamy w dokumentacji Stackhero!

Stackhero oferuje łatwe w użyciu rozwiązanie GitLab Runner cloud, zaprojektowane do wydajnej obsługi zadań GitLab CI/CD. Oto, czego możesz się spodziewać:

  • Nielimitowane minuty CI/CD: brak rozliczania za minuty, więc Twoje pipeline'y mogą działać zawsze, gdy tego potrzebujesz.
  • Wiele równoczesnych zadań: uruchamiaj kilka jobów jednocześnie, aby przyspieszyć cały pipeline.
  • Docker executor z obsługą Docker-in-Docker: usprawnij budowanie i wysyłanie swoich obrazów kontenerów.
  • Kompatybilny zarówno z GitLab.com, jak i każdą samodzielnie zarządzaną instancją GitLab.
  • Prywatna, dedykowana maszyna wirtualna (VM) oparta na szybkich dyskach NVMe/SSD, zapewniająca stabilne i niezawodne buildy.
  • Dostępny w regionach 🇪🇺 Europa oraz 🇺🇸 USA.

Oszczędzaj czas: możesz podłączyć swojego pierwszego GitLab Runnera i uruchomić pipeline'y w zaledwie kilka minut!

Kiedy korzystasz z Stackhero GitLab Runnera, zadania są uruchamiane z użyciem Docker executor. Oznacza to, że każde zadanie startuje w nowym kontenerze, bazującym na wskazanym przez Ciebie image. Jeśli chcesz budować własne obrazy Docker w ramach pipeline’u, możesz skorzystać z Docker-in-Docker (DinD). Taka konfiguracja pozwala na uruchomienie demona Docker równolegle z Twoim zadaniem, dzięki czemu możesz wykonywać polecenia takie jak docker build i docker push bezpośrednio w pipeline’ie.

Jedną z głównych zalet tego rozwiązania jest to, że Twój runner posiada nielimitowane minuty CI/CD. Możesz budować obrazy tak często, jak tylko potrzebujesz. Dodatkowo, ponieważ cache buildów znajduje się na dedykowanym dysku runnera, kolejne budowy mogą wykorzystywać poprzednie warstwy, co znacząco przyspiesza działanie pipeline’ów.

Poniżej znajdziesz przykładowy plik .gitlab-ci.yml, który możesz dodać do swojego repozytorium. Ta konfiguracja buduje Dockerfile znajdujący się w katalogu głównym projektu:

build-image:
  stage: build
  image: docker:27
  services:
    - docker:27-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker info
  script:
    # Zamień "my-image" na wybraną nazwę:
    - docker build -t my-image .
    # Opcjonalnie możesz uruchomić szybki test na zbudowanym obrazie:
    # - docker run --rm my-image /path/to/tests

W tej konfiguracji serwis docker:27-dind uruchamia demona Docker. Zmienna DOCKER_TLS_CERTDIR: "/certs" umożliwia bezpieczne połączenie TLS pomiędzy zadaniem a demonem Docker.

GitLab udostępnia kilka predefiniowanych zmiennych (CI_REGISTRY, CI_REGISTRY_USER, CI_REGISTRY_PASSWORD, CI_REGISTRY_IMAGE), dzięki którym pipeline może zalogować się i wysłać obrazy do rejestru kontenerów projektu bez konieczności podawania dodatkowych sekretów.

Oto przykładowe zadanie, które buduje i wysyła Twój obraz:

build-and-push:
  stage: build
  image: docker:27
  services:
    - docker:27-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
  script:
    - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" .
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
    # Jeśli jesteś na domyślnej gałęzi, możesz również oznaczyć i wysłać "latest":
    - |
      if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then
        docker tag "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE:latest"
        docker push "$CI_REGISTRY_IMAGE:latest"
      fi

Jeśli chcesz wysyłać obrazy do innego rejestru (np. Docker Hub lub prywatnego rejestru), możesz przechowywać te dane uwierzytelniające jako zmienne CI/CD i używać ich z docker login w podobny sposób.

Ponieważ dysk runnera jest trwały pomiędzy pipeline’ami, możesz przyspieszyć budowanie, wykorzystując poprzednie warstwy obrazu jako cache. Oto jak można to skonfigurować:

build-cached:
  stage: build
  image: docker:27
  services:
    - docker:27-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
  script:
    # Spróbuj pobrać najnowszy obraz, aby zasilić cache (nie szkodzi, jeśli jeszcze nie istnieje):
    - docker pull "$CI_REGISTRY_IMAGE:latest" || true
    - docker build --cache-from "$CI_REGISTRY_IMAGE:latest" -t "$CI_REGISTRY_IMAGE:latest" .
    - docker push "$CI_REGISTRY_IMAGE:latest"

Takie podejście pozwala Twoim pipeline’om z czasem działać coraz szybciej, dzięki efektywnemu wykorzystaniu cache warstw Docker.

Twój plan określa, ile zadań może być uruchamianych jednocześnie. Zadania w tej samej fazie (stage) startują równolegle, do limitu współbieżności. Oznacza to, że faza z wieloma niezależnymi zadaniami zakończy się, gdy najwolniejsze z nich się skończy, zamiast uruchamiać wszystkie zadania po kolei.

Oto prosty przykład:

stages:
  - test

unit:
  stage: test
  image: node:22
  script: npm run test:unit

integration:
  stage: test
  image: node:22
  script: npm run test:integration

e2e:
  stage: test
  image: node:22
  script: npm run test:e2e

Jeśli ustawisz współbieżność na 3 lub więcej, zadania unit, integration i e2e zostaną uruchomione jednocześnie.

Jeśli chcesz dowiedzieć się więcej o budowaniu obrazów Docker w CI, zapoznaj się z oficjalną dokumentacją GitLab.