D’Apache Archiva à Sonatype Nexus – La migration

Passons à l’action aujourd’hui avec la migration en elle même. Comment avons-nous fait ? A quoi faut-il faire attention ?

Avant de migrer …

Petit topo sur la solution existante. Avant la migration, notre environnement ressemble à peu de choses près à ceci :

L'environnement avant migration
L'environnement avant migration

Nous hébergeons nos référentiels internes dans ce que Archiva appelle des managed repositories. On en retrouve un pour les releases, un pour les snapshots et un dernier pour les librairies tierces (celles des éditeurs en général).
Pour gérer le cache des référentiels externes (déclarés en tant que “remote repositories”) nous utilisons deux autres référentiels internes ( releases et snapshots).

Archiva expose deux groupes : L’un pour accéder à toutes les releases, l’autre pour les snapshots. Nous n’avons jamais mis en place de groupe qui expose les deux types d’artifacts ensembles car Archiva a souvent eu des problèmes pour fusionner les descripteurs présents sur les référentiels (maven-metadata.xml).

Les groupes permettent de simplifier énormément la configuration de Maven en évitant de déclarer tous les référentiels. Encore plus important, les groupes optimisent grandement les performances de Maven car pour un artifact manquant celui-ci ne fait qu’une requête vers le groupe qui la distribue sur tous les référentiels qu’il masque. Interroger individuellement chaque référentiel est une perte de temps inexorable.

Les clients des référentiels (utilisateurs et intégration continue) y accèdent en configurant ainsi Maven :
[xml]
default


central
http://serveur.entreprise.fr/archiva/repository/releases/
true
false


snapshots
http://serveur.entreprise.fr/archiva/repository/snapshots/
false
true

central
http://serveur.entreprise.fr/archiva/repository/releases/
true
false
snapshots
http://serveur.entreprise.fr/archiva/repository/snapshots/
false
true

default


[/xml]

