Aller au contenu

Migrer depuis JFrog Artifactory

Ce guide couvre le déplacement d'un dépôt APT de JFrog Artifactory vers Repod. Il utilise l'API REST d'Artifactory et l'Artifactory Query Language (AQL) pour énumérer et télécharger chaque paquet .deb, puis les importe dans Repod avec un script d'upload en masse.

Artifactory CE vs Repod

Artifactory Community Edition nécessite un compte JFrog pour l'activation et effectue des appels de télémétrie vers l'extérieur. Repod est entièrement autonome : pas de compte, pas de serveur de licence, aucun appel sortant requis. Il stocke tout dans des volumes Docker sur votre propre infrastructure.

Vous migrez aussi des dépôts Maven, PyPI, npm ou Docker ?

Repod héberge des dépôts Maven, PyPI, npm et Docker/OCI aux côtés d'APT — voir Formats de paquets. Puisque Repod parle le protocole natif de chaque format, le chemin de migration le plus rapide pour ceux-ci n'est généralement pas un script de téléchargement en masse : pointez mvn deploy, twine upload, ou docker push directement vers Repod (voir Configuration des clients / Registre de conteneurs) et republiez depuis votre pipeline de build, ou utilisez l'importateur intégré de Repod pour récupérer des artefacts spécifiques directement depuis Maven Central / PyPI / npmjs.org / Docker Hub sans passer par Artifactory du tout. L'approche par téléchargement-puis-réupload basée sur AQL de ce guide est spécifique à la disposition de fichiers .deb d'APT.


1. Quand migrer

Ce guide est la bonne approche quand :

  • Artifactory est utilisé principalement ou exclusivement comme miroir APT ou hébergeur de paquets internes, et que la complexité de son modèle multi-format n'est plus justifiée.
  • Votre équipe souhaite un flux de travail APT dédié avec scan CVE et génération de manifestes intégrés, plutôt que de maintenir un stockage d'artefacts générique.
  • Vous voulez réduire les coûts de licence : les licences Artifactory Pro ou Enterprise sont coûteuses ; Repod est open-source et auto-hébergé.

Vous pouvez faire tourner Repod et Artifactory côte à côte pendant la transition et migrer les dépôts une distribution à la fois.


2. Avant de commencer — checklist d'inventaire

Rassemblez ces informations avant d'apporter tout changement :

  • URL de base d'Artifactory (par ex. https://artifactory.example.com) et identifiants admin.
  • Noms de tous les dépôts locaux APT (type Debian en terminologie Artifactory).
  • Distributions et composants définis dans les paramètres Debian de chaque dépôt.
  • Nombre approximatif de paquets et taille disque totale.
  • Nombre et emplacement des machines clientes, et comment sources.list est géré.
  • Si Artifactory impose l'authentification sur le chemin de lecture (accès anonyme vs. jetons de déploiement).

Tip

Dans Artifactory, naviguez vers Administration → Repositories → Repositories et filtrez par type « Local » et type de paquet « Debian ». Faites une capture d'écran ou exportez la liste comme feuille de suivi de votre migration.


3. Étape 1 — Lister les paquets avec AQL

L'API Storage d'Artifactory peut lister les fichiers de façon récursive, mais Artifactory Query Language (AQL) offre un filtrage précis et une pagination avec bien moins de surcharge de réponse. Utilisez AQL pour énumérer chaque fichier .deb de votre dépôt avant de télécharger quoi que ce soit.

#!/usr/bin/env bash
# artifactory-list.sh — list all .deb files in an Artifactory local repo via AQL
set -euo pipefail

ART_URL="https://artifactory.example.com"
REPO_NAME="apt-local"
ART_USER="admin"
ART_PASS="changeme"

