Change language

rp-registry

Objectif

Le registre des modules et des solutions : ce qui existe, de quoi est composée chaque solution,
et les octets eux-mêmes. Il répond à deux lecteurs qui ne partagent rien d'autre. Ptah
demande un index puis des objets par condensat, sans jamais apprendre un nom et en
vérifiant chaque octet reçu. Le portail et le chat posent la question opposée — quelles
solutions existent, qu'apporterait celle-ci, de quoi a-t-elle besoin en premier.

Les deux vivent sur un même service, car un catalogue nommant des modules que le magasin
d'objets ne contient pas est précisément la défaillance que celui-ci cherche à prévenir,
et cela ne peut être vérifié que là où les deux moitiés sont visibles.

Limite de responsabilité

rp-registry ne touche jamais à un cluster. Il publie un catalogue et sert des octets ;
transformer une sélection en plateforme en fonctionnement relève de lm-kubernetes, qui
écrit des ressources personnalisées Solution, et leur rapprochement relève de ptah.
Maintenir cette séparation permet à un seul registre de servir de nombreux clusters sans
détenir leurs identifiants.

Stockage

Deux magasins, délibérément pas davantage.

objects est un unique magasin KV contenant deux types de valeurs sous deux préfixes :
les octets des modules par condensat (obj), et les documents de solution par couche et
par nom (sol). Les deux sont lus intégralement avec une clé exacte, et constituent donc
le même type de stockage utilisé deux fois. KVStore distingue le binaire du JSON grâce
à un en-tête qu'il écrit lui-même ; aucun des deux préfixes n'a donc besoin d'être décodé
ici.

catalog est SQL, car il contient la partie qui change et celle qui est interrogée :
quel artefact correspond actuellement à quel condensat, dans quelle couche. Les octets
sont immuables et adressés par leur contenu, ils n'ont donc pas besoin de table ; les
noms changent à chaque publication et sont recherchés par couche, par type et entre les
couches.

La correspondance publiée n'est pas stockée. C'est une réduction sur layers et
modules, calculée à la demande, et son condensat est la revision. La stocker
maintiendrait une seconde copie de la vérité, obsolète précisément lorsqu'une publication
vient d'avoir lieu et qu'un cluster demande pourquoi il ne peut pas la voir.

Couches

Une couche est le résultat d'une compilation. converged publie ses modules, club publie
les siens et déclare extends: ["converged"], et la correspondance que lit chaque
consommateur est composée à partir de toutes les couches — une couche produit arrivant
après la base dont elle étend le contenu, de sorte qu'un module qu'elle remplace
délibérément l'emporte. L'ordre de publication cesse d'avoir de l'importance, et aucune
compilation ne peut effacer des noms qu'elle n'a pas créés.

La publication remplace entièrement une couche au lieu de la fusionner : une publication
est la totalité de la sortie de cette couche, donc un nom que la nouvelle compilation ne
produit plus doit disparaître. Une fusion le laisserait pointer vers des octets que plus
aucune compilation ne produit.

Servir les octets

ensureObjectCached renvoie une clé Valkey, et non l'objet. Les octets sont matérialisés
dans le cache limité au périmètre, puis lus depuis celui-ci par l'interface, ce qui est
la même transmission que celle utilisée par la galerie pour les images et pour la même
raison : un module peut atteindre 2 MiB, et répondre avec la charge utile la ferait passer
par stockage → ms → interface à chaque défaut de cache, sur un canal destiné aux requêtes.

Les deux routes utilisées par un cluster — /registry/index.json et /registry/<digest> —
sont servies par l'hôte ui du club, et non par ce service
(club/core/frontend/landing/src/ptah-registry.ts). ptah parle uniquement HTTP brut et
rien d'autre, donc quelque chose disposant d'une surface HTTP doit lui répondre, et c'est
l'interface ; l'image de base n'intervient pas, car un produit sans registre n'a rien à
servir. Les routes sont anonymes, car l'authenticité repose sur le condensat : ptah vérifie
chaque octet reçu par rapport au condensat demandé, et un secret partagé ajouterait quelque
chose à distribuer et à révoquer sans apporter de garantie supplémentaire.

Un condensat qu'aucune couche ne nomme n'est pas servi, même si les octets sont stockés.
Les objets sans nom sont soit des déchets issus d'une publication interrompue, soit quelque
chose qu'un appelant a deviné, et les servir transformerait ceci en magasin ouvert de blobs.

Limites

Un objet est limité à 2 MiB. Les vrais modules font quelques dizaines de kilo-octets —
l'ensemble des modules du backend converged fait environ 0.44 MiB compressé — et ptah
refuse tout ce qui dépasse 64 MiB, ce qui le place bien en dessous des deux limites. Ce
n'est pas une optimisation : le registre est destiné à héberger des modules communautaires,
et un téléversement de la taille d'une image de conteneur signifie que quelqu'un a publié
le mauvais artefact.

Les objets sont stockés exactement tels qu'ils arrivent. Le registre ne compresse ni ne
décompresse : les bundles de modules sont en brotli, les sources de workflows sont brutes
car centimanus les exécute lui-même, et le condensat couvre les octets stockés dans les deux
cas. Tout réencodage romprait l'adressage par contenu au seul endroit qu'il est censé
protéger.

Source

modules/repositories/rp-registry