Pulp

Siehe auch

Verwandte Artikel
Offizielle Dokumentation

Pulp ist ein Repository-Server für die zentrale, versionierte Spiegelung und Bereitstellung von Software-Paketen: RPMs, Debs, Container-Images, Ansible-Collections, Python-Wheels und beliebige Dateien. Gegenüber einem nackten createrepo/reposync-Setup bringt Pulp drei Dinge mit, die im Betrieb den Unterschied machen: versionierte Snapshots jedes Repositories (mit Rollback-Option), eine definierte Trennung von Inhalt und Veröffentlichung (erst nach einer expliziten Freigabe sehen Clients neue Pakete), und automatisch signierte RPM-Metadaten über einen konfigurierbaren Signing Service.

Zum Einsatz kommt Pulp typischerweise dort, wo eine Flotte RHEL-/Debian-Hosts Pakete aus kontrollierten, firmen-eigenen Mirror-URLs zieht und die Paket-Versionen in verschiedenen Umgebungen (Test/Staging/Produktion) unabhängig voneinander weitergeschaltet werden sollen.

Begriffe

Content App

Der HTTP-Server-Anteil von Pulp. Liefert die Dateien über https://<pulp>/pulp/content/<base-path>/ an Clients aus, nach dem, was die jeweilige Distribution freigibt.

Distribution

Öffentlicher Pfad, unter dem eine Publication erreichbar ist. Die Distribution verweist entweder auf eine konkrete Publication (statisch) oder auf ein Repository (dann zeigt sie immer die neueste Publication davon). Erst durch eine Distribution wird Inhalt für Clients sichtbar.

Orphan

Content-Unit (RPM, Deb, File), die in keinem Repository-Version mehr referenziert wird. Bleibt nach repository destroy im Store liegen, bis pulp orphans cleanup aufräumt.

Publication

Versionsgebundener Snapshot eines Repositories, inklusive signierter Metadaten. Ohne Publication gibt es keine Auslieferung - selbst wenn das Repository aktuell ist, sieht der Client bis zur nächsten Publication nichts.

Pulp CLI

Offizielles Kommandozeilen-Werkzeug (pulp-cli). Redet mit der REST-API und ist der empfohlene Weg für den Admin-Alltag. Alles, was die CLI kann, geht auch direkt per curl oder pulpcore-manager.

pulpcore

Kern-Komponente, stellt API, Tasking, Auth und Content App bereit. Plugins wie pulp_rpm, pulp_deb, pulp_file, pulp_container, pulp_ansible und pulp_python binden sich in pulpcore ein und liefern den Content-Typ-spezifischen Code.

Remote

Definiert die Upstream-Quelle eines Repositories: URL, TLS-Validierung, Credentials, Download-Policy (immediate lädt alle Dateien, on_demand lädt erst bei Client-Zugriff, streamed wirft sie nach dem Ausliefern weg).

Repository

Container für Content. Sammelt die Inhalte, die sync vom Remote holt oder die per content upload hochgeladen werden. Ein Repository hat mehrere Versionen (Version 0 = leer, Version N nach dem N-ten Sync).

Signing Service

Konfigurations-Objekt in Pulp, das auf ein Signier-Skript plus einen GPG-Key zeigt. Wird ein Repository mit einem Signing Service verknüpft, signiert Pulp die Metadaten bei jeder neuen Publication automatisch.

Architektur

Pulp besteht aus drei Diensten, die je nach Installations-Methode als eigene Systemd-Units oder Container laufen:

  • API-Server (Django/Gunicorn): REST-API, nimmt pulp-cli-Aufrufe und Browser-Anfragen entgegen, lehnt sich an PostgreSQL als Metadaten-Datenbank und Redis als Broker an.

  • Worker-Pool: führt asynchrone Tasks aus - Syncs, Publications, Orphan-Cleanup, Signing. Mehrere Worker parallel lassen sich anhand der Sync-Last skalieren.

  • Content App: liefert die Dateien aus. Üblicherweise vor der Content App ein Apache oder nginx als Reverse Proxy (TLS, Auth, Rewrites).

Pakete und andere Content-Units landen im Storage (Dateisystem unter /var/lib/pulp/ oder ein S3-Bucket).

Installation

Offiziell unterstützt werden zwei Wege: die Ansible-Collection pulp_installer (pulp.pulp_installer), die PostgreSQL, Redis, pulpcore, die gewünschten Plugins, Systemd-Units und den Content-App-Reverse-Proxy in einem Rutsch einrichtet, und die Pulp-OCI-Images als Container in Podman oder Docker - bequem für Teststände und kurzlebige Setups.

