ProHoster > Blog > Verwaltung > Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central
Einrichten von GitLab CI zum Hochladen eines Java-Projekts in Maven Central
Dieser Artikel richtet sich an Java-Entwickler, die ihre Produkte mithilfe von GitLab schnell in zentralen Sonatype- und/oder Maven-Repositorys veröffentlichen müssen. In diesem Artikel werde ich über die Einrichtung von Gitlab-Runner, Gitlab-CI und Maven-Plugin sprechen, um dieses Problem zu lösen.
Voraussetzungen:
Sichere Speicherung von MVN- und GPG-Schlüsseln.
Sichere Ausführung öffentlicher CI-Aufgaben.
Hochladen von Artefakten (Release/Snapshot) in öffentliche Repositorys.
Automatische Prüfung der Release-Versionen zur Veröffentlichung in Maven Central.
Eine allgemeine Lösung zum Hochladen von Artefakten in ein Repository für mehrere Projekte.
Eine detaillierte Beschreibung des Mechanismus zum Veröffentlichen von Artefakten in Maven Central über den Sonatype OSS Repository Hosting Service finden Sie bereits in dieser Artikel Benutzer Googolplex, daher werde ich an den richtigen Stellen auf diesen Artikel verweisen.
Vorab anmelden unter Sonatyp JIRA und starten Sie ein Ticket, um das Repository zu öffnen (weitere Informationen finden Sie im Abschnitt Erstellen Sie ein Sonatype JIRA-Ticket). Nach dem Öffnen des Repositorys wird das JIRA-Login/Passwort-Paar (im Folgenden als Sonatype-Konto bezeichnet) verwendet, um Artefakte in den Sonatype-Nexus hochzuladen.
Wenn Sie die Linux-Konsole zum Generieren eines GPG-Schlüssels (gnupg/gnupg2) verwenden, müssen Sie ihn installieren Rng-Werkzeuge Entropie zu erzeugen. Andernfalls kann die Schlüsselgenerierung sehr lange dauern.
Einrichten eines Bereitstellungsprojekts in GitLab
Zunächst müssen Sie ein Projekt erstellen und konfigurieren, in dem die Pipeline für die Bereitstellung von Artefakten gespeichert wird. Ich habe mein Projekt einfach und unkompliziert aufgerufen - einsetzen
Nachdem Sie das Repository erstellt haben, müssen Sie den Zugriff beschränken, um das Repository ändern zu können.
Gehen Sie zum Projekt -> Einstellungen -> Repository -> Geschützte Zweige. Wir löschen alle Regeln und fügen eine einzelne Regel mit Wildcard * mit dem Recht zum Pushen und Zusammenführen nur für Benutzer mit der Rolle „Betreuer“ hinzu. Diese Regel gilt für alle Benutzer dieses Projekts und der Gruppe, zu der dieses Projekt gehört.
Wenn es mehrere Betreuer gibt, wäre es die beste Lösung, den Zugriff auf das Projekt grundsätzlich einzuschränken.
Gehen Sie zum Projekt -> Einstellungen -> Allgemein -> Sichtbarkeit, Projektfunktionen, Berechtigungen und stellen Sie die Sichtbarkeit des Projekts auf ein Privat.
Ich habe ein Projekt im öffentlichen Zugriff, da ich meinen eigenen GitLab Runner verwende und nur ich Zugriff zum Ändern des Repositorys habe. Nun, eigentlich liegt es nicht in meinem Interesse, private Informationen in öffentlichen Pipeline-Protokollen anzuzeigen.
Verschärfung der Regeln für den Wechsel des Repositorys
Gehen Sie zum Projekt -> Einstellungen -> Repository -> Push-Regeln und setzen Sie die Flags Committer-Einschränkung. Überprüfen Sie, ob der Autor ein GitLab-Benutzer ist. Ich empfehle auch die Einstellung Unterzeichnung verpflichtenund setzen Sie das Flag „Unsignierte Commits ablehnen“.
Als Nächstes müssen Sie einen Auslöser zum Ausführen von Aufgaben konfigurieren
Gehen Sie zu Projekt -> Einstellungen -> CI/CD -> Pipeline-Trigger und erstellen Sie ein neues Trigger-Token
Dieses Token kann sofort zur allgemeinen Variablenkonfiguration für eine Gruppe von Projekten hinzugefügt werden.
Gehen Sie zur Gruppe -> Einstellungen -> CI/CD -> Variablen und fügen Sie eine Variable hinzu DEPLOY_TOKEN mit Trigger-Token im Wert.
In diesem Abschnitt wird die Konfiguration zum Ausführen von Aufgaben bei der Bereitstellung mithilfe des nativen (spezifischen) und öffentlichen (gemeinsam genutzten) Läufers beschrieben.
Spezifischer Läufer
Ich benutze meine eigenen Läufer, weil es vor allem bequem, schnell und günstig ist.
Für Läufer empfehle ich Linux VDS mit 1 CPU, 2 GB RAM, 20 GB HDD. Ausgabepreis ~ 3000₽ pro Jahr.
Mein Läufer
Für den Runner habe ich eine VDS 4 CPU, 4 GB RAM, 50 GB SSD genommen. Es hat ca. 11000₽ gekostet und ich habe es nie bereut.
Ich habe insgesamt 7 Maschinen. 5 auf Aruba und 2 auf Ihor.
Wir haben also einen Läufer. Jetzt werden wir es einrichten.
Wir gehen über SSH auf die Maschine und installieren Java, Git, Maven, Gnupg2.
Erstellen Sie ein Verzeichnis für den Maven-Cache und weisen Sie Gruppenrechte zu runner
Sie können diesen Schritt überspringen, wenn Sie nicht vorhaben, mehrere Läufer auf demselben Computer auszuführen.
Runtime platform arch=amd64 os=linux pid=17594 revision=3001a600 version=11.10.0
Running in system-mode.
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://gitlab.com/
Please enter the gitlab-ci token for this runner:
REGISTRATION_TOKEN
Please enter the gitlab-ci description for this runner:
[ih1174328.vds.myihor.ru]: Deploy Runner
Please enter the gitlab-ci tags for this runner (comma separated):
deploy
Registering runner... succeeded runner=ZvKdjJhx
Please enter the executor: docker-ssh, parallels, virtualbox, docker-ssh+machine, kubernetes, docker, ssh, docker+machine, shell:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Überprüfen Sie, ob der Läufer registriert ist. Gehen Sie zu gitlab.com -> Deploy-Project -> Einstellungen -> CI/CD -> Runners -> Spezifische Runners -> Für dieses Projekt aktivierte Runners
Bildschirm
Hinzufügen trennen Service /etc/systemd/system/gitlab-deployer.service
Durch die Beantwortung von Fragen generieren wir einen Schlüssel. Ich habe meinen eigenen Namen und meine E-Mail-Adresse verwendet.
Geben Sie unbedingt das Passwort für den Schlüssel an. Artefakte werden mit diesem Schlüssel signiert.
gpg --gen-key
Überprüfung
gpg --list-keys -a
/home/gitlab-deployer/.gnupg/pubring.gpg
----------------------------------------
pub 4096R/00000000 2019-04-19
uid Petruha Petrov <[email protected]>
sub 4096R/11111111 2019-04-19
Hochladen unseres öffentlichen Schlüssels auf den Schlüsselserver
gpg --keyserver keys.gnupg.net --send-key 00000000
gpg: sending key 00000000 to hkp server keys.gnupg.net
Erstellen Sie ein Maven-Verzeichnis Quelle und mit dem Cache verknüpfen (kein Fehler machen)
Dieser Schritt kann übersprungen werden, wenn Sie nicht vorhaben, mehrere Läufer auf derselben Maschine auszuführen.
Zunächst müssen Sie einen GPG-Schlüssel erstellen. Installieren Sie dazu gnupg.
yum install -y gnupg
Durch die Beantwortung von Fragen generieren wir einen Schlüssel. Ich habe meinen eigenen Namen und meine E-Mail-Adresse verwendet. Geben Sie unbedingt das Passwort für den Schlüssel an.
Gehen Sie zu Projekteinstellungen -> Einstellungen -> CI/CD -> Variablen und speichern Sie in einer Variablen SETTINGS_SECURITY_XML die folgenden Zeilen:
Wir erstellen eine ziemlich einfache Docker-Datei, um Aufgaben bei der Bereitstellung mit der gewünschten Java-Version auszuführen. Unten finden Sie ein Beispiel für alpine.
FROM java:8u111-jdk-alpine
RUN apk add gnupg maven git --update-cache
--repository http://dl-4.alpinelinux.org/alpine/edge/community/ --allow-untrusted &&
mkdir ~/.m2/
Fügen Sie die Datei .gitlab-ci.yml zum Stammverzeichnis des Bereitstellungsprojekts hinzu
Das Skript stellt zwei sich gegenseitig ausschließende Bereitstellungsaufgaben dar. Spezifischer Runner bzw. Shared Runner.
.gitlab-ci.yml
stages:
- deploy
Specific Runner:
extends: .java_deploy_template
# Задача будет выполняться на вашем shell-раннере
tags:
- deploy
Shared Runner:
extends: .java_deploy_template
# Задача будет выполняться на публичном docker-раннере
tags:
- docker
# Образ из раздела GitLab Runner -> Shared Runner -> Docker
image: registry.gitlab.com/group/deploy-project:latest
before_script:
# Импортируем GPG ключ
- printf "${GPG_SECRET_KEY}" | gpg --batch --import
# Сохраняем maven конфигурацию
- printf "${SETTINGS_SECURITY_XML}" > ~/.m2/settings-security.xml
- printf "${SETTINGS_XML}" > ~/.m2/settings.xml
.java_deploy_template:
stage: deploy
# Задача сработает по триггеру, если передана переменная DEPLOY со значением java
only:
variables:
- $DEPLOY == "java"
variables:
# отключаем клонирование текущего проекта
GIT_STRATEGY: none
script:
# Предоставляем возможность хранения пароля в незашифрованном виде
- git config --global credential.helper store
# Сохраняем временные креды пользователя gitlab-ci-token
# Токен работает для всех публичных проектов gitlab.com и для проектов группы
- echo "https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com" >> ~/.git-credentials
# Полностью чистим текущую директорию
- rm -rf .* *
# Клонируем проект который, будем деплоить в Sonatype Nexus
- git clone ${DEPLOY_CI_REPOSITORY_URL} .
# Переключаемся на нужный коммит
- git checkout ${DEPLOY_CI_COMMIT_SHA} -f
# Если хоть один pom.xml содержит параметр autoReleaseAfterClose валим сборку.
# В противном случае есть риск залить сырые артефакты в maven central
- >
for pom in $(find . -name pom.xml); do
if [[ $(grep -q autoReleaseAfterClose "$pom" && echo $?) == 0 ]]; then
echo "File $pom contains prohibited setting: <autoReleaseAfterClose>";
exit 1;
fi;
done
# Если параметр DEPLOY_CI_COMMIT_TAG пустой, то принудительно ставим SNAPSHOT-версию
- >
if [[ "${DEPLOY_CI_COMMIT_TAG}" != "" ]]; then
mvn versions:set -DnewVersion=${DEPLOY_CI_COMMIT_TAG}
else
VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
if [[ "${VERSION}" == *-SNAPSHOT ]]; then
mvn versions:set -DnewVersion=${VERSION}
else
mvn versions:set -DnewVersion=${VERSION}-SNAPSHOT
fi
fi
# Запускаем задачу на сборку и деплой артефактов
- mvn clean deploy -DskipTests=true
In Java-Projekten, die in öffentliche Repositorys hochgeladen werden sollen, müssen Sie zwei Schritte hinzufügen, um die Release- und Snapshot-Versionen herunterzuladen.
.gitlab-ci.yml
stages:
- build
- test
- verify
- deploy
<...>
Release:
extends: .trigger_deploy
# Запускать задачу только пo тегу.
only:
- tags
Snapshot:
extends: .trigger_deploy
# Запускаем задачу на публикацию SNAPSHOT версии вручную
when: manual
# Не запускать задачу, если проставлен тег.
except:
- tags
.trigger_deploy:
stage: deploy
variables:
# Отключаем клонирование текущего проекта
GIT_STRATEGY: none
# Ссылка на триггер deploy-задачи
URL: "https://gitlab.com/api/v4/projects/<deploy project ID>/trigger/pipeline"
# Переменные deploy-задачи
POST_DATA: "
token=${DEPLOY_TOKEN}&
ref=master&
variables[DEPLOY]=${DEPLOY}&
variables[DEPLOY_CI_REPOSITORY_URL]=${CI_REPOSITORY_URL}&
variables[DEPLOY_CI_PROJECT_NAME]=${CI_PROJECT_NAME}&
variables[DEPLOY_CI_COMMIT_SHA]=${CI_COMMIT_SHA}&
variables[DEPLOY_CI_COMMIT_TAG]=${CI_COMMIT_TAG}
"
script:
# Не использую cURL, так как с флагами --fail --show-error
# он не выводит тело ответа, если HTTP код 400 и более
- wget --content-on-error -qO- ${URL} --post-data ${POST_DATA}
Bei dieser Lösung bin ich noch einen Schritt weiter gegangen und habe mich für die Verwendung einer CI-Vorlage für Java-Projekte entschieden.
Ausführlicher
Ich habe ein separates Projekt erstellt gitlab-ci in dem er die CI-Vorlage für Java-Projekte platzierte common.yml.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<!-- Генерация javadoc должна быть после фазы генерации ресурсов -->
<phase>prepare-package</phase>
<configuration>
<!-- Очень помогает в публичных проектах -->
<failOnError>true</failOnError>
<failOnWarnings>true</failOnWarnings>
<!-- Убирает ошибку поиска документации в target директории -->
<detectOfflineLinks>false</detectOfflineLinks>
</configuration>
</execution>
</executions>
</plugin>
Wenn Sie ein Modul haben, das kein Java enthält (zum Beispiel nur Ressourcen)
Oder Sie möchten Javadoc grundsätzlich nicht generieren, um dann zu helfen maven-jar-plugin
Wenn Sie ein Projekt mit mehreren Modulen haben und kein bestimmtes Modul in das Repository hochladen müssen, müssen Sie es zur pom.xml dieses Moduls hinzufügen nexus-staging-maven-plugin mit Fahne skipNexusStagingDeployMojo
Nach dem Hochladen sind Snapshot-/Release-Versionen in verfügbar Staging-Repositorys
<repositories>
<repository>
<id>SonatypeNexus</id>
<url>https://oss.sonatype.org/content/groups/staging/</url>
<!-- Не надо указывать флаги snapshot/release для репозитория -->
</repository>
</repositories>
Mehr Pluspunkte
Eine sehr umfangreiche Liste von Zielen für die Arbeit mit dem Nexus-Repository (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
Automatische Release-Prüfung auf Herunterladbarkeit in Maven Central
Wenn das Tag gesetzt ist, wird die entsprechende Aufgabe im Bereitstellungsprojekt automatisch ausgelöst, um die Release-Version auf Nexus hochzuladen (Beispiel).
Das Beste daran ist, dass die Nahfreigabe automatisch in Nexus ausgelöst wird.
[INFO] Performing remote staging...
[INFO]
[INFO] * Remote staging into staging profile ID "9043b43f77dcc9"
[INFO] * Created staging repository with ID "orgtouchbit-1037".
[INFO] * Staging repository at https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1037
[INFO] * Uploading locally staged artifacts to profile org.touchbit
[INFO] * Upload of locally staged artifacts finished.
[INFO] * Closing staging repository with ID "orgtouchbit-1037".
Waiting for operation to complete...
.........
[INFO] Remote staged 1 repositories, finished with success.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Shields4J 1.0.0 .................................... SUCCESS [ 9.603 s]
[INFO] test-core .......................................... SUCCESS [ 3.419 s]
[INFO] Shields4J client ................................... SUCCESS [ 9.793 s]
[INFO] TestNG listener 1.0.0 .............................. SUCCESS [01:23 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:47 min
[INFO] Finished at: 2019-04-21T04:05:46+03:00
[INFO] ------------------------------------------------------------------------
Und wenn etwas schiefgeht, wird die Aufgabe scheitern
[INFO] Performing remote staging...
[INFO]
[INFO] * Remote staging into staging profile ID "9043b43f77dcc9"
[INFO] * Created staging repository with ID "orgtouchbit-1038".
[INFO] * Staging repository at https://oss.sonatype.org:443/service/local/staging/deployByRepositoryId/orgtouchbit-1038
[INFO] * Uploading locally staged artifacts to profile org.touchbit
[INFO] * Upload of locally staged artifacts finished.
[INFO] * Closing staging repository with ID "orgtouchbit-1038".
Waiting for operation to complete...
.......
[ERROR] Rule failure while trying to close staging repository with ID "orgtouchbit-1039".
[ERROR]
[ERROR] Nexus Staging Rules Failure Report
[ERROR] ==================================
[ERROR]
[ERROR] Repository "orgtouchbit-1039" failures
[ERROR] Rule "signature-staging" failures
[ERROR] * No public key: Key with id: (1f42b618d1cbe1b5) was not able to be located on <a href=http://keys.gnupg.net:11371/>http://keys.gnupg.net:11371/</a>. Upload your public key and try the operation again.
...
[ERROR] Cleaning up local stage directory after a Rule failure during close of staging repositories: [orgtouchbit-1039]
[ERROR] * Deleting context 9043b43f77dcc9.properties
[ERROR] Cleaning up remote stage repositories after a Rule failure during close of staging repositories: [orgtouchbit-1039]
[ERROR] * Dropping failed staging repository with ID "orgtouchbit-1039" (Rule failure during close of staging repositories: [orgtouchbit-1039]).
[ERROR] Remote staging finished with a failure: Staging rules failure!
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Shields4J 1.0.0 .................................... SUCCESS [ 4.073 s]
[INFO] test-core .......................................... SUCCESS [ 2.788 s]
[INFO] Shields4J client ................................... SUCCESS [ 3.962 s]
[INFO] TestNG listener 1.0.0 .............................. FAILURE [01:07 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
Dadurch bleibt uns nur noch eine Wahl. Oder diese Version löschen oder veröffentlichen.
Nach der Veröffentlichung, nach einiger Zeit, werden die Artefakte verfügbar sein
Offtopic
Für mich war es eine Offenbarung, dass Maven andere öffentliche Repositories indiziert.
Ich musste robots.txt hochladen, weil es mein altes Repository indizierte.
Ein separates Bereitstellungsprojekt, in dem Sie mehrere CI-Aufgaben zum Hochladen von Artefakten in öffentliche Repositorys für verschiedene Entwicklungssprachen implementieren können.
Das Bereitstellungsprojekt ist von externen Eingriffen isoliert und kann nur von Benutzern mit den Rollen „Eigentümer“ und „Betreuer“ geändert werden.
Ein separater spezifischer Runner mit einem „heißen“ Cache, um nur Bereitstellungsaufgaben auszuführen.
Veröffentlichung von Snapshot-/Release-Versionen in einem öffentlichen Repository.
Automatische Prüfung der Release-Version auf Veröffentlichungsbereitschaft in Maven Central.
Schutz vor der automatischen Veröffentlichung von „Rohversionen“ in Maven Central.
Erstellen und veröffentlichen Sie Snapshot-Versionen „auf Knopfdruck“.
Einzelnes Repository zum Abrufen von Snapshot-/Release-Versionen.
Allgemeine Pipeline zum Erstellen/Testen/Veröffentlichen eines Java-Projekts.
Das Einrichten von GitLab CI ist kein so kompliziertes Thema, wie es auf den ersten Blick scheint. Es reicht aus, CI ein paar Mal schlüsselfertig einzurichten, und jetzt sind Sie in dieser Angelegenheit alles andere als ein Amateur. Darüber hinaus ist die GitLab-Dokumentation sehr redundant. Haben Sie keine Angst, den ersten Schritt zu tun. Die Straße erscheint unter den Schritten der Person, die geht (ich weiß nicht mehr, wer das gesagt hat :)
Über Feedback freue ich mich.
Im nächsten Artikel zeige ich Ihnen, wie Sie GitLab CI einrichten, um Integrationstestaufgaben wettbewerbsfähig auszuführen (Testdienste mit Docker-Compose ausführen), wenn Sie nur einen Shell-Runner haben.