curl -s -u "${ART_USER}:${ART_PASS}" \
  -X POST "${ART_URL}/artifactory/api/search/aql" \
  -H "Content-Type: text/plain" \
  -d "items.find({
        \"repo\": \"${REPO_NAME}\",
        \"name\": {\"\$match\": \"*.deb\"}
      }).include(\"repo\", \"path\", \"name\", \"size\", \"sha256\")" \
  | jq -r '.results[] | "\(.repo)/\(.path)/\(.name)"'

Enregistrez la sortie dans un fichier — elle devient le manifeste de téléchargement :

chmod +x artifactory-list.sh
./artifactory-list.sh > package-manifest.txt
wc -l package-manifest.txt   # confirm total count matches your inventory

Alternativement, utilisez l'API Storage plus simple pour un listage rapide de répertoire (pas de pagination, adapté aux dépôts plus petits) :

curl -s -u "${ART_USER}:${ART_PASS}" \
  "${ART_URL}/artifactory/api/storage/${REPO_NAME}?list&deep=1&listFolders=0" \
  | jq -r '.files[].uri | select(endswith(".deb"))'

Warning

Le point de terminaison Storage API ?list&deep=1 charge l'intégralité de l'arborescence du dépôt en mémoire sur le serveur Artifactory avant de répondre. Sur des dépôts de dizaines de milliers de fichiers, cela peut être lent ou expirer. Préférez AQL pour les gros dépôts.


4. Étape 2 — Télécharger les fichiers .deb depuis Artifactory

Avec package-manifest.txt en main, téléchargez chaque fichier vers un répertoire de staging local :

#!/usr/bin/env bash
# artifactory-export.sh — download .deb files listed in package-manifest.txt
set -euo pipefail

ART_URL="https://artifactory.example.com"
ART_USER="admin"
ART_PASS="changeme"
MANIFEST="./package-manifest.txt"
OUT_DIR="./artifactory-export"

mkdir -p "$OUT_DIR"

while IFS= read -r path; do
  filename=$(basename "$path")
  dest="${OUT_DIR}/${filename}"

  if [[ -f "$dest" ]]; then
    echo "Already exists, skipping: ${filename}"
    continue
  fi

  echo -n "Downloading ${filename} ... "
  http_code=$(curl -s -L -u "${ART_USER}:${ART_PASS}" \
    -o "$dest" \
    -w "%{http_code}" \
    "${ART_URL}/artifactory/${path}")

  if [[ "$http_code" == "200" ]]; then
    echo "OK"
  else
    echo "FAILED (HTTP ${http_code})"
    rm -f "$dest"
  fi
done < "$MANIFEST"

echo "Download complete. Files in ${OUT_DIR}/"

Le modèle d'URL de téléchargement direct pour des paquets individuels est :

GET /artifactory/apt-local/pool/main/p/package_1.0_amd64.deb

Le nom du dépôt, le chemin du composant et le nom de fichier proviennent des résultats AQL stockés dans package-manifest.txt.

Tip

Ajoutez --retry 3 --retry-delay 5 aux options curl si votre connexion réseau vers Artifactory est instable ou si vous téléchargez via un VPN.


5. Étape 3 — Mettre en place Repod

Si vous n'avez pas encore Repod en cours d'exécution, suivez le guide de démarrage et 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'un jeton API (préfixe repod_) depuis Paramètres → Jetons API.

6. Étape 4 — Import en masse dans Repod

Uploadez les paquets téléchargés vers Repod. Le backend applique une limite de débit de 20 uploads par minute ; le script ci-dessous s'y adapte en conséquence.

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

REPOD_URL="http://repod.example.com"
API_TOKEN="repod_xxxxxxxxxxxxxxxx"
DEB_DIR="./artifactory-export"
DISTRIBUTION="jammy"
COMPONENT="main"
UPLOAD_DELAY=3   # 20/min rate limit → 3s between uploads

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}"

Exécutez dans une session de terminal persistante :

chmod +x repod-import.sh
tmux new-session -s repod-import './repod-import.sh | tee import.log'

7. Étape 5 — Vérifier

Comparez les décomptes et exécutez un test canari avant de toucher aux clients de production.

# Count downloaded files
ls artifactory-export/*.deb | wc -l

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

Testez sur une machine canari isolée :

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

8. Étape 6 — Mettre à jour les machines clientes

Déployez la nouvelle source APT vers tous les clients à l'aide de votre outillage de gestion de configuration.

sudo rm /etc/apt/sources.list.d/artifactory.list

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

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

sudo apt update
- name: Remove Artifactory APT source
  ansible.builtin.file:
    path: /etc/apt/sources.list.d/artifactory.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: Install dearmored 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

9. Étape 7 — Basculer

Pointez le nom d'hôte APT canonique vers Repod via un changement DNS ou une mise à jour du reverse proxy. Vérifiez avec sudo apt update sur plusieurs machines depuis différents segments réseau avant de déclarer le succès.


10. Plan de retour arrière

Gardez Artifactory en cours d'exécution à son URL d'origine pendant au moins deux semaines après le basculement. Pour revenir en arrière, annulez l'enregistrement DNS ou la mise à jour du proxy. Aucun changement client n'est nécessaire — apt update recommencera automatiquement à récupérer depuis Artifactory.

Warning

Ne décommissionnez pas Artifactory avant que Repod n'ait servi le trafic de production avec succès pendant au moins deux semaines et que vous ayez vérifié que toutes les versions de paquets sont présentes et installables.


11. Problèmes courants

AQL ne renvoie aucun résultat

Confirmez que le nom du dépôt dans la requête AQL correspond exactement (sensible à la casse). Dans Artifactory, ouvrez Administration → Repositories, trouvez votre dépôt APT, et copiez la valeur « Repository Key » telle quelle.

401 Unauthorized sur les téléchargements

Les jetons d'accès Artifactory et les mots de passe sont distincts. Si vous avez créé un jeton d'accès dans l'interface, transmettez-le comme jeton Bearer plutôt qu'en HTTP Basic :

curl -H "Authorization: Bearer ${ART_TOKEN}" ...

Les paquets atterrissent dans la mauvaise distribution

Artifactory stocke les paquets Debian avec les métadonnées de distribution dans leurs propriétés. Repod détermine la distribution à partir des paramètres d'upload (-F "distribution=...") plutôt qu'en lisant le fichier control du .deb. Assurez-vous que votre script d'import cible le bon nom de distribution.

Les gros fichiers expirent à l'upload

Augmentez client_max_body_size dans la configuration Nginx de Repod avant de lancer l'import. Les très gros paquets peuvent aussi nécessiter un délai d'expiration de requête FastAPI plus long — définissez --timeout-keep-alive dans la définition du service backend dans docker-compose.yaml.