Voraussetzung für die nachstehenden Beispiele: ein laufender Pulp-Server mit den Plugins pulp_rpm und pulp_file.

Pulp CLI einrichten

pip install 'pulp-cli[pygments]'
pulp config create \
    --username=admin \
    --base-url=https://mirror.example.com \
    --password=<secret>

Die Konfiguration landet in ~/.config/pulp/cli.toml. Für automatisierte Aufrufe empfiehlt sich ein Service-Account mit eigenem Passwort statt des admin-Users und eine TOML-Datei, die nur diesem Account gehört und chmod 0600 trägt.

Verbindung testen:

pulp status

Signing Service einrichten

Ein Signing Service ist die Voraussetzung, damit Clients den Pulp-Metadaten trauen. Er wird einmal eingerichtet und danach per Name in Repositories referenziert.

GPG-Key auf dem Pulp-Host anlegen oder importieren, dann ein Wrapper-Skript, das Pulp zum Signieren aufruft:

/var/lib/pulp/scripts/sign-metadata.sh
#!/usr/bin/env bash
set -euo pipefail

FILE_PATH=$1
SIGNATURE_PATH="${FILE_PATH}.asc"
KEY_ID="${PULP_SIGNING_KEY_FINGERPRINT}"

gpg --quiet --batch --pinentry-mode loopback \
    --passphrase "${PULP_SIGNING_KEY_PASSPHRASE}" \
    --armor --detach-sign --local-user "${KEY_ID}" \
    --output "${SIGNATURE_PATH}" "${FILE_PATH}"

echo "{\"file\": \"${FILE_PATH}\", \"signature\": \"${SIGNATURE_PATH}\", \"key_id\": \"${KEY_ID}\"}"

Skript-Permissions und Besitzer auf den pulp-User setzen. Dann den Service in Pulp registrieren:

pulpcore-manager add-signing-service sign-metadata \
    /var/lib/pulp/scripts/sign-metadata.sh \
    <fingerprint>

pulp signing-service show --name=sign-metadata

RPM-Repository spiegeln und veröffentlichen

Am Beispiel des offiziellen MariaDB-11.8-Repos für Rocky 9. Der Ablauf ist immer: Remote anlegen, Repository mit Signing Service anlegen, syncen, publishen, distributen.

Remote:

pulp rpm remote create \
    --name=mariadb-11.8-rocky-9-remote \
    --url=https://mirror.mariadb.org/yum/11.8/rocky9-amd64/ \
    --policy=immediate \
    --tls-validation=true

Repository mit Signing Service:

pulp rpm repository create \
    --name=mariadb-11.8-rocky-9 \
    --remote=mariadb-11.8-rocky-9-remote \
    --metadata-signing-service=$(pulp signing-service show --name=sign-metadata | jq --raw-output .pulp_href)

Synchronisieren:

pulp rpm repository sync \
    --name=mariadb-11.8-rocky-9 \
    --sync-policy=mirror_complete

mirror_complete spiegelt genau den Upstream-Stand (alte Pakete verschwinden, wenn sie upstream weg sind). Für additives Verhalten (nur neue Pakete dazu, nichts entfernen) additive wählen.

Publication und Distribution:

pulp rpm publication create --repository=mariadb-11.8-rocky-9

pulp rpm distribution create \
    --name=mariadb-11.8-rocky-9-dist \
    --base-path=mariadb-11.8-rocky-9 \
    --repository=mariadb-11.8-rocky-9

Wird die Distribution mit --repository statt --publication angelegt, zeigt sie automatisch immer auf die jeweils neueste Publication des Repositories - nach einem sync plus neuer Publication ist der neue Stand sofort sichtbar, ohne dass die Distribution umgehängt werden muss. Das ist der Default für Mirror-Setups.

Das Repository ist danach unter https://mirror.example.com/pulp/content/mariadb-11.8-rocky-9/ erreichbar und enthält eine von Pulp signierte repomd.xml samt repomd.xml.asc.

Auf dem Client eine passende .repo-Datei anlegen (Beispiel):

/etc/yum.repos.d/mariadb.repo
[mariadb]
name=MariaDB 11.8 (Rocky 9)
baseurl=https://mirror.example.com/pulp/content/mariadb-11.8-rocky-9/
gpgcheck=1
gpgkey=https://mirror.example.com/pulp/content/keys/GPG-KEY-mariadb-signing-key.asc
repo_gpgcheck=1
enabled=1

