Aller au contenu

Migrer depuis Sonatype Nexus

Ce guide vous accompagne dans le déplacement d'un dépôt APT existant de Sonatype Nexus Repository Manager vers Repod. Le processus exporte chaque asset .deb de Nexus via son API REST, les importe dans Repod avec un script d'upload en masse, met à jour les machines clientes, puis bascule l'URL — le tout sans interrompre un seul apt install pendant la transition.

Vous migrez aussi un dépôt Maven, PyPI ou npm depuis Nexus ?

Repod héberge nativement des dépôts Maven, PyPI, npm et Docker/OCI aux côtés d'APT — voir Formats de paquets. Pour ceux-ci, pointez votre configuration existante mvn deploy / twine upload / npm publish vers Repod (Configuration des clients) et republiez depuis votre pipeline de build, plutôt que d'adapter le script d'export REST spécifique aux .deb de ce guide.


1. Quand migrer

Ce guide est la bonne approche quand :

  • Nexus est utilisé exclusivement (ou principalement) pour l'hébergement APT, et que le reste de ses fonctionnalités — Maven, npm, Docker — est inutilisé ou géré ailleurs.
  • Votre équipe souhaite un scan de sécurité intégré (rapports CVE, manifestes SBOM) sans maintenir un pipeline séparé.
  • Vous voulez une empreinte opérationnelle plus légère : Repod tourne comme une seule stack Docker Compose, sans tas Java à régler.

Si vous utilisez toujours Nexus pour d'autres types d'artefacts, vous pouvez faire tourner les deux systèmes en parallèle et migrer les dépôts APT un à la fois.


2. Avant de commencer — checklist d'inventaire

