GitLab Runner: Docker-images bouwen
Bouw en push Docker-images efficiënt vanuit uw GitLab CI/CD-pipelines met Stackhero runners en Docker-in-Docker
👋 Welkom bij de Stackhero-documentatie!
Stackhero biedt een eenvoudige GitLab Runner cloud oplossing waarmee u uw GitLab CI/CD-jobs efficiënt en zonder gedoe kunt uitvoeren. Dit kunt u verwachten:
- Onbeperkte CI/CD-minuten: voer uw pijplijnen zo vaak uit als nodig, zonder kosten per minuut of onverwachte extra kosten.
- Meerdere gelijktijdige jobs: versnel uw ontwikkeling door verschillende jobs parallel uit te voeren.
- De Docker executor met ondersteuning voor Docker-in-Docker: bouw en push eenvoudig container images als onderdeel van uw CI/CD-proces.
- Werkt naadloos met zowel GitLab.com als self-managed GitLab-omgevingen.
- Een privé, dedicated infrastructuur met snelle NVMe/SSD-opslag zorgt voor stabiele en voorspelbare build-prestaties.
- Beschikbaar in de regio's 🇪🇺 Europa en 🇺🇸 USA om aan de behoeften van uw team te voldoen.
Bespaar tijd: u kunt uw eerste GitLab Runner koppelen en binnen enkele minuten starten met het uitvoeren van pijplijnen!
Introductie
Met een Stackhero GitLab Runner draait elke job in een verse container via de Docker executor. U kunt uw eigen Docker-images direct in uw pipeline bouwen door Docker-in-Docker (DinD) in te schakelen. Deze configuratie start een Docker-daemon naast uw job, zodat u docker build- en docker push-commando's kunt uitvoeren als onderdeel van uw CI/CD-proces.
Elke run profiteert van onbeperkte CI/CD-minuten: u kunt zo vaak bouwen als nodig is, zonder u zorgen te maken over limieten. Uw build-cache wordt opgeslagen op de dedicated schijf van de runner, waardoor herhaalde builds eerdere lagen kunnen hergebruiken. Dit verkort de buildtijden aanzienlijk en versnelt uw pipelines.
Een Docker-image bouwen met Docker-in-Docker
U kunt het volgende voorbeeld van .gitlab-ci.yml toevoegen aan uw repository. Deze configuratie bouwt de Dockerfile in de root van uw project:
build-image:
stage: build
image: docker:29
services:
- name: docker:29-dind
alias: docker
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
before_script:
- docker info
script:
# Vervang "my-image" door de gewenste naam:
- docker build -t my-image .
# Optioneel: voer een snelle test uit op het gebouwde image:
# - docker run --rm my-image /path/to/tests
In dit voorbeeld gebruiken we Docker-image versie 29. U kunt een nieuwere versie gebruiken zodra deze beschikbaar is. De laatste tags vindt u op de officiële Docker image pagina.
In deze setup start de docker:29-dind service een Docker-daemon naast uw job, en DOCKER_HOST: "tcp://docker:2375" vertelt de docker CLI om deze te gebruiken. Stel altijd DOCKER_HOST in wanneer u een docker:dind service gebruikt: zonder deze variabele maakt de CLI stilzwijgend verbinding met een andere daemon, waardoor uw build kan slagen zelfs als de service verkeerd is geconfigureerd. Dit verbergt echte problemen (en breekt tools zoals Testcontainers die afhankelijk zijn van de service). DOCKER_TLS_CERTDIR: "" zorgt ervoor dat er verbinding wordt gemaakt via de niet-versleutelde poort 2375 op het interne jobnetwerk.
Als eenvoudiger alternatief kunt u het services-blok en beide variabelen weglaten: de Stackhero runner biedt ook een kant-en-klare Docker-daemon via een gemounte socket, zodat een eenvoudige docker build werkt zonder extra configuratie.
Uw tests uitvoeren met Testcontainers
Testcontainers is een testbibliotheek, beschikbaar voor Java, Go, Node.js, Python, .NET en andere talen, die echte services als tijdelijke Docker-containers opstart tijdens het uitvoeren van uw tests. In plaats van bijvoorbeeld een database of message broker te mocken, communiceren uw integratietests met een echte PostgreSQL-, MySQL-, Redis- of Kafka-instantie, die vóór de tests wordt aangemaakt en direct erna weer wordt verwijderd. Het is vooral populair in Java- en Spring-projecten.
Testcontainers heeft een Docker-daemon nodig en werkt dus met exact dezelfde Docker-in-Docker-configuratie als hierboven. Er is geen extra variabele nodig:
test:
stage: test
# Gebruik het image dat uw tests nodig hebben (hier een JDK), niet per se het docker-image:
image: gradle:jdk21
services:
- name: docker:29-dind
alias: docker
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
script:
- gradle test
Testcontainers leest DOCKER_HOST om de daemon te vinden en gebruikt dezelfde docker hostname om de poorten te bereiken die door de containers worden gepubliceerd. Beide werken zelfstandig, omdat het docker alias op het netwerk van uw job wordt opgelost.
Houd
DOCKER_HOSTin uw Testcontainers-jobs. Zonder deze variabele valt Testcontainers terug op de Docker-socket die door de runner is gemount, en probeert vervolgens uw testcontainers te bereiken via het host-IP-adres, waar uw job geen verbinding mee kan maken. Het gebruikelijke symptoom is dat de Ryuk-helpercontainer faalt metWait strategy failed. Container is removed, ofTimed out waiting for log output matching '.*Started.*'.
Pushen naar de GitLab container registry
GitLab stelt vooraf gedefinieerde variabelen beschikbaar (CI_REGISTRY, CI_REGISTRY_USER, CI_REGISTRY_PASSWORD, CI_REGISTRY_IMAGE) zodat uw pipeline veilig kan authenticeren en images kan pushen naar de container registry van uw project. Er zijn geen extra secrets nodig.
Hier is een voorbeeldjob die uw image bouwt en pusht:
build-and-push:
stage: build
image: docker:29
services:
- name: docker:29-dind
alias: docker
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
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"
# Als u op de default branch zit, kunt u ook "latest" taggen en pushen:
- |
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
Om uw images naar een andere registry te pushen (zoals Docker Hub of een private registry), kunt u credentials opslaan als CI/CD-variabelen en deze op dezelfde manier gebruiken met docker login.
Herhaalde builds versnellen
De schijf van uw runner blijft behouden tussen pipelines, waardoor u imagelagen als build-cache kunt hergebruiken. Dit maakt herhaalde builds veel sneller. Hier is een voorbeeldconfiguratie:
build-cached:
stage: build
image: docker:29
services:
- name: docker:29-dind
alias: docker
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
script:
# Pull het laatste image om de cache te vullen (indien aanwezig):
- 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"
Met deze aanpak kunnen uw builds gebruikmaken van Docker's laagcaching, zodat alleen nieuwe of gewijzigde lagen opnieuw worden opgebouwd.
Jobs parallel uitvoeren
Uw abonnement bepaalt hoeveel jobs er gelijktijdig kunnen draaien. Jobs in dezelfde stage starten samen, tot aan uw limiet voor gelijktijdigheid. Dit betekent dat meerdere onafhankelijke jobs parallel kunnen draaien en afronden zodra de langzaamste klaar is, in plaats van te wachten tot elke job na elkaar klaar is.
Voorbeeld:
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
Als u uw gelijktijdigheid op 1 of hoger instelt, zullen de unit, integration en e2e jobs tegelijkertijd worden uitgevoerd.
Voor meer informatie over het bouwen van Docker-images in GitLab CI/CD-pipelines kunt u de officiële GitLab-documentatie over Docker builds raadplegen.