En redéfinissant l’adresse du serveur central (normalement situé ici : http://repo1.maven.org/maven2/) Maven recherche les artifacts de type release dans notre groupe dédié sur archiva. Cela nous donne alors accès autant aux releases internes qu’externes. De la même manière le référentiel additionnel snapshots nous permet d’obtenir les versions en cours de développement.

Les contraintes

La migration n’est pas aisée lorsque l’on a 200 développeurs qui utilisent le serveur au quotidien.

Premièrement, il faut s’assurer de stopper le gestionnaire d’artifacts un minimum de temps (ou alors venir le faire en dehors des heures de travail … gloups !!!). Arrêter l’intégration continue temporairement n’est pas un problème majeur. Par contre, demander aux équipes d’utiliser Maven en mode offline et de ne plus utiliser les référentiels est plus difficile. En général, Il ne faut pas longtemps avant qu’une personne ait besoin de télécharger une librairie ou qu’un projet doive faire une release.

Deuxièmement, il est impératif de garder la compatibilité avec les paramétrages Maven actuels. Compte tenu du nombre de projets et de développeurs il est impossible de reconfigurer tous les références aux référentiels dans le paramétrage Maven. Il faudrait impacter tous les projets pour modifier les urls d’upload (distributionManagement) et tous les développeurs pour les paramètres de téléchargement (repositories).

La démarche

Pour limiter les coûts nous avons décidé de ne pas faire tous nos tests sur un environnement de recette. Il aurait fallu dupliquer tout l’environnement d’intégration continue aujourd’hui en production afin d’avoir des résultats probants.
Une fois les quelques tests de base effectués sur l’outil, la véritable épreuve du feu se joue sur la volumétrie et la montée en charge du serveur.
Comme nous changeons de produit, nous pouvons facilement faire tourner les deux serveurs en parallèle (tant que les ressources système nous le permettent). Nous sommes donc partis sur la stratégie de faire un “parallel run” Archiva / Nexus pour ensuite basculer les services les uns après les autres (en gardant la possibilité de revenir en arrière au cas où).
Nous avons assez de place pour recréer les caches des référentiels externes (cela ne représente que quelques Go). Il n’y a que les référentiels internes que nous ne pouvons pas dupliquer (ils sont trop gros, et cela poserait un problème de cohérence). Nous ne voulons pas non plus partager ces référentiels internes entre les deux produits afin de ne pas risquer d’avoir des accès concurrents. Nous commencerons donc notre migration en laissant les repositories internes sur Archiva puis nous les migrerons à la dernière minute sur Nexus lors de la bascule finale.

Pour la compatibilité des urls nous allons utiliser des règles de réécritures (rewriting rules) sur le serveur Apache que nous avons en frontal. Il fera le passage entre les anciennes url et les nouvelles de manière transparente.

Installation de Nexus

Nous effectuons une installation classique de Nexus 1.3.2 en version opensource standalone en adaptant uniquement quelques paramètres comme le port HTTP, les chemins des répertoires des données et des logs pour se conformer à l’organisation de notre serveur. Tout cela se fait en très très peu de temps puisque contrairement à Archiva nous n’avons pas à créer de base de données. Notre serveur Nexus est rapidement en route et prêt à être configuré.

Configuration des groupes et référentiels externes

Nous commençons la configuration de Nexus par les référentiels externes (proxy repositories). Nous rajoutons aussi pour les besoins de la migration les caches vers nos référentiels internes toujours hébergés sur Archiva.

L’IHM est assez bien faite ce qui rend la saisie des 20 référentiels externes supportable. Merci à ExtJS !

Contrairement à Archiva qui propose de stocker les artifacts de plusieurs référentiels externes dans un même référentiel local, Nexus stocke le contenu de chacun dans un répertoire dédié.

Concernant le paramétrage des référentiels externes, il faut noter que l’on perd la possibilité offerte par Archiva de gérer des listes blanches ou noires des artifacts à récupérer sur les référentiels externes. C’est la notion de “routes” qui est utilisée dans Nexus pour faire ce type de filtrage. Malheureusement elle ne s’applique aujourd’hui qu’au niveau d’un groupe et non pas au niveau d’un référentiel.
Puisque les quelques listes que nous avons dans Archiva ne sont là que pour des questions de performance (ne pas interroger un référentiel dans lequel on sait qu’un artifact n’est pas), nous avons décidé de ne pas dupliquer cette configuration sur Nexus en attendant de voir si cela posait de réels problèmes.

Lors de notre paramétrage nous faisons face à une autre déconvenue. Comme nous devons faire proxy pour des référentiels hébergés en interne (pour le référentiel exposé par le serveur sonar et pour Archiva pendant la migration) nous avons été obligés de déclarer le proxy web de l’entreprise sur chaque référentiel externe. Il est impossible en définissant le proxy web dans la configuration globale de Nexus de la désactiver sur un référentiel donné.

Alors que notre configuration des référentiels externes était quasiment terminée, nous trébuchons sur un os de taille. Nous découvrons qu’il est impossible de faire proxy de référentiels qui sont au format maven 1 (chez atlassian et dev.java.net par exemple).
Pour y parvenir nous devons créer des référentiels virtuels (virtual repository) qui servent à Nexus pour convertir un référentiel d’un format vers un autre. Manque de chance deux bugs (NEXUS-1909, NEXUS-1910) nous empêchent de le faire.
Heureusement pour nous, l’équipe Nexus a su être très réactive et elle a pu incorporer les corrections à ces bugs dans la version 1.3.3 qu’elle publiait le lendemain de notre découverte. Sans cela il fallait bien avouer que l’on n’aurait probablement pas continué nos tests sur Nexus.
Nous avons donc mis à jour notre installation ce qui en passant nous a permis de voir que l’opération était très aisée puisque l’application, sa configuration et ses données sont très bien séparées.

Nous finalisons la configuration de Nexus par la création des groupes. Cette la même notion que celle d’Archiva (qui a d’ailleurs copié dessus).
La gestion d’un groupe est par contre assez mal faite en terme d’ergonomie. Il nous faut sélectionner les référentiels à rajouter au groupe puis l’ordonner dans une liste. L’ordre est très important car Nexus l’utilisera pour rechercher les artifacts. Il faut donc placer les référentiels avec des releases avant des snapshots et les référentiels locaux avant les référentiels externes. Le problème c’est que cette liste n’affiche que le nom de chaque référentiel (et encore ce nom est souvent tronqué faute de place). Vous avez donc intérêt à faire très attention au nommage des référentiels pour vous y retrouver lorsqu’il faut en classer plusieurs dizaines dans un groupe.

Nous suivons les recommandations de Nexus en créant un groupe unique qui expose toutes les releases et tous les snapshots. (Ce qui nous évitera en plus de nous battre deux fois avec l’écran de configuration d’un groupe).

A partir de ce moment là nous sommes censés être en mesure de récupérer tous les artifacts nécessaires à la construction de nos projets depuis Nexus.

Après quelques tests unitaires concluants nous validons l’ensemble avec notre serveur d’intégration continue.
Nous supprimons son référentiel local et mettons à jour sa configuration :
[xml]




nexus
*
http://serveur.entreprise.fr/nexus/content/groups/public/

default




central
http://central
true
true

central
http://central
true
true


default


[/xml]

A noter : Je ne suis pas du tout fan de l’utilisation du mirroir * qui oblige à mettre dans le même groupe les releases et les snapshots. C’est cependant la seule solution aujourd’hui puisqu’il n’y a pas la possibilité avec les miroirs de dire à Maven de rechercher les releases à un emplacement et les snapshots à un autre. Je trouve cette utilisation dangereuse car, par exemple, lorsque vous demandez un plugin sans définir sa version (un plugin en ligne de commande par exemple comme eclipse:eclipse ou archetype:generate) vous risquez de récupérer une version snapshot. Il faut donc prendre à la lettre la recommandation de Maven qui est de définir dans son POM (ou par héritage) toutes les versions des plugins que l’on utilise pour s’éviter des surprises (ce qui ne me gène pas dans notre contexte puisque la recommandation est suivie par tous les projets en utilisant un pom parent qui fait cette définition pour eux).

L’environnement Archiva et Nexus en parallèle est opérationnel.

Nexus / Archiva en parallèle
Nexus / Archiva en parallèle

Rien ne changent pour les développeurs qui continuent d’utiliser Archiva. Le serveur d’intégration continue récupère par contre tous les artifacts nécessaires depuis Nexus.

Tuning

Au bout de quelques jours de tests on remarque que Nexus a parfois du mal à servir rapidement les artifacts. On s’intéresse donc aux paramétrages un peu plus avancés.

Les routes permettent lorsque l’on demande un artifact à un groupe de restreindre la liste des référentiels que Nexus doit consulter dans le groupe donné. Cela peut se faire via des autorisations ou des interdictions.

La route que nous créons en premier est celle qui concerne les artifacts de nos projets (.*/fr/monentreprise/.*) pour lesquels Nexus doit renvoyer automatiquement vers les proxy des référentiels gérés pour l’instant par Archiva. Une fois la mise en production finale effectuée, celui-ci pointe uniquement vers les référentiels locaux.

Nous ajoutons aussi des règles pour .*/org/apache/.* et .*/org/codehaus/.* qui sont massivement utilisées par Maven afin que les artifacts ne soient recherchés que sur le référentiel central et sur les référentiels des snapshots de chaque communauté.

Tout cela donne déjà un bon coup de boost à notre Nexus.
Après plusieurs jours d’utilisation pour les téléchargements de l’intégration continue, le serveur Nexus tourne parfaitement. Nous préparons donc la deuxième partie de la migration : La mise en place des référentiels internes sur Nexus.

Configuration des référentiels internes et de la sécurité

Pour reprendre les référentiels internes hébergés par Archiva sur Nexus il nous faut commencer par créer les référentiels internes (hosted repositories). Nous plaçons les répertoires de stockage des artifacts à un emplacement différent de celui d’Archiva pour ne pas laisser les deux produits accéder aux même données. Nous reprenons les identifiants de référentiels utilisés dans Archiva afin de pouvoir facilement créer des règles de réécriture sur notre frontal Apache.

Nous passons un peu de temps pour comprendre le mécanisme de sécurité de Nexus. Ce dernier est tellement fin que les paramétrages basiques sont vite compliqués.

Nous commençons par créer des privilèges sur les référentiels internes (lecture, écriture, mis à jour). Nous créons des rôles qui regroupent un certain nombre de privilèges sur certains référentiels. Dans notre cas un rôle pour déployer sur les référentiels des releases (pour les équipes projets) et un rôle pour déployer sur les référentiels de snapshots (pour l’intégration continue).
Nous terminons en créant les utilisateurs avec les rôles définis ci-dessus sans oublier le rôle pour lire sur tous les référentiels.

Les référentiels internes étant prêts il ne nous reste plus qu’à les basculer sur Nexus et éteindre Archiva.

La bascule finale

Pour conserver la compatibilité des urls entre Archiva et Nexus nous faisons deux choses.
Pour les accès en écriture sur les référentiels nous définissons une à une la règle qui transforme l’adresse d’Archiva vers Nexus.
Exemple de configuration Apache :
[text]
####
# Compatibilité ARCHIVA
####
RewriteRule ^/archiva/repository/internal-releases/(.*) http://localhost/nexus/content/repositories/internal-releases/$1 [P]
RewriteRule ^/archiva/repository/internal-snapshots/(.*) http://localhost/nexus/content/repositories/internal-snapshots/$1 [P]
RewriteRule ^/archiva/repository/third-parties/(.*) http://localhost/nexus/content/repositories/third-parties/$1 [P]

[/text]
Pour les accès en lecture qui se faisaient sur archiva avec des groupes nous transférons la demande vers le groupe unique que nous avons sur Nexus.
Exemple de configuration Apache :
[text]
####
# Accès aux groupes
####
RewriteRule ^/archiva/repository/[a-z\-]+/(.*) http://localhost/nexus/content/groups/public/$1 [P]
[/text]
La bascule est prête :

  1. Arrêt de Nexus,
  2. Arrêt d’Archiva,
  3. Installation des règles de réécriture sur le frontal Apache,
  4. Déplacement du contenu des référentiels internes depuis Archiva vers Nexus,
  5. Redémarrage de Nexus.

Le jour J nous avons fait la bascule en moins de 10 minutes. Nexus a pris quelques heures à digérer nos centaines de Go de données mais sans pour autant que cela diminue énormément ses performances.

Environnement après migration
Environnement après migration

Malgré les quelques écueils rencontrés, la migration n’aura pas été d’une grande complexité technique. Elle s’est déroulée sur deux semaines et nous en a coûté moins de la moitié en temps consommé.

Nous étudions aujourd’hui comment régler les taches en arrière plan. Sonatype a fait un très gros effort sur la documentation du produit. Celle-ci permet de découvrir rapidement l’ensemble de ses fonctionnalités. Cependant on reste vite sur notre faim lorsque l’on veut dépasser le cadre du guide de référence. Il manque encore quelques bons conseils sur la mise en œuvre de l’outil dans un environnement d’entreprise :

  • Quelles tâches planifiées faut-il utiliser ?
  • Dans quels cas ?
  • Quand ?
  • Pourquoi réparer les metadonnées ?
  • Pourquoi supprimer les caches ?
  • Comment gère-t’on la poubelle ?

Je n’hésiterai pas à remonter ces manques à l’équipe Nexus pour qu’elle enrichisse la documentation ( C’est Tim qui va être content 🙂 ).

Ainsi se termine ce retour d’expérience les mains dans le cambouis pour migrer d’Archiva vers Nexus. Sur le prochain et dernier article sur le sujet, à découvrir dès demain, vous verrez quel est notre bilan un peu plus de deux semaines après la migration.

11 thoughts on “D’Apache Archiva à Sonatype Nexus – La migration”

  1. Salut Emmanuel. Comme tu peux le voir j’ai un problème pour afficher le XML dans les commentaires.
    Dans ton cas internal-repository c’est pour les releases, et ensuite foo c’est apache-snapshots, codehaus-snapshots, et tout ce que l’on a besoin ?
    Ce qui m’ennuie avec cela c’est de lister tous les repo de snapshots surtout que comme les ids ne sont pas standardiser tu peux te retrouver avec du codehaus-snapshots, codehaus.snapshots, ….

  2. J’ai lu l’article avec attention étant passé par la, il y a quelques mois déjà. J’ai été étonne de la mention des bugs pour la virtualisation des repos m1 car j’ai pu le faire sans soucis sur celui de javadev (pour le jaxws notamment). D’ailleurs j’ai mis une règle afin de ne prendre les jaxws que depuis ce virtual.

    Pour les groupes, j’en ai défini 2, l’un pour toutes les releases et l’autre pour tous les snapshots. Il faudra que je rajoute ça sur mon bloc d’ailleurs.

    Bel article en tout cas, bravo.

  3. Il y a un problème avec les tags HTML dans les commentaires. On ne comprend pas ton commentaire philippe. Tu peux le refaire peut etre en remplacant par les caracteres html encodés. Je vais me renseigner si ce bug est connu sur wordpress.

  4. Hello très bon article!
    Je l’ai trouvé malheureusement juste après ma phase de migration, mais la méthodo est à peu près la même.

    Par contre comment as tu gérer la migration des utilisateurs Archiva vers Nexus (et leurs mots de passe)?

  5. Bonjour,

    J’ai une question concernant essentiellement Nexus.
    actuellement j’ai un nexus qui tourne sur une machine M1 avec la version 1.7.0 et je voudrais déplacer le repository sur une autre machine avec la nouvelle version de nexus 1.9.2.3.
    Avez-vous une idée sur la méthode de basculement ?
    Merci de votre réponse.

    1. Bonjour,

      Je pense que ca peut se faire assez facilement :

          Copier tout le contenu du repertoire sonatype-work (supprimer les index et timeline pour gagner de la place et reindexer l’ensemble)
          Installer la nouvelle version, maj les plugins optionnels installés si necessaires et reutiliser le sonatype-work

      Nexus devrait upgrader sa config et repartir normalement.

Comments are closed.