ProHoster > Blog > administration > Configuration de GitLab CI pour télécharger un projet Java sur Maven Central
Configuration de GitLab CI pour télécharger un projet Java sur Maven Central
Cet article est destiné aux développeurs Java qui ont besoin de publier rapidement leurs produits dans les référentiels centraux sonatype et/ou maven à l'aide de GitLab. Dans cet article, je parlerai de la configuration de gitlab-runner, gitlab-ci et maven-plugin pour résoudre ce problème.
Conditions préalables:
Stockage sécurisé des clés mvn et GPG.
Exécution sécurisée des tâches publiques de CI.
Téléchargement d'artefacts (version/instantané) vers des référentiels publics.
Vérification automatique des versions pour publication dans Maven Central.
Une solution générale pour télécharger des artefacts vers un référentiel pour plusieurs projets.
Une description détaillée du mécanisme de publication d'artefacts dans Maven Central via le service d'hébergement de référentiel Sonatype OSS a déjà été décrite dans cet article par utilisateur Googleplex, je ferai donc référence à cet article aux bons endroits.
Pré-inscrivez-vous pour Sonatype JIRA et ouvrez un ticket pour ouvrir le dépôt (lisez la section pour plus de détails Créer un ticket sur Sonatype JIRA). Après avoir ouvert le référentiel, la paire login/mot de passe de JIRA (ci-après dénommé le compte Sonatype) sera utilisée pour télécharger des artefacts sur Sonatype nexus.
Si vous utilisez la console Linux pour générer une clé GPG (gnupg/gnupg2), alors vous devez installer outils-rng pour générer de l'entropie. Sinon, la génération des clés peut prendre beaucoup de temps.
Tout d'abord, vous devez créer et configurer un projet dans lequel le pipeline sera stocké pour déployer les artefacts. J'ai nommé mon projet simplement et sans complication - déployer
Après avoir créé le référentiel, vous devez restreindre l'accès pour modifier le référentiel.
Accédez au projet -> Paramètres -> Référentiel -> Branches protégées. Nous supprimons toutes les règles et ajoutons une seule règle avec Wildcard * avec le droit de pousser et de fusionner uniquement pour les utilisateurs ayant le rôle de mainteneur. Cette règle fonctionnera pour tous les utilisateurs de ce projet et du groupe auquel ce projet appartient.
S'il y a plusieurs responsables, alors la meilleure solution serait en principe de limiter l'accès au projet.
Accédez au projet -> Paramètres -> Général -> Visibilité, fonctionnalités du projet, autorisations et définissez la visibilité du projet sur Chef.
J'ai un projet accessible au public, puisque j'utilise mon propre GitLab Runner et que moi seul ai accès pour modifier le référentiel. Eh bien, en fait, ce n’est pas dans mon intérêt d’afficher des informations privées dans les journaux publics des pipelines.
Renforcer les règles de changement de référentiel
Accédez au projet -> Paramètres -> Référentiel -> Règles Push et définissez la restriction Committer, vérifiez si l'auteur est un utilisateur GitLab. Je recommande également de configurer valider la signatureet définissez l'indicateur Rejeter les validations non signées.
Ensuite, vous devez configurer un déclencheur pour lancer des tâches
Accédez au projet -> Paramètres -> CI / CD -> Déclencheurs de pipeline et créez un nouveau jeton de déclenchement
Ce token peut être immédiatement ajouté à la configuration générale des variables d'un groupe de projets.
Allez dans le groupe -> Paramètres -> CI / CD -> Variables et ajoutez une variable DEPLOY_TOKEN avec jeton de déclenchement en valeur.
Cette section décrit la configuration pour exécuter des tâches lors du déploiement à l'aide de votre propre exécuteur (spécifique) et public (partagé).
Coureur spécifique
J'utilise mes propres patins parce que, tout d'abord, c'est pratique, rapide et bon marché.
Pour un coureur, je recommande un VDS Linux avec 1 CPU, 2 Go de RAM, 20 Go de disque dur. Le prix d'émission est de ~3000₽ par an.
Mon coureur
Pour le coureur, j'ai pris un processeur VDS 4, 4 Go de RAM, 50 Go de SSD. J'ai coûté ~11000 XNUMX₽ et je ne l'ai jamais regretté.
J'ai un total de 7 machines. 5 sur Aruba et 2 sur Ihor.
Nous avons donc un coureur. Nous allons maintenant le configurer.
Nous allons sur la machine via SSH et installons Java, git, maven, gnupg2.
Créez un répertoire pour le cache maven et attribuez des autorisations de groupe runner
Vous pouvez ignorer ce point si vous ne prévoyez pas d'exécuter plusieurs exécuteurs sur une seule machine.
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!
Nous vérifions que le coureur est inscrit. Allez sur le site gitlab.com -> déployer-project -> Paramètres -> CI/CD -> Runners -> Specific Runners -> Runners activés pour ce projet
Écran
Ajouter séparé service /etc/systemd/system/gitlab-deployer.service
Nous générons une clé en répondant aux questions. J'ai utilisé mon propre nom et mon adresse e-mail.
Assurez-vous de spécifier le mot de passe de la clé. Les artefacts seront signés avec cette clé.
gpg --gen-key
Chèque
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
Télécharger notre clé publique sur le serveur de clés
gpg --keyserver keys.gnupg.net --send-key 00000000
gpg: sending key 00000000 to hkp server keys.gnupg.net
Connectez-vous en tant qu'utilisateur gitlab-deployer
su gitlab-deployer
Créer un répertoire maven dépôt et lien vers le cache (ne vous y trompez pas)
Vous pouvez ignorer ce point si vous ne prévoyez pas d'exécuter plusieurs exécuteurs sur une seule machine.
Tout d'abord, vous devez créer une clé GPG. Pour ce faire, installez gnupg.
yum install -y gnupg
Nous générons une clé en répondant aux questions. J'ai utilisé mon propre nom et mon adresse e-mail. Assurez-vous de spécifier le mot de passe de la clé.
Nous créons un Dockerfile assez simple pour exécuter des tâches de déploiement avec la version requise de Java. Vous trouverez ci-dessous un exemple pour alpin.
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/
Ajoutez le fichier .gitlab-ci.yml à la racine du projet de déploiement
Le script présente deux tâches de déploiement mutuellement exclusives. Coureur spécifique ou coureur partagé respectivement.
.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
Dans les projets Java censés être téléchargés sur des référentiels publics, vous devez ajouter 2 étapes pour télécharger les versions Release et Snapshot.
.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}
Dans cette solution, je suis allé un peu plus loin et j'ai décidé d'utiliser un modèle CI pour les projets Java.
Plus de détails
J'ai créé un projet séparé gitlab-ci dans lequel j'ai placé un modèle CI pour les projets Java commun.yml.
Installe les modules dans le référentiel local.
Très utile pour la vérification locale des solutions dans d'autres projets, ainsi qu'une somme de contrôle.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<executions>
<execution>
<id>install-project</id>
<!-- Если у вас многомодульный проект с деплоем родительского помика -->
<phase>install</phase>
<!-- Явно указываем файлы для локальной установки -->
<configuration>
<file>target/${project.artifactId}-${project.version}.jar</file>
```target/${project.artifactId}-${project.version}-sources.jar</sources>
<pomFile>dependency-reduced-pom.xml</pomFile>
<!-- Принудительное обновление метаданных проекта -->
<updateReleaseInfo>true</updateReleaseInfo>
<!-- Контрольные суммы для проверки целостности -->
<createChecksum>true</createChecksum>
</configuration>
</execution>
</executions>
</plugin>
<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>
Si vous disposez d'un module qui ne contient pas de java (par exemple uniquement des ressources)
Ou vous ne voulez pas générer de javadoc en principe, alors aidez maven-jar-plugin
Si vous avez un projet multi-modules et que vous n'avez pas besoin de télécharger un module spécifique dans le référentiel, vous devez alors ajouter nexus-staging-maven-plugin avec drapeau skipNexusStagingDeployMojo
Après le téléchargement, les versions instantanées/release sont disponibles dans référentiels de préparation
<repositories>
<repository>
<id>SonatypeNexus</id>
<url>https://oss.sonatype.org/content/groups/staging/</url>
<!-- Не надо указывать флаги snapshot/release для репозитория -->
</repository>
</repositories>
Plus d'atouts
Une liste très riche d'objectifs pour travailler avec le référentiel Nexus (mvn help:describe -Dplugin=org.sonatype.plugins:nexus-staging-maven-plugin).
Vérification automatique de la version pour le téléchargement sur Maven Central
Lorsqu'une balise est installée, la tâche correspondante dans le projet de déploiement est automatiquement déclenchée pour télécharger la version finale sur Nexus (exemple).
La meilleure partie est que la version rapprochée est automatiquement déclenchée dans Nexus.
[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] ------------------------------------------------------------------------
Et si quelque chose ne va pas, la tâche échouera définitivement
[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] ------------------------------------------------------------------------
En conséquence, nous n’avons qu’un seul choix. Soit supprimez cette version, soit publiez-la.
Après leur publication, après un certain temps, les artefacts seront disponibles
offtop
Ce fut une découverte pour moi que Maven indexe d'autres référentiels publics.
J'ai dû ajouter robots.txt car il indexait mon ancien référentiel.
Un projet de déploiement distinct dans lequel vous pouvez implémenter plusieurs tâches CI pour télécharger des artefacts vers des référentiels publics pour différents langages de développement.
Le projet Deploy est isolé des interférences extérieures et ne peut être modifié que par les utilisateurs disposant des rôles Propriétaire et Mainteneur.
Un exécuteur spécifique distinct avec un cache « chaud » pour exécuter uniquement les tâches de déploiement.
Publication de versions d'instantanés/versions dans un référentiel public.
Vérification automatique de la version finale pour la préparation à la publication dans Maven Central.
Protection contre la publication automatique de versions « brutes » dans maven central.
Créez et publiez des versions instantanées « en un clic ».
Un référentiel unique pour obtenir des versions instantanées/release.
Pipeline général pour créer/tester/publier un projet Java.
La configuration de GitLab CI n'est pas un sujet aussi compliqué qu'il y paraît à première vue. Il suffit de mettre en place CI clé en main à plusieurs reprises, et maintenant vous êtes loin d'être un amateur en la matière. De plus, la documentation GitLab est très redondante. N'ayez pas peur de faire le premier pas. La route apparaît sous les pas de la personne qui marche (je ne me souviens plus qui l'a dit :)
Je serai heureux de recevoir des commentaires.
Dans le prochain article, je parlerai de la façon de configurer GitLab CI pour exécuter des tâches avec des tests d'intégration de manière compétitive (exécuter les services testés à l'aide de docker-compose) si vous n'avez qu'un seul exécuteur de shell.