Hinweis perev. : Der Originalartikel wurde von Miłosz Smółka verfasst, einem der Gründer des kleinen polnischen Unternehmens Three Dots Labs , das sich auf „fortschrittliche Backend-Lösungen“ spezialisiert hat. Der Autor stützt sich auf seine Erfahrungen mit der aktiven Nutzung von GitLab CI und teilt die gesammelten Tipps für andere Benutzer dieses Open Source-Produkts. Nachdem wir sie gelesen hatten, stellten wir fest, wie nahe die von ihm beschriebenen Probleme an uns liegen, und beschlossen, die vorgeschlagenen Lösungen einem breiteren Publikum zugänglich zu machen.
Dieses Mal werde ich fortgeschrittenere Themen in GitLab CI behandeln. Eine häufige Aufgabe besteht darin, nicht standardmäßige Funktionen in der Pipeline zu implementieren. Die meisten Tipps sind spezifisch für GitLab, obwohl einige von ihnen auf andere CI-Systeme angewendet werden können.
Führen Sie Integrationstests aus
In der Regel lässt sich die Codeüberprüfung mithilfe von
Komponententests problemlos mit jedem CI-System verbinden. Normalerweise ist dies nicht komplizierter als das Ausführen eines der Befehle, die in den Standarddienstprogrammen in einer Programmiersprache integriert sind. In solchen Tests verwenden Sie wahrscheinlich verschiedene Moki und Stubs, um Implementierungsdetails auszublenden und sich auf das Testen spezifischer Logik zu konzentrieren. Beispielsweise können Sie die In-Memory-Datenbank als Speicher- oder Schreibstubs für HTTP-Clients verwenden, die immer bereits vorbereitete Antworten zurückgeben.
Früher oder später benötigen Sie jedoch
Integrationstests , um ungewöhnlichere Situationen mit Tests abzudecken. Ich werde nicht auf alle möglichen Arten von Tests eingehen und nur sagen, dass ich unter
Integration Tests verstehe, die externe Ressourcen verwenden. Dies kann ein echter Datenbankserver, ein HTTP-Dienst, ein verbundener Speicher usw. sein.
In GitLab ist es einfach, steckbare Ressourcen als Docker-Container auszuführen, die dem Container zugeordnet sind, in dem die Skripte ausgeführt werden. Diese Abhängigkeiten können mithilfe von
services
definiert werden. Sie sind unter dem Namen des Bildes oder nach dem Namen Ihrer Wahl verfügbar, wenn Sie ihn im
alias
angeben.
Hier ist ein einfaches Beispiel für die Verwendung eines steckbaren Containers mit MySQL:
integration_tests: stage: tests services: - name: mysql:8 alias: db script: - ./run_tests.sh db:3306
In diesem Fall müssen Sie in Testskripten eine Verbindung zum
db
. Die Verwendung eines Alias ist normalerweise eine gute Idee, da Sie damit Bilder ersetzen können, ohne den Testcode ändern zu müssen. Sie können beispielsweise das
mysql
Image durch
mariadb
ersetzen, und das Skript funktioniert weiterhin ordnungsgemäß.
Warten auf Container
Da das Laden von Plug-In-Containern einige Zeit in Anspruch nimmt, müssen Sie möglicherweise warten, bevor Sie Anforderungen senden. Eine einfache Möglichkeit besteht darin, auf
ein Skript mit einem definierten Zeitlimit zu
warten .
Verwenden von Docker Compose
In den meisten Fällen sollten die
services
ausreichend sein. Manchmal kann jedoch eine Interaktion mit externen Diensten erforderlich sein. Zum Beispiel beim Starten von Kafka und ZooKeeper in zwei separaten Containern (auf diese Weise werden offizielle Bilder gesammelt). Ein weiteres Beispiel ist das Ausführen von Tests mit einer dynamischen Anzahl von Knoten, z. B. Selen. Die beste Lösung zum Ausführen dieser Dienste wäre
Docker Compose :
version: '3' services: zookeeper: image: confluentinc/cp-zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: image: confluentinc/cp-kafka environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 ports: - 9092:9092
Wenn Sie Ihre Installation mit GitLab-Läufern auf vertrauenswürdigen Servern verwenden, können Sie Docker Composer über den
Shell-Executor ausführen . Eine weitere mögliche Option ist der
dind
Docker in Docker (
dind
). Lesen Sie in diesem Fall zuerst
diesen Artikel .
Eine Möglichkeit, Compose zu verwenden, besteht darin, Ihre Umgebung einzurichten, Tests auszuführen und dann alles zu zerstören. Ein einfaches Bash-Skript würde folgendermaßen aussehen:
docker-compose up -d ./run_tests.sh localhost:9092 docker-compose down
Solange Sie Tests in einer minimalen Umgebung ausführen, ist alles in Ordnung. Obwohl eine Situation auftreten kann, in der Sie einige Abhängigkeiten installieren müssen ... Es gibt eine andere Möglichkeit, Tests in Docker Compose auszuführen: Sie können Ihr eigenes Docker-Image mit einer Testumgebung erstellen. In einem der Container führen Sie Tests aus und beenden das Programm mit dem entsprechenden Rückkehrcode:
version: '3' services: zookeeper: image: confluentinc/cp-zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: image: confluentinc/cp-kafka environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 tests: image: registry.example.com/some-image command: ./run_tests.sh kafka:9092
Beachten Sie, dass wir keine Ports mehr zuordnen müssen. In diesem Beispiel können Tests direkt mit allen Diensten interagieren.
Und ihr Start wird von einem Befehl ausgeführt:
docker-compose up --exit-code-from tests
Die
--abort-on-container-exit
--exit-code-from
impliziert
--abort-on-container-exit
, was bedeutet: Die gesamte von
docker-compose up
initiierte Umgebung wird gestoppt, nachdem einer der Container abgeschlossen ist. Der Abschlusscode für diesen Befehl entspricht dem Beendigungscode des ausgewählten Dienstes (d. H. Dies sind
tests
im obigen Beispiel). Wenn der Befehl, mit dem die Tests gestartet werden, mit einem Code ungleich Null abgeschlossen wird, wird der gesamte
docker-compose up
damit beendet.
Verwenden von Labels als CI-Tags
Achtung : Dies ist eine eher ungewöhnliche Idee, die mir jedoch sehr nützlich und flexibel erschien.
Wie Sie vielleicht wissen, verfügt GitLab über eine Etikettenfunktion auf Projekt- und Gruppenebene. Auf Tickets und Zusammenführungsanforderungen können Beschriftungen festgelegt werden. Sie haben jedoch keine Beziehung zu Pipelines.

