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 -shsur 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.listsont 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 :
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 :
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) :
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 :
- Annulez l'enregistrement DNS ou l'upstream du reverse proxy pour pointer à nouveau vers Nexus.
- Aucun changement client n'est nécessaire — ils récupéreront
automatiquement les paquets depuis Nexus de nouveau au prochain
apt update. - 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.