Ein häufiger Anwendungsfall für CI-Pipelines ist das Erstellen der Docker-Images, die Sie zum Bereitstellen Ihrer Anwendung verwenden. GitLab CI ist dafür eine gute Wahl, da es einen integrierten Pull-Proxy-Dienst unterstützt, was schnellere Pipelines und eine integrierte Registrierung zum Speichern Ihrer erstellten Images bedeutet.
In diesem Leitfaden zeigen wir Ihnen, wie Sie Docker-Builds einrichten, die beide oben genannten Funktionen verwenden. Die Schritte, die Sie ausführen müssen, variieren leicht, je nachdem, welchen GitLab Runner-Executor-Typ Sie für Ihre Pipeline verwenden werden. Wir werden die Shell- und Docker-Executoren unten behandeln.
Bauen mit dem Shell-Executor
Wenn Sie den Shell-Executor verwenden, stellen Sie sicher, dass Docker auf dem Computer installiert ist, der Ihren Runner hostet. Der Executor funktioniert, indem er reguläre Shell-Befehle mit dem docker
ausführt binär auf dem Host des Runners.
Gehen Sie zum Git-Repository für das Projekt, für das Sie Images erstellen möchten. Erstellen Sie eine .gitlab-ci.yml
Datei im Stammverzeichnis des Repositorys. Diese Datei definiert die GitLab CI-Pipeline, die ausgeführt wird, wenn Sie Änderungen an Ihr Projekt übertragen.
Fügen Sie der Datei folgenden Inhalt hinzu:
stages: - build docker_build: stage: build script: - docker build -t example.com/example-image:latest . - docker push example.com/example-image:latest
Diese vereinfachte Konfiguration reicht aus, um die Grundlagen von Pipeline-gestützten Image-Builds zu demonstrieren. GitLab klont Ihr Git-Repository automatisch in die Build-Umgebung und führt so docker build
aus verwendet das Dockerfile
Ihres Projekts und stellen Sie den Inhalt des Repositorys als Build-Kontext zur Verfügung.
Nachdem der Build abgeschlossen ist, können Sie docker push
das Image in Ihre Registrierung. Andernfalls wäre es nur für die lokale Docker-Installation verfügbar, die den Build ausgeführt hat. Wenn Sie eine private Registrierung verwenden, führen Sie docker login
aus Geben Sie zuerst die richtigen Authentifizierungsdetails ein:
script: - docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD
Definieren Sie die Werte der beiden Credential-Variablen, indem Sie in der GitLab-Webbenutzeroberfläche zu Einstellungen> CI/CD> Variablen gehen. Klicken Sie auf die blaue Schaltfläche „Variable hinzufügen“, um eine neue Variable zu erstellen und einen Wert zuzuweisen. GitLab stellt diese Variablen in der Shell-Umgebung zur Verfügung, die zum Ausführen Ihres Jobs verwendet wird.
Building with the Docker Executor
Der Docker-Executor von GitLab Runner wird häufig verwendet, um eine vollständig saubere Umgebung für jeden Job bereitzustellen. Der Job wird in einem isolierten Container ausgeführt, also dem docker
Binärdatei auf dem Runner-Host ist unzugänglich.
Der Docker-Executor bietet Ihnen zwei mögliche Strategien zum Erstellen Ihres Images:Verwenden Sie entweder Docker-in-Docker oder binden Sie den Docker-Socket des Hosts in die Build-Umgebung des Runners ein. Anschließend verwenden Sie das offizielle Docker-Container-Image als Image Ihres Jobs und erstellen so den docker
Befehl, der in Ihrem CI-Skript verfügbar ist.
Docker-in-Docker
Durch die Verwendung von Docker-in-Docker (DinD) zum Erstellen Ihrer Images erhalten Sie eine vollständig isolierte Umgebung für jeden Job. Der Docker-Prozess, der den Build durchführt, ist ein untergeordnetes Element des Containers, den GitLab Runner auf dem Host erstellt, um den CI-Job auszuführen.
Sie müssen Ihren GitLab Runner Docker-Executor mit aktiviertem privilegiertem Modus registrieren, um DinD verwenden zu können. Fügen Sie --docker-privileged
hinzu Flagge, wenn Sie Ihren Läufer registrieren:
sudo gitlab-runner register -n --url https://example.com --registration-token $GITLAB_REGISTRATION_TOKEN --executor docker --description "Docker Runner" --docker-image "docker:20.10" --docker-volumes "/certs/client" --docker-privileged
Fügen Sie in Ihrer CI-Pipeline den docker:dind
hinzu Bild als Dienstleistung. Dadurch wird Docker als separates Image verfügbar, das mit dem Job-Image verknüpft ist. Sie können den docker
verwenden Befehl zum Erstellen von Images mithilfe der Docker-Instanz im docker:dind
Behälter.
services: - docker:dind docker_build: stage: build image: docker:latest script: - docker build -t example-image:latest .
Durch die Verwendung von DinD erhalten Sie vollständig isolierte Builds, die sich gegenseitig oder Ihren Host nicht beeinflussen können. Der größte Nachteil ist das kompliziertere Caching-Verhalten:Jeder Job erhält eine neue Umgebung, in der zuvor erstellte Layer nicht zugänglich sind. Sie können dies teilweise beheben, indem Sie versuchen, die vorherige Version Ihres Images vor dem Erstellen abzurufen, und dann --cache-from
verwenden build-Flag, um die Ebenen des gezogenen Bildes als Cache-Quelle verfügbar zu machen:
docker_build: stage: build image: docker:latest script: - docker pull $CI_REGISTRY_IMAGE:latest || true - docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:latest .
Socket-Bind-Halterungen
Das Mounten des Docker-Sockets Ihres Hosts in die Umgebung Ihres Jobs ist eine alternative Option, wenn Sie den Docker-Executor verwenden. Dies ermöglicht ein nahtloses Caching und macht das Hinzufügen von docker:dind
überflüssig Service zu Ihrer CI-Konfiguration.
Um dies einzurichten, registrieren Sie Ihren Runner mit einem docker-volumes
-Flag, das den Docker-Socket des Hosts an /var/run/docker.sock
bindet innerhalb von Jobcontainern:
sudo gitlab-runner register -n --url https://example.com --registration-token $GITLAB_REGISTRATION_TOKEN --executor docker --description "Docker Runner" --docker-image "docker:20.10" --docker-volumes /var/run/docker.sock:/var/run/docker.sock
Jetzt Jobs, die mit dem docker
ausgeführt werden image kann den docker
verwenden Binär wie gewohnt. Vorgänge werden tatsächlich auf Ihrem Hostcomputer ausgeführt und werden zu Geschwistern des Containers des Jobs statt zu Kindern.
Dies ähnelt effektiv der Verwendung des Shell-Executors mit der Docker-Installation Ihres Hosts. Bilder werden auf dem Host gespeichert, was die nahtlose Verwendung des regulären docker build
erleichtert Layer-Caching.
Während dieser Ansatz zu höherer Leistung, weniger Konfiguration und keiner der Einschränkungen von DinD führen kann, bringt er seine eigenen einzigartigen Probleme mit sich. Am wichtigsten sind die Auswirkungen auf die Sicherheit:Jobs könnten beliebige Docker-Befehle auf Ihrem Runner-Host ausführen, sodass ein bösartiges Projekt in Ihrer GitLab-Instanz möglicherweise docker run -it malicious-image:latest
ausführt oder docker rm -f $(docker ps -a)
mit verheerenden Folgen.
GitLab warnt auch davor, dass die Socket-Bindung Probleme verursachen kann, wenn Jobs gleichzeitig ausgeführt werden. Dies tritt auf, wenn Sie sich darauf verlassen, dass Container mit bestimmten Namen erstellt werden. Wenn zwei Instanzen eines Jobs parallel ausgeführt werden, schlägt die zweite fehl, da der Containername bereits auf Ihrem Host vorhanden ist.
Sie sollten stattdessen DinD verwenden, wenn Sie erwarten, dass eines dieser Probleme Probleme bereiten wird. Obwohl DinD nicht mehr allgemein empfohlen wird, kann es für öffentlich zugängliche GitLab-Instanzen sinnvoller sein, die gleichzeitig CI-Jobs ausführen.
Pushing von Bildern in die Registrierung von GitLab
GitLab-Projekte verfügen optional über eine integrierte Registry, in der Sie Ihre Images speichern können. Sie können den Inhalt der Registrierung anzeigen, indem Sie in der Seitenleiste Ihres Projekts zu Pakete &Registrierungen> Container-Registrierung navigieren. Wenn Sie diesen Link nicht sehen, aktivieren Sie die Registrierung, indem Sie zu Einstellungen> Allgemein> Sichtbarkeit, Projekt, Funktionen und Berechtigungen gehen und den Schalter „Container-Registrierung“ aktivieren.
GitLab setzt automatisch Umgebungsvariablen in Ihren CI-Jobs, mit denen Sie auf die Containerregistrierung Ihres Projekts verweisen können. Passen Sie das script
an Abschnitt, um sich bei der Registrierung anzumelden und Ihr Image zu übertragen:
script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:latest . - docker push $CI_REGISTRY_IMAGE:latest
GitLab generiert einen sicheren Satz von Anmeldeinformationen für jeden Ihrer CI-Jobs. Der $CI_JOB_TOKEN
Die Umgebungsvariable enthält ein Zugriffstoken, das der Job verwenden kann, um sich mit der Registrierung als gitlab-ci-token
zu verbinden Benutzer. Die Registrierungsserver-URL ist als $CI_REGISTRY
verfügbar .
Die letzte Variable, $CI_REGISTRY_IMAGE
, stellt den vollständigen Pfad zur Containerregistrierung Ihres Projekts bereit. Dies ist eine geeignete Basis für Ihre Image-Tags. Sie können diese Variable erweitern, um Unterrepositorys zu erstellen, z. B. $CI_REGISTRY_IMAGE/production/api:latest
.
Andere Docker-Clients können Images aus der Registrierung abrufen, indem sie sich mit einem Zugriffstoken authentifizieren. Sie können diese auf dem Bildschirm Einstellungen> Zugriffstoken Ihres Projekts generieren. Fügen Sie die read_registry
hinzu Bereich, und verwenden Sie dann die angezeigten Anmeldeinformationen für die docker login
in die Registrierung Ihres Projekts.
Verwenden des Abhängigkeitsproxys von GitLab
Der Dependency Proxy von GitLab bietet eine Caching-Schicht für die Upstream-Images, die Sie aus Docker Hub abrufen. Es hilft Ihnen, innerhalb der Ratenbegrenzungen von Docker Hub zu bleiben, indem es nur den Inhalt von Bildern abruft, wenn sie sich tatsächlich geändert haben. Dadurch wird auch die Leistung Ihrer Builds verbessert.
Der Abhängigkeits-Proxy wird auf der GitLab-Gruppenebene aktiviert, indem Sie zu Einstellungen> Pakete &Registrierungen> Abhängigkeits-Proxy gehen. Sobald es aktiviert ist, stellen Sie Bildreferenzen in Ihrer .gitlab-ci.yml
voran Datei mit $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
um sie durch den Proxy zu ziehen:
docker_build: stage: build image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:latest services: - name: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:dind alias: docker
Das ist alles dazu! GitLab Runner meldet sich automatisch bei der Dependency-Proxy-Registrierung an, sodass Sie Ihre Anmeldeinformationen nicht manuell eingeben müssen.
GitLab speichert Ihre Bilder jetzt im Cache, was Ihnen eine verbesserte Leistung sowie Ausfallsicherheit bei Netzwerkausfällen bietet. Beachten Sie, dass die services
Definition musste auch angepasst werden – Umgebungsvariablen funktionieren nicht mit dem früher verwendeten Inline-Formular, also das vollständige Bild name
angegeben werden muss, dann ein Befehl alias
in Ihrem script
zu referenzieren Abschnitt.
Während wir jetzt den Proxy für Bilder eingerichtet haben, die direkt von unseren Jobphasen verwendet werden, ist mehr Arbeit erforderlich, um Unterstützung für das Basisbild in der Dockerfile
hinzuzufügen bauen. Eine normale Anweisung wie diese geht nicht über den Proxy:
FROM ubuntu:latest
Um diesen letzten Teil hinzuzufügen, verwenden Sie die Build-Argumente von Docker, um die Abhängigkeits-Proxy-URL verfügbar zu machen, wenn Sie die Docker-Datei schrittweise durchlaufen:
ARG GITLAB_DEPENDENCY_PROXY FROM ${GITLAB_DEPENDENCY_PROXY}/ubuntu:latest
Ändern Sie dann Ihren docker build
Befehl, um den Wert der Variablen zu definieren:
script: > - docker build --build-arg GITLAB_DEPENDENCY_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX} -t example-image:latest .
Jetzt wird auch Ihr Basis-Image durch den Abhängigkeits-Proxy gezogen.
Zusammenfassung
Docker-Image-Builds lassen sich einfach in Ihre GitLab-CI-Pipelines integrieren. Nach der anfänglichen Runner-Konfiguration docker build
und docker push
Befehle im script
Ihres Jobs Abschnitt sind alles, was Sie brauchen, um ein Image mit dem Dockerfile
zu erstellen in Ihrem Depot. Die integrierte Containerregistrierung von GitLab bietet Ihnen privaten Speicherplatz für die Bilder Ihres Projekts.
Über grundlegende Builds hinaus lohnt es sich, den Abhängigkeits-Proxy von GitLab zu integrieren, um die Leistung zu beschleunigen und zu vermeiden, dass Docker Hub-Ratenbegrenzungen erreicht werden. Sie sollten auch die Sicherheit Ihrer Installation überprüfen, indem Sie prüfen, ob Ihre ausgewählte Methode nicht vertrauenswürdigen Projekten erlaubt, Befehle auf Ihrem Runner-Host auszuführen. Obwohl es seine eigenen Probleme mit sich bringt, ist Docker-in-Docker der sicherste Ansatz, wenn Ihre GitLab-Instanz öffentlich zugänglich ist oder von einer großen Benutzerbasis aufgerufen wird.