Mit einer kleinen Verfeinerung können Sie in Jobskripten auf die Beschriftungen der Zusammenführungsanforderung zugreifen. In GitLab 11.6 ist alles noch einfacher geworden, weil Die Umgebungsvariable
CI_MERGE_REQUEST_IID
(ja, es handelt sich um die
IID
, nicht um die
ID
), wenn die Pipeline
only: merge_requests
verwendet
only: merge_requests
.
Wenn
only: merge_requests
nicht verwendet wird oder Sie mit einer älteren Version von GitLab arbeiten, kann MR weiterhin abgerufen werden - mithilfe des API-Aufrufs:
curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/commits/$CI_COMMIT_SHA/merge_requests?private_token=$GITLAB_TOKEN"
Das Feld, das wir brauchen, ist
iid
. Denken Sie jedoch daran, dass viele MRs für ein bestimmtes Commit zurückkehren können.
Wenn die MR IID empfangen wird, müssen Sie sich nur noch an die
Merge Requests API wenden und das Feld
labels
aus der Antwort verwenden:
curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID?private_token=$GITLAB_TOKEN"
Login
Leider ist
es derzeit
nicht möglich , mit
$CI_JOB_TOKEN
auf die Projekt-API zuzugreifen (zumindest wenn das Projekt nicht öffentlich ist). Wenn das Projekt nur eingeschränkten Zugriff hat (intern oder privat), müssen Sie für die Autorisierung in der GitLab-API ein persönliches API-Token generieren.

