Votre première promotion
Étape 2 sur 2 — vous avez l’instance de
l’étape 1. Cette page la met à sa vraie place :
entre les registres où le contenu vit déjà et la zone qui le consomme.
Vous allez épingler une image publique dans une recipe, signer la recipe,
la publier dans un cookbook, déclarer l’état désiré de la zone, laisser
votre instance promouvoir — et finir par un docker pull depuis le
registre de zone. Tout ce qui suit n’utilise que de l’outillage
utilisateur ordinaire — rien qui vienne de l’arborescence des sources.
Il vous faut : le binaire tobby et le tobby.yaml de l’étape 1,
plus docker, cosign et curl. L’image vient de Docker Hub ; la seule
chose que vous montez vous-même est un registre cookbook jetable en
boucle locale.
La distribution
Section intitulée « La distribution »| Élément | Rôle |
|---|---|
docker.io |
Le registre amont. L’image y vit déjà ; rien n’y est poussé. |
Un registre cookbook (:5001) |
Un registre OCI ordinaire qui héberge votre recipe signée. N’importe quel registre où vous pouvez pousser convient — ici, un registre local jetable. |
Votre instance (:8080) |
Celle de l’étape 1 : sécurisée, avec sa clé de confiance et son Retriever. C’est elle qui promeut. |
Une paire de clés cosign |
Signe la recipe. La clé publique devient la racine de confiance de votre instance. |
1. Un registre cookbook
Section intitulée « 1. Un registre cookbook »Les recipes se publient dans un cookbook : un dépôt OCI ordinaire, sur n’importe quel registre où vous pouvez pousser. Si vous en avez déjà un (ghcr.io, Harbor, …), utilisez-le et adaptez les adresses qui suivent. Pour le parcours, un registre jetable en boucle locale suffit :
docker run -d --rm --name cookbook -p 5001:5000 registry:2Le port hôte est 5001 et non 5000 : sur macOS, le récepteur AirPlay occupe le port 5000 et répond 403 à sa place — un grand classique des tutoriels de registry locale.
2. Épingler l’image
Section intitulée « 2. Épingler l’image »Une recipe désigne le contenu par digest, jamais par simple tag. Lisez le
digest que alpine:3.22.1 résout aujourd’hui :
docker buildx imagetools inspect docker.io/library/alpine:3.22.1Les premières lignes affichent Digest: sha256:… — gardez ce digest,
la recipe l’épingle.
3. Écrire la recipe
Section intitulée « 3. Écrire la recipe »Une recipe décrit une livraison cohérente. Une recipe « cuite » — la
seule qu’un cookbook publie — épingle chaque ingrédient par digest : une
seule signature atteste les octets exacts de toute la livraison. Écrivez
alpine.yaml, avec le digest de l’étape précédente :
apiVersion: recipe.tobby.dev/v1alpha1kind: Recipe
metadata: name: alpine version: 3.22.1 description: Première promotion — une image épinglée
spec: ingredients: - name: alpine kind: ContainerImage ref: docker.io/library/alpine # référence nominale, sans tag version: 3.22.1 digest: sha256:<le digest affiché par imagetools>Les concepts — recipes, cookbooks, retrievers — sont couverts dans Comprendre les recipes.
4. La publier et la signer
Section intitulée « 4. La publier et la signer »tobby recipe push publie la recipe comme artefact OCI après l’avoir
contrôlée : un document qui n’est pas une recipe valide, pas entièrement
épinglé, ou déjà publié avec un contenu différent est refusé. Le registre
jetable parle HTTP simple, ce qui exige un accord explicite par hôte :
export TOBBY_REGISTRIES_INSECURE=127.0.0.1:5001tobby recipe push alpine.yaml 127.0.0.1:5001/cookbook/alpine:3.22.1Le digest publié sort sur stdout, prêt pour la signature. Signer reste hors de Tobby — il ne détient jamais de clé privée :
cosign generate-key-paircosign sign --key cosign.key --yes --allow-insecure-registry \ --use-signing-config=false --tlog-upload=false \ "127.0.0.1:5001/cookbook/alpine@<le digest affiché par recipe push>"Les deux drapeaux --use-signing-config=false --tlog-upload=false
gardent la signature vérifiable hors-ligne : sans eux, cosign 3.x publie
dans le journal de transparence public — un appel réseau qu’un signataire
de zone restreinte ne devrait pas faire, et une consultation que la
destination ne pourrait de toute façon pas effectuer.
5. Déclarer l’état désiré de la zone
Section intitulée « 5. Déclarer l’état désiré de la zone »Un Retriever nomme ce que la zone doit contenir. Écrivez
retriever.yaml :
apiVersion: recipe.tobby.dev/v1alpha1kind: Retriever
metadata: name: zone-demo
spec: cookbook: 127.0.0.1:5001/cookbook recipes: - name: alpine version: "3.22.1"Une version exacte est prise au mot ; une contrainte (6.x, ~0.16.1)
se résout contre le cookbook à chaque synchronisation — une version
corrective arrive en la publiant, sans fichier à modifier.
6. Pointer votre instance dessus
Section intitulée « 6. Pointer votre instance dessus »Arrêtez l’instance de l’étape 1 avec Ctrl-C — l’arrêt est gracieux —
et ajoutez trois choses à son tobby.yaml : le Retriever, la racine de
confiance, et l’accord HTTP simple pour le registre jetable :
retriever: source: ./retriever.yaml # un fichier, une URL https://, ou une référence OCI
trust: roots: - name: cle-signature-demo keyFile: ./cosign.pub
registries: insecure: ["127.0.0.1:5001"]Puis redémarrez :
tobby serve --config ./tobby.yaml7. Promouvoir
Section intitulée « 7. Promouvoir »En mode passthrough l’instance réconcilie sur son propre rythme (toutes les 15 minutes par défaut). Déclenchez un cycle tout de suite : l’écran Recipes propose une action de synchronisation, ou en ligne de commande :
curl -u admin -X POST http://localhost:8080/api/v1/syncObservez l’écran Tâches : la synchronisation résout le Retriever,
récupère la recipe depuis le cookbook, vérifie sa signature cosign contre
votre racine de confiance, puis tire l’image directement depuis
docker.io et la contrôle contre le digest épinglé — en ne transférant
que ce qui manque à la zone. L’écran Recipes montre alors la recipe,
sa version résolue et son verdict de vérification.