Rassemblez ces informations depuis Nexus avant de toucher à toute configuration :

  • Nombre de dépôts APT (chaque dépôt APT « hosted » Nexus devient une distribution Repod).
  • Distributions et composants dans chaque dépôt (par ex. jammy main, focal restricted).
  • Nombre approximatif de paquets et taille disque totale (du -sh sur le blob store Nexus, ou le contrôle de santé du dépôt dans l'interface Nexus).
  • Nombre de machines clientes consommant le dépôt, et comment leurs entrées sources.list sont gérées (Ansible, Chef, cloud-init, manuel).
  • Si Nexus impose actuellement l'authentification sur le chemin de lecture — si c'est le cas, les clients ont déjà un jeton ou un nom d'utilisateur/mot de passe dans leur configuration apt.
  • Vos identifiants admin Nexus et l'URL de base (par ex. https://nexus.example.com).

Tip

Exportez la liste des dépôts Nexus depuis Administration → Repositories au format CSV avant de commencer. Elle devient votre feuille de suivi pour la migration.


3. Étape 1 — Exporter les fichiers .deb depuis Nexus

Nexus expose une API de composants paginée. Le script ci-dessous itère à travers chaque page et télécharge chaque asset .deb vers un répertoire de staging local.

#!/usr/bin/env bash
# nexus-export.sh — download all .deb assets from a Nexus APT repository
set -euo pipefail

NEXUS_URL="https://nexus.example.com"
REPO_NAME="apt-repo"           # the Nexus repository name
NEXUS_USER="admin"
NEXUS_PASS="changeme"
OUT_DIR="./nexus-export"

mkdir -p "$OUT_DIR"

continuation_token=""

while true; do
  url="${NEXUS_URL}/service/rest/v1/components?repository=${REPO_NAME}"
  if [[ -n "$continuation_token" ]]; then
    url="${url}&continuationToken=${continuation_token}"
  fi

  response=$(curl -s -u "${NEXUS_USER}:${NEXUS_PASS}" "$url")
  continuation_token=$(echo "$response" | jq -r '.continuationToken // empty')

  # Extract asset download URLs for .deb files
  mapfile -t asset_urls < <(echo "$response" | \
    jq -r '.items[].assets[] | select(.contentType == "application/vnd.debian.binary-package") | .downloadUrl')

  for asset_url in "${asset_urls[@]}"; do
    filename=$(basename "$asset_url")
    echo "Downloading: $filename"
    curl -s -L -u "${NEXUS_USER}:${NEXUS_PASS}" \
         -o "${OUT_DIR}/${filename}" \
         "$asset_url"
  done

  [[ -z "$continuation_token" ]] && break
done

echo "Export complete. Files saved to ${OUT_DIR}/"

Note

Ce script nécessite jq (apt install jq). Si votre instance Nexus utilise HTTPS avec un certificat auto-signé, ajoutez -k aux options curl ou installez le bundle de CA.

Exécutez-le et vérifiez que le nombre de fichiers correspond à celui enregistré dans votre inventaire :

chmod +x nexus-export.sh
./nexus-export.sh
ls nexus-export/ | wc -l

4. Étape 2 — Mettre en place Repod

Si vous n'avez pas encore Repod en cours d'exécution, suivez d'abord le guide de démarrage. Revenez ici une fois que :

  • La stack Docker Compose est démarrée (frontend :3003, backend :8000, nginx :80).
  • Une clé de signature GPG a été générée dans Paramètres → GPG.
  • Vous disposez d'au moins un jeton API (préfixe repod_) depuis Paramètres → Jetons API.

5. Étape 3 — Script d'import en masse

Avec les fichiers .deb mis en staging localement, uploadez-les vers Repod en boucle. Le backend applique une limite de débit de 20 uploads par minute, le script marque donc une brève pause entre les appels pour respecter cette limite.

#!/usr/bin/env bash
# repod-import.sh — upload all .deb files in a directory to Repod
set -euo pipefail

REPOD_URL="http://repod.example.com"   # or http://localhost:8000 during testing
API_TOKEN="repod_xxxxxxxxxxxxxxxx"
DEB_DIR="./nexus-export"
DISTRIBUTION="jammy"                   # target distribution in Repod
COMPONENT="main"                       # target component

UPLOAD_DELAY=3   # seconds between uploads; 20/min limit = 3s minimum

success=0
failed=0

for deb in "${DEB_DIR}"/*.deb; do
  filename=$(basename "$deb")
  echo -n "Uploading ${filename} ... "

  http_code=$(curl -s -o /tmp/repod_response.json -w "%{http_code}" \
    -X POST "${REPOD_URL}/upload/" \
    -H "Authorization: Bearer ${API_TOKEN}" \
    -F "file=@${deb}" \
    -F "distribution=${DISTRIBUTION}" \
    -F "component=${COMPONENT}")

  if [[ "$http_code" == "200" || "$http_code" == "201" ]]; then
    echo "OK"
    ((success++))
  else
    echo "FAILED (HTTP ${http_code})"
    cat /tmp/repod_response.json
    ((failed++))
  fi

  sleep "$UPLOAD_DELAY"
done

echo ""
echo "Done. Success: ${success}  Failed: ${failed}"

Warning

Si vous uploadez des milliers de paquets, exécutez ce script dans une session tmux ou screen afin qu'une session SSH déconnectée ne l'interrompe pas. Les gros fichiers .deb (> 500 Mo) peuvent atteindre la limite de taille de corps par défaut de Nginx — augmentez client_max_body_size dans la configuration Nginx avant de commencer.

Lancez l'import :

chmod +x repod-import.sh
./repod-import.sh 2>&1 | tee import.log

6. Étape 4 — Vérifier

Comparez les décomptes de paquets entre Nexus et Repod avant de toucher à toute machine cliente.

Décompte de paquets Nexus (depuis votre export) :

ls nexus-export/*.deb | wc -l

Décompte de paquets Repod (via l'API) :

curl -s -H "Authorization: Bearer ${API_TOKEN}" \
  "${REPOD_URL}/packages/?distribution=jammy" | jq '.total'

Testez ensuite un cycle complet apt install sur une machine canari — un VM ou conteneur isolé — en la pointant temporairement vers la nouvelle URL Repod :

# On the canary machine
echo "deb [signed-by=/etc/apt/trusted.gpg.d/repod.gpg] \
  http://repod.example.com jammy main" \
  | sudo tee /etc/apt/sources.list.d/repod-test.list

curl -fsSL http://repod.example.com/gpg.key \
  | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/repod.gpg

sudo apt update
sudo apt install your-internal-package

Tip

Testez en premier les paquets les plus critiques pour votre infrastructure. Un apt update cassé sur la machine canari est bien préférable à un déploiement cassé sur l'ensemble du parc.


7. Étape 5 — Mettre à jour les machines clientes

Une fois le test canari réussi, déployez la nouvelle source APT vers tous les clients. La méthode exacte dépend de votre outillage de gestion de configuration.

# Remove the old Nexus source
sudo rm /etc/apt/sources.list.d/nexus.list

# Add the Repod source
echo "deb [signed-by=/etc/apt/trusted.gpg.d/repod.gpg] \
  http://repod.example.com jammy main" \
  | sudo tee /etc/apt/sources.list.d/repod.list

# Import the Repod GPG key
curl -fsSL http://repod.example.com/gpg.key \
  | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/repod.gpg

sudo apt update
- name: Remove Nexus APT source
  ansible.builtin.file:
    path: /etc/apt/sources.list.d/nexus.list
    state: absent

- name: Download Repod GPG key
  ansible.builtin.get_url:
    url: http://repod.example.com/gpg.key
    dest: /tmp/repod.gpg.asc

- name: Dearmor and install GPG key
  ansible.builtin.command:
    cmd: gpg --dearmor -o /etc/apt/trusted.gpg.d/repod.gpg /tmp/repod.gpg.asc
    creates: /etc/apt/trusted.gpg.d/repod.gpg

- name: Add Repod APT source
  ansible.builtin.apt_repository:
    repo: "deb [signed-by=/etc/apt/trusted.gpg.d/repod.gpg] http://repod.example.com jammy main"
    state: present
    filename: repod

8. Étape 6 — Basculer

Une fois tous les clients reconfigurés, la dernière étape consiste à rendre la nouvelle URL canonique :

  • Changement DNS : Mettez à jour l'enregistrement CNAME ou A pour votre nom d'hôte APT interne afin qu'il pointe vers l'hôte Repod. Les clients utilisant le nom d'hôte canonique n'ont besoin d'aucun autre changement.
  • Changement de reverse proxy : Si vous exposez Nexus et Repod derrière Nginx ou HAProxy, mettez à jour le bloc upstream pour router le trafic APT vers Repod.
  • Changement d'URL directe : Si les clients ont déjà la nouvelle URL Repod dans leur sources.list (depuis l'étape 5), aucune action supplémentaire n'est nécessaire.

Vérifiez en exécutant sudo apt update sur plusieurs machines depuis différents segments réseau.


9. Plan de retour arrière

Gardez Nexus en cours d'exécution et joignable à son URL interne d'origine pendant au moins deux semaines après le basculement. Si un problème critique survient :

  1. Annulez l'enregistrement DNS ou l'upstream du reverse proxy pour pointer à nouveau vers Nexus.
  2. Aucun changement client n'est nécessaire — ils récupéreront automatiquement les paquets depuis Nexus de nouveau au prochain apt update.
  3. Investiguez et résolvez le problème dans Repod avant de retenter le basculement.

Warning

Ne décommissionnez pas Nexus avant d'avoir exécuté apt install avec succès depuis Repod sur tous les environnements de production et que la fenêtre de retour arrière de deux semaines soit passée.


10. Problèmes courants

Erreurs d'authentification depuis l'API Nexus

Si vous voyez 401 Unauthorized en exécutant nexus-export.sh, confirmez que les identifiants sont corrects et que l'utilisateur Nexus a le privilège nx-repository-view-*-*-read. L'accès anonyme en lecture doit être activé sur le dépôt si vous omettez les identifiants.

La pagination s'arrête prématurément

Le continuationToken de Nexus n'est renvoyé que lorsqu'il existe d'autres pages. Si le script se termine avant d'avoir téléchargé tous les paquets, vérifiez que l'expression jq correspond au schéma de réponse de votre version de Nexus — le nom du champ n'a pas changé depuis Nexus 3.20, mais la structure environnante peut différer dans les versions plus anciennes.

Les gros fichiers .deb expirent

Le frontend Nginx de Repod a une client_max_body_size par défaut de 100 Mo. Modifiez docker-compose.yaml (ou le volume de configuration Nginx) pour l'augmenter avant d'uploader de gros paquets. Le point de terminaison d'upload a aussi une limite de 20 requêtes par minute ; la variable UPLOAD_DELAY du script d'import gère cela, mais vous devrez peut-être augmenter le délai si vous partagez le jeton API avec d'autres processus.

Le paquet existe déjà

Si un paquet avec le même nom, la même version et la même architecture existe déjà dans Repod (par ex. suite à un import partiel précédent), l'upload renvoie 409 Conflict. C'est sans danger à ignorer — le paquet est déjà présent. Filtrez ces cas de votre décompte d'échecs en vérifiant le corps de la réponse.