Dies ist jedoch nicht die sicherste Lösung. Seien Sie also vorsichtig. Wenn das Token in schlechte Hände gerät, wird möglicherweise der Schreibzugriff auf alle Ihre Projekte angezeigt. Eine Möglichkeit, Risiken zu reduzieren, besteht darin, ein separates Konto mit dem Recht zu erstellen, das Repository zu lesen und ein persönliches Token für dieses Konto zu erstellen.
Wie sicher sind Ihre Variablen?
Vor einigen Versionen wurde der Abschnitt "
Variablen " als "
Geheime Variablen" bezeichnet.
Dies scheint so zu sein , als ob sie zum zuverlässigen Speichern von Anmeldeinformationen und anderen wichtigen Informationen erstellt wurden. Tatsächlich werden die Variablen einfach vor Benutzern ausgeblendet, die keine Maintainer-Berechtigungen haben. Sie sind nicht auf der Festplatte verschlüsselt, und ihr Leck kann leicht durch Umgebungsvariablen in Skripten auftreten.
Beachten Sie dies, wenn Sie Variablen hinzufügen, und ziehen Sie in Betracht, Geheimnisse in sichereren Lösungen (z. B.
Vault von HashiCorp )
aufzubewahren .
Anwendungsfälle
Was mit den Etikettenlisten zu tun ist, liegt bei Ihnen. Hier sind einige Ideen:
- Verwenden Sie sie zum Segmentieren von Tests.
- Verwenden Sie die Schlüsselwertsemantik mit einem Doppelpunkt als Trennzeichen (z. B. Bezeichnungen wie
tests:auth
, tests:user
). - Fügen Sie bestimmte Funktionen für Jobs hinzu.
- Ermöglichen Sie das Debuggen bestimmter Jobs, wenn das Label vorhanden ist.
Externe APIs aufrufen
Obwohl GitLab bereits mit einer Reihe von Funktionen ausgestattet ist, ist es sehr wahrscheinlich, dass Sie andere Dienstprogramme verwenden möchten, die in Pipelines integriert werden können. Der einfachste Weg, dies zu implementieren, ist natürlich das Aufrufen der guten alten
curl
.
Wenn Sie Ihre eigenen Tools erstellen, können Sie ihnen das Anhören von
GitLab-Webhooks beibringen (siehe Registerkarte
Integrationen in den Projekteinstellungen). Wenn Sie sie jedoch mit kritischen Systemen verwenden möchten, stellen Sie sicher, dass sie den Anforderungen an hohe Verfügbarkeit entsprechen.
Beispiel: Grafana-Anmerkungen
Wenn Sie mit
Grafana arbeiten , sind
Anmerkungen eine hervorragende Möglichkeit, Ereignisse, die im Laufe der Zeit aufgetreten sind, in Diagrammen zu markieren. Sie können nicht nur manuell durch Klicken in die GUI hinzugefügt werden, sondern auch durch Aufrufen der
Grafana REST-API :

Um auf die API zugreifen zu können, müssen Sie einen API-Schlüssel generieren. Ziehen Sie in Betracht, einen separaten Benutzer mit eingeschränktem Zugriff zu erstellen:

Definieren Sie zwei Variablen in den Projekteinstellungen:
GRAFANA_URL
- URL zur Grafana-Installation (z. B. https://grafana.example.com
);GRAFANA_APIKEY
- generierter Schlüssel zur API.
Um es wiederverwenden zu können, legen Sie das Skript
mit allgemeinen Skripten im
Repository ab :
Jetzt können Sie der CI-Konfiguration den Aufruf mit den erforderlichen Parametern hinzufügen:
deploy: stage: deploy script: - $SCRIPTS_DIR/deploy.sh production - $SCRIPTS_DIR/grafana-annotation.sh "$VERSION deployed to production" deploy-production
Diese Aufrufe können im Skript
deploy.sh
platziert werden, um die CI-Konfiguration zu vereinfachen.
Bonus: schnelle Tipps
GitLab verfügt über eine
hervorragende Dokumentation zu allen möglichen Schlüsselwörtern, die zum Konfigurieren von CI verwendet werden können. Ich möchte den Inhalt hier nicht duplizieren, werde aber auf einige nützliche Fälle hinweisen. Klicken Sie auf die Überschriften, um die zugehörige Dokumentation anzuzeigen.
Durch Definieren von Mustern für CI-Variablen können Sie benutzerdefinierte Assemblys für einige Zweige definieren. Dies kann zum Beispiel helfen, Push-Fixes für dringende Fixes zu identifizieren, aber missbrauchen Sie es nicht:
only: refs: - branches variables: - $CI_COMMIT_REF_NAME =~ /^hotfix/
GitLab hat viele
vordefinierte Variablen in jedem CI-Job - verwenden Sie sie.
Verwenden Sie sie, um Doppelarbeit zu vermeiden.
Ab Version 11.3 können Sie auch das
Schlüsselwort extenses verwenden :
.common_before_script: &common_before_script before_script: - ... - ... deploy: <<: *common_before_script
Standardmäßig werden alle in der Pipeline gesammelten Artefakte auf alle nachfolgenden Jobs übertragen. Wenn Sie die Artefakte, von denen Jobs abhängen, explizit auflisten, können Sie Zeit und Speicherplatz sparen:
dependencies: - build
Oder - im Gegenteil - alles komplett überspringen, wenn keiner von ihnen benötigt wird:
dependencies: []
Überspringen Sie das Klonen des Repositorys, wenn der Job diese Dateien nicht verwendet:
variables: GIT_STRATEGY: none
Das ist alles!
Danke fürs Lesen! Für Feedback und Fragen kontaktieren Sie mich auf
Twitter oder
Reddit .
Weitere GitLab-Tipps finden Sie in früheren Beiträgen:
PS vom Übersetzer
Lesen Sie auch in unserem Blog: