GitLab Runner: Docker-Images bauen
Bauen und pushen Sie Docker-Images effizient aus Ihren GitLab CI/CD-Pipelines mit Stackhero Runnern und Docker-in-Docker
👋 Willkommen in der Stackhero-Dokumentation!
Stackhero bietet Ihnen eine unkomplizierte GitLab Runner Cloud-Lösung, mit der Sie Ihre GitLab CI/CD-Jobs effizient und ohne Aufwand ausführen können. Das erwartet Sie:
- Unbegrenzte CI/CD-Minuten: Führen Sie Ihre Pipelines so oft aus, wie Sie möchten – ohne Abrechnung pro Minute oder unerwartete Zusatzkosten.
- Mehrere gleichzeitige Jobs: Beschleunigen Sie Ihre Entwicklung, indem Sie mehrere Jobs parallel ausführen.
- Der Docker Executor mit Docker-in-Docker-Unterstützung: Erstellen und pushen Sie Container-Images ganz einfach als Teil Ihres CI/CD-Prozesses.
- Funktioniert nahtlos mit GitLab.com und self-managed GitLab-Instanzen.
- Eine private, dedizierte Infrastruktur mit schneller NVMe/SSD-Speicherung sorgt für stabile und vorhersehbare Build-Performance.
- Verfügbar in den Regionen 🇪🇺 Europa und 🇺🇸 USA, passend zu den Anforderungen Ihres Teams.
Sparen Sie Zeit: Sie können Ihren ersten GitLab Runner verbinden und bereits nach wenigen Minuten mit Ihren Pipelines starten!
Einführung
Mit einem Stackhero GitLab Runner läuft jeder Job in einem frischen Container unter Verwendung des Docker Executors. Sie können Ihre eigenen Docker-Images direkt in Ihrer Pipeline bauen, indem Sie Docker-in-Docker (DinD) aktivieren. Dieses Setup startet einen Docker-Daemon parallel zu Ihrem Job, sodass Sie docker build- und docker push-Befehle als Teil Ihres CI/CD-Prozesses ausführen können.
Jeder Lauf profitiert von unbegrenzten CI/CD-Minuten: Sie können beliebig oft bauen, ohne sich um Nutzungslimits sorgen zu müssen. Ihr Build-Cache wird auf der dedizierten Festplatte des Runners gespeichert, sodass wiederholte Builds vorherige Layer wiederverwenden können. Das reduziert die Build-Zeiten erheblich und beschleunigt Ihre Pipelines.
Docker-Image mit Docker-in-Docker bauen
Sie können die folgende Beispiel-.gitlab-ci.yml-Datei zu Ihrem Repository hinzufügen. Diese Konfiguration baut das Dockerfile im Root-Verzeichnis Ihres Projekts:
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:
# Ersetzen Sie "my-image" durch den gewünschten Namen:
- docker build -t my-image .
# Optional: Führen Sie einen schnellen Test mit dem gebauten Image durch:
# - docker run --rm my-image /path/to/tests
In diesem Beispiel verwenden wir die Docker-Image-Version 29. Sie können auch eine neuere Version verwenden, sobald diese verfügbar ist. Die aktuellsten Tags finden Sie auf der offiziellen Docker-Image-Seite.
In diesem Setup startet der Service docker:29-dind einen Docker-Daemon neben Ihrem Job, und DOCKER_HOST: "tcp://docker:2375" weist das docker CLI an, diesen zu verwenden. Setzen Sie immer DOCKER_HOST, wenn Sie einen docker:dind-Service deklarieren: Ohne diese Variable verbindet sich das CLI stillschweigend mit einem anderen Daemon, sodass Ihr Build auch bei fehlerhafter Service-Konfiguration erfolgreich sein kann. Das verbirgt echte Probleme (und führt dazu, dass Tools wie Testcontainers, die auf den Service angewiesen sind, nicht funktionieren). DOCKER_TLS_CERTDIR: "" sorgt dafür, dass die Verbindung über den unverschlüsselten Port 2375 im internen Job-Netzwerk erfolgt.
Als einfachere Alternative können Sie den services-Block und beide Variablen weglassen: Der Stackhero Runner stellt auch einen einsatzbereiten Docker-Daemon über einen gemounteten Socket bereit, sodass ein einfaches docker build ohne weitere Konfiguration funktioniert.
Tests mit Testcontainers ausführen
Testcontainers ist eine Testbibliothek, verfügbar für Java, Go, Node.js, Python, .NET und weitere Sprachen, die während Ihrer Tests echte Services als temporäre Docker-Container startet. Anstatt eine Datenbank oder einen Message-Broker zu mocken, kommunizieren Ihre Integrationstests mit einer echten PostgreSQL-, MySQL-, Redis- oder Kafka-Instanz, die vor den Tests erstellt und danach wieder entfernt wird. Besonders beliebt ist Testcontainers in Java- und Spring-Projekten.
Testcontainers benötigt einen Docker-Daemon und läuft daher mit exakt derselben Docker-in-Docker-Konfiguration wie oben. Es sind keine zusätzlichen Variablen erforderlich:
test:
stage: test
# Verwenden Sie das Image, das Ihre Tests benötigen (hier ein JDK), nicht zwingend das 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 liest DOCKER_HOST, um den Daemon zu finden, und verwendet denselben docker-Hostnamen, um auf die von den Containern veröffentlichten Ports zuzugreifen. Beides funktioniert, da der Alias docker im Netzwerk Ihres Jobs aufgelöst wird.
Belassen Sie
DOCKER_HOSTin Ihren Testcontainers-Jobs. Ohne diese Variable greift Testcontainers auf den vom Runner gemounteten Docker-Socket zurück und versucht dann, Ihre Testcontainer über die Host-IP-Adresse zu erreichen, was aus dem Job heraus nicht möglich ist. Typische Symptome sind, dass der Ryuk-Helfercontainer mitWait strategy failed. Container is removedoderTimed out waiting for log output matching '.*Started.*'fehlschlägt.
Push in die GitLab Container Registry
GitLab stellt vordefinierte Variablen (CI_REGISTRY, CI_REGISTRY_USER, CI_REGISTRY_PASSWORD, CI_REGISTRY_IMAGE) bereit, damit Ihre Pipeline sich authentifizieren und Images sicher in die Container Registry Ihres Projekts pushen kann. Zusätzliche Secrets sind nicht erforderlich.
Hier ein Beispiel-Job, der Ihr Image baut und 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"
# Wenn Sie sich auf dem Default-Branch befinden, können Sie zusätzlich "latest" taggen und 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
Um Ihre Images in ein anderes Registry (wie Docker Hub oder ein privates Registry) zu pushen, können Sie Zugangsdaten als CI/CD-Variablen speichern und diese mit docker login auf die gleiche Weise verwenden.
Wiederholte Builds beschleunigen
Die Festplatte Ihres Runners bleibt zwischen den Pipelines bestehen, sodass Sie Image-Layer als Build-Cache wiederverwenden können. Das macht wiederholte Builds deutlich schneller. Hier ein Beispiel für eine entsprechende Konfiguration:
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:
# Die neueste Image-Version ziehen, um den Cache zu initialisieren (falls vorhanden):
- 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"
Mit diesem Ansatz können Ihre Builds den Layer-Cache von Docker nutzen, sodass nur neue oder geänderte Layer neu gebaut werden.
Jobs parallel ausführen
Ihr Tarif bestimmt, wie viele Jobs gleichzeitig laufen können. Jobs in derselben Stage starten gemeinsam, bis zur Grenze Ihrer Parallelität. Das bedeutet, mehrere unabhängige Jobs können parallel ausgeführt werden und sind fertig, sobald der langsamste Job abgeschlossen ist – ohne dass sie nacheinander warten müssen.
Beispiel:
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
Wenn Sie Ihre Parallelität auf 1 oder höher setzen, laufen die Jobs unit, integration und e2e gleichzeitig.
Weitere Informationen zum Bauen von Docker-Images in GitLab CI/CD-Pipelines finden Sie in der offiziellen GitLab-Dokumentation zur Verwendung von Docker-Builds.