Relancez la synchronisation : elle se termine sans rien transférer — la zone correspond déjà à son état désiré.
8. Tirer depuis le registre de zone
Section intitulée « 8. Tirer depuis le registre de zone »Le registre embarqué de votre instance sert désormais le contenu promu. Docker s’authentifie avec le même compte que l’interface :
docker login 127.0.0.1:8080 # le compte créé par le quickstartdocker pull 127.0.0.1:8080/docker.io/library/alpine:3.22.1Si votre daemon Docker tourne dans une VM (Rancher Desktop, certains
montages Colima), son 127.0.0.1 est la VM, pas votre machine — utilisez
l’adresse LAN de votre hôte dans les deux commandes.
Le pull réussit, digest intact : l’image a été transportée, vérifiée et servie — jamais réécrite, jamais re-signée. Le chemin dit d’où vient le contenu ; pourquoi c’est important, et comment brancher de vrais clients (mirrors containerd, GitOps), c’est dans Brancher vos clients.
Ce que vous venez de faire
Section intitulée « Ce que vous venez de faire »La scène était petite, mais rien n’était simulé : une recipe signée dans un cookbook, une zone qui déclare son état désiré, une promotion qui vérifie tout avant de servir. La production ne change que les adresses — le cookbook part sur un registre alimenté par votre processus de qualification, le Retriever se publie comme artefact OCI, les clés viennent de ce même processus.
Et maintenant
Section intitulée « Et maintenant »- Zones connectées (passthrough) — le cas d’usage livré, en vrai : architecture et promotion continue, puis Déployer sur Kubernetes ou en VM.
- Zones isolées (air-gap) — la même promotion, portée sur un média amovible : le parcours média.
- Écrire vos propres recipes — le raisonnement derrière une liste d’ingrédients, et les pièges : écrire, publier et signer.
- Lecteur sécurité ? — le modèle derrière ce que vous venez de voir, en une page : le one-pager sécurité.