File-Repository für GPG-Keys und statische Dateien

GPG-Keys, Shell-Skripte, Ansible-Inventories oder Konfigurationsdateien, die per HTTP bereitgestellt werden sollen, leben in File-Repositories.

Repository anlegen, Datei hochladen, veröffentlichen:

pulp file repository create --name=keys

pulp file content upload \
    --repository=keys \
    --file=/home/linuxfabrik/GPG-KEY-galeracluster.com \
    --relative-path=GPG-KEY-galeracluster.com

pulp file publication create --repository=keys

pulp file distribution create \
    --name=keys-dist \
    --base-path=keys \
    --repository=keys

Updates einspielen

Ein Routine-Update für ein gespiegeltes Repository besteht aus genau drei Kommandos: erneut syncen, neue Publication anlegen, Distribution zeigt automatisch auf den neuen Stand (sofern sie mit --repository angelegt wurde):

pulp rpm repository sync --name=mariadb-11.8-rocky-9
pulp rpm publication create --repository=mariadb-11.8-rocky-9

Für regelmässige Mirror-Läufe eignet sich ein Systemd-Timer oder ein Cron-Job, der die beiden Kommandos für jede relevante Repo-Definition absetzt.

Aufräumen

Pulp löscht Content nicht automatisch. Nach dem Entfernen von Repositories oder Repository-Versionen bleiben verwaiste Content-Units im Storage; der Aufräum-Lauf ist explizit:

pulp orphans cleanup

Ein Auto-Cleanup-Intervall lässt sich über ORPHAN_PROTECTION_TIME (in Minuten) in der Pulp-Konfiguration setzen; per Default wartet Pulp 24 Stunden, bevor ein Orphan entfernt werden darf.

Repository und Distribution löschen

In umgekehrter Reihenfolge zum Anlegen: Distribution, Publications, Repository:

pulp rpm distribution destroy --name=mariadb-11.8-rocky-9-dist

pulp rpm publication list --repository=mariadb-11.8-rocky-9
pulp rpm publication destroy --href=<pulp_href>

pulp rpm repository destroy --name=mariadb-11.8-rocky-9
pulp rpm remote destroy --name=mariadb-11.8-rocky-9-remote

pulp orphans cleanup

Troubleshooting

pulp sync schlägt mit TLS-Fehler fehl

Das Upstream-Zertifikat ist Pulp nicht bekannt. Bei öffentlich gültigem Zertifikat das CA-Root des Pulp-Hosts aktualisieren (update-ca-trust unter RHEL). Bei selbstsignierten Zertifikaten das Zertifikat am Remote hinterlegen: pulp rpm remote update --name=<remote> --ca-cert @/path/to/ca.pem oder, nur für kurzlebige Tests, --tls-validation=false.

Clients sehen ein Paket nicht, obwohl sync gelaufen ist

Der sync bringt Content nur ins Repository; sichtbar wird er erst mit einer neuen publication create und - falls die Distribution statisch auf eine Publication zeigt - einer neuen distribution update --publication=.... Distributions mit --repository (Default für Mirrors) folgen automatisch; ein systemctl reload httpd oder Ähnliches ist nie nötig, weil die Content App keine Zwischenpuffer hat.

Metadaten-Signatur fehlt in repomd.xml.asc

Repository nicht mit --metadata-signing-service verknüpft. Nachziehen über pulp rpm repository update --name=<repo> --metadata-signing-service=<href> und danach eine neue Publication erstellen.

pulpcore-manager add-signing-service findet den Key nicht

Der GPG-Key muss im Keyring des pulp-Systemusers liegen, nicht im Keyring des Admins, der das Kommando ausführt. Key als pulp-User importieren oder per --gnupghome explizit den richtigen Pfad angeben.

pulp orphans cleanup entfernt nichts, obwohl Repos gelöscht sind

ORPHAN_PROTECTION_TIME gibt dem Content eine Schonfrist. Entweder warten oder den Parameter in /etc/pulp/settings.py auf 0 setzen und den API-Server neu starten (nur auf Teststellen sinnvoll).

Uploads oder Syncs bleiben im Status waiting stehen

Kein freier Worker. systemctl status pulpcore-worker@* prüfen; bei Bedarf weitere Worker-Units über die pulp_installer-Variable pulpcore_workers hochskalieren.