Aller au contenu
Développement medium

Installer Pulp avec un conteneur (podman, CLI, UI)

11 min de lecture

Logo Pulp

Ce guide déploie une instance Pulp fonctionnelle en un seul conteneur, configure la CLI pulp, ouvre l'interface web, puis expose le tout proprement en HTTPS derrière Traefik. Public visé : administrateurs à l'aise avec podman ou docker. Prérequis : une machine Linux avec podman (ou Docker) et l'accès à /dev/fuse. À la fin, vous aurez un dépôt d'artefacts prêt à recevoir vos paquets, en local pour tester, en HTTPS pour la production.

L'image officielle pulp/pulp fait tourner dans un même conteneur tous les services de Pulp : l'API, l'application de contenu, les workers, plus PostgreSQL, Redis et nginx. C'est la méthode recommandée pour une petite installation qui n'a pas besoin de monter en charge sur plusieurs machines.

  • Lancer Pulp en un conteneur avec podman.
  • Définir le mot de passe administrateur et le paramètre CONTENT_ORIGIN.
  • Installer et configurer la CLI pulp.
  • Ouvrir l'interface web servie par l'image.
  • Exposer l'instance en HTTPS derrière Traefik.
  • podman 4+ (ou Docker) et le périphérique /dev/fuse disponible (nécessaire au plugin conteneur).
  • Un port HTTP libre sur l'hôte (ici 8080).
  • Environ 2 Go de RAM libres pour PostgreSQL, Redis et les workers.

Pulp a besoin de répertoires persistants pour la base de données, le stockage des artefacts et sa configuration. On les crée à côté du conteneur avant de démarrer.

  1. Préparer l'arborescence et un fichier de réglages minimal :

    Fenêtre de terminal
    mkdir -p pulp/{settings,pulp_storage,pgsql,containers}
    cd pulp
    echo 'CONTENT_ORIGIN="http://localhost:8080"' > settings/settings.py

    Le paramètre CONTENT_ORIGIN est critique : c'est l'URL publique à laquelle vos clients joignent Pulp. Toutes les métadonnées publiées (index PyPI, realm du registre de conteneurs) l'utilisent pour construire leurs liens. S'il ne correspond pas au port réellement exposé, les pip install et podman pull échouent avec des liens cassés.

  2. Démarrer le conteneur :

    Fenêtre de terminal
    podman run --detach --publish 8080:80 --name pulp \
    --volume "$(pwd)/settings":/etc/pulp \
    --volume "$(pwd)/pulp_storage":/var/lib/pulp \
    --volume "$(pwd)/pgsql":/var/lib/pgsql \
    --volume "$(pwd)/containers":/var/lib/containers \
    --device /dev/fuse \
    docker.io/pulp/pulp:3.114

    L'image est tirée par tag de version (3.114) plutôt que latest, pour une installation reproductible.

  3. Attendre l'initialisation (migrations de base, ~1 minute), puis vérifier l'API :

    Fenêtre de terminal
    curl -s http://localhost:8080/pulp/api/v3/status/ | head

    La commande doit renvoyer un JSON listant les composants (core, file, python, container...). Tant que vous obtenez une erreur de connexion, le conteneur finit de démarrer.

L'image ne fixe pas de mot de passe par défaut. On le définit avec l'outil pulpcore-manager, exécuté dans le conteneur.

Fenêtre de terminal
podman exec pulp bash -c 'pulpcore-manager reset-admin-password --password "VotreMotDePasseFort"'

La sortie confirme Successfully set password for "admin" user. Ce compte admin est celui que vous utiliserez dans la CLI et l'interface web.

La CLI pulp est le moyen le plus direct de piloter l'instance. On l'installe dans un environnement Python isolé pour ne pas polluer le système.

Fenêtre de terminal
uv tool install "pulp-cli[pygments]"

On enregistre ensuite les coordonnées de l'instance :

Fenêtre de terminal
pulp config create \
--username admin \
--base-url http://localhost:8080 \
--password "VotreMotDePasseFort"

Vérifiez que la CLI dialogue bien avec le serveur :

Fenêtre de terminal
pulp status

La sortie affiche la version de core (3.114.0) et la liste des plugins actifs. Vous pilotez désormais Pulp sans toucher à curl.

L'image sert une interface graphique, Pulp UI, sous le chemin /ui/. Ouvrez dans un navigateur :

http://localhost:8080/ui/

Connectez-vous avec le compte admin et le mot de passe défini plus haut. L'authentification passe par une session (cookies sessionid et csrftoken), comme n'importe quelle application web classique.

L'installation ci-dessus, sur localhost:8080, n'est qu'un amorçage local pour vérifier que l'instance démarre. On ne publie jamais Pulp en HTTP pour de vrais clients : on place un reverse proxy qui termine le TLS et transmet le trafic au conteneur. Traefik convient bien grâce à sa configuration par étiquettes. En réseau isolé, sans autorité publique, la même exposition se fait avec une autorité auto-signée que l'on approuve sur les clients (voir Pulp en air-gapped).

Deux règles conditionnent le bon fonctionnement derrière un proxy :

  • CONTENT_ORIGIN doit valoir l'URL publique HTTPS (par exemple https://pulp.exemple.com). C'est elle qui alimente les liens des index et le realm du registre de conteneurs.
  • Le proxy doit transmettre l'en-tête Host et positionner X-Forwarded-Proto: https, ce que Traefik fait automatiquement. Sans cela, Pulp génère des URLs en http:// et les clients refusent les redirections.
  1. Ajuster les réglages pour l'URL publique, dans settings/settings.py :

    CONTENT_ORIGIN = "https://pulp.exemple.com"
    TOKEN_SERVER = "https://pulp.exemple.com/token/"
    TOKEN_SIGNATURE_ALGORITHM = "ES256"
    PUBLIC_KEY_PATH = "/etc/pulp/certs/token_public_key.pem"
    PRIVATE_KEY_PATH = "/etc/pulp/certs/token_private_key.pem"

    Les quatre dernières lignes activent l'authentification par jeton du registre de conteneurs ; sans une paire de clés cohérente avec l'URL publique, podman pull renvoie une erreur 500.

  2. Ajouter les labels Traefik au service Pulp. Si vous avez déjà un Traefik qui écoute sur une entrypoint HTTPS (websecure) avec un résolveur de certificats (le), il suffit de quatre labels sur le conteneur Pulp, rien d'autre à déclarer :

    services:
    pulp:
    image: docker.io/pulp/pulp:3.114
    devices:
    - "/dev/fuse"
    volumes:
    - "./settings:/etc/pulp"
    - "./pulp_storage:/var/lib/pulp"
    - "./pgsql:/var/lib/pgsql"
    - "./containers:/var/lib/containers"
    labels:
    - "traefik.enable=true"
    - "traefik.http.routers.pulp.rule=Host(`pulp.exemple.com`)"
    - "traefik.http.routers.pulp.tls.certresolver=le"
    - "traefik.http.services.pulp.loadbalancer.server.port=80"

    Une seule règle de routage suffit : elle englobe l'API (/pulp/api/), le contenu (/pulp/content/), le registre (/v2/, /token/) et l'interface (/ui/), tous servis par le même port 80 du conteneur. Le certresolver termine le TLS et Traefik ajoute seul les en-têtes Host et X-Forwarded-Proto.

  3. Démarrer et vérifier :

    Fenêtre de terminal
    docker compose up -d
    curl -s https://pulp.exemple.com/pulp/api/v3/status/ | head

    La CLI et les clients pointent désormais vers https://pulp.exemple.com, et podman login pulp.exemple.com fonctionne sans --tls-verify=false.

En air-gapped : certificat auto-signé au lieu d'ACME

Section intitulée « En air-gapped : certificat auto-signé au lieu d'ACME »

Le résolveur le ci-dessus repose sur Let's Encrypt, qui exige un accès Internet et un domaine public : inutilisable en réseau isolé. Hors ligne, vous fournissez à Traefik un certificat auto-signé au lieu d'un certresolver. On le déclare dans un fichier de configuration dynamique chargé par le file provider :

# certs.yaml (monté et référencé via --providers.file.filename)
tls:
certificates:
- certFile: /certs/pulp.crt
keyFile: /certs/pulp.key

Le label du routeur devient alors simplement traefik.http.routers.pulp.tls=true (sans certresolver). La génération de la paire pulp.crt / pulp.key et surtout l'approbation de l'autorité sur les clients sont détaillées dans Pulp en air-gapped, l'étape suivante logique de ce guide.

L'image tout-en-un pulp/pulp embarque son propre nginx, qui répartit les requêtes vers l'API et l'application de contenu. Dans le montage ci-dessus, Traefik ne le remplace pas : il se place devant, termine le TLS, et transmet au port 80 du conteneur, où le nginx interne prend le relais. Ce double proxy est normal et parfaitement supporté.

Si vous voulez faire de Traefik la seule couche web (sans nginx interne), il faut passer du conteneur unique au déploiement multi-conteneurs : l'image pulp-minimal fournit séparément pulp-api (port 24817) et pulp-content (port 24816), et l'image pulp-web n'est que le nginx. Vous supprimez alors pulp-web et vous répliquez son routage dans Traefik :

CheminService cible
/pulp/content/pulp-content:24816
/v2/ (registre OCI)pulp-content:24816
/pulp/api/v3/, /auth/, /token/, /pulp-api:24817

C'est plus souple mais plus délicat : la moindre route oubliée (le /token/ du registre de conteneurs, par exemple) casse une fonctionnalité. Pour la plupart des installations, garder le nginx interne et mettre Traefik devant reste le choix le plus sûr.

SymptômeCause probableSolution
pip install télécharge un fichier au mauvais digestCONTENT_ORIGIN ne correspond pas au port ou à l'URL publiqueCorriger CONTENT_ORIGIN, redémarrer le conteneur
podman pull renvoie 500 sur /v2/TOKEN_SERVER ou la paire de clés ES256 absenteAjouter les réglages de jeton et générer les clés
L'API met longtemps à répondre au premier démarrageMigrations PostgreSQL en coursAttendre ~1 minute, surveiller podman logs pulp
podman pull refuse l'accès (denied)Pull anonyme non autorisépodman login avec le compte admin
  • L'image pulp/pulp fait tourner toute la pile Pulp dans un seul conteneur, idéale pour démarrer.
  • Le mot de passe admin se définit avec pulpcore-manager reset-admin-password.
  • Le paramètre CONTENT_ORIGIN doit toujours refléter l'URL publique réelle, sinon les liens publiés sont cassés.
  • La CLI pulp pilote l'instance ; l'interface /ui/ l'explore mais reste jeune.
  • En production, un reverse proxy Traefik termine le TLS avec une seule règle de routage vers le port 80 du conteneur.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn