Zum Inhalt springen
use-cases / push-one-build-to-thirty-ci-workers / hero
PIPE · CI FAN-OUT

Einen Build gleichzeitig an dreißig CI-Worker pushen

Deine Matrix-CI fächert sich über dreißig Test-Runner auf. Jeder davon braucht dasselbe 800-MB-Image. Stream das Tarball mit ?n=30 in einen Pipe-Pfad. Alle dreißig Worker rufen dieselbe URL per curl ab. Die Bytes laufen einmal durch, der Server hält nichts, und keine Registry-Credentials werden rotiert.

Pipe-Docs lesen
use-cases / push-one-build-to-thirty-ci-workers / mechanism

Wie aus dreißig curls ein Stream wird

Die Pipe ist ein Fan-out-Router ohne Disk. Der POST des Senders auf /api/v1/pipe/[path]?n=30 blockiert, bis dreißig Empfänger sich mit demselben n auf derselben URL verbinden. Dann fließen die Bytes vom Build-Container direkt zu jedem Runner — gleichzeitig, in der Geschwindigkeit des langsamsten Empfängers.

Drei Schritte. Keine Registry, kein S3, keine Cache-Action.PIPE · ?n=30
01

Build streamt einmal

tar c | curl -T - https://pipe/.../build?n=30

Der Build-Container pipet das Tarball direkt in curl. Keine Datei geschrieben, keine Registry gepusht.

02

Pipe wartet auf die Flotte

POST /api/v1/pipe/[path]?n=30

Der Server hält den Sender, bis alle dreißig Empfänger verbinden. Abweichendes n liefert 400. Vorab verbundene Empfänger sind okay.

03

Alle dreißig ziehen dieselbe URL

curl https://pipe/.../build?n=30 | tar x

Jeder Runner bekommt identische Bytes. Backpressure kommt vom langsamsten Empfänger, nicht von der Bandbreite des Senders.

Nichts persistiert. Nichts wird gecached. Die Pipe vermittelt die Verbindung und tritt dann zurück. Wenn der langsamste Runner fertig ist, ist der Transfer fertig — und die URL ist weg.

use-cases / push-one-build-to-thirty-ci-workers / numbers

Was es die Matrix kostet

Naiv: dreißig Registry-Pulls desselben 800-MB-Tarballs, dreißig kalte Caches, dreißig Netzwerk-Round-Trips. Pipe: ein Egress, ein Transfer, der langsamste Empfänger gibt das Tempo vor.

WALL TIME

12s

Ein Egress mit Linerate. Der langsamste Empfänger bestimmt das Tempo, aber niemand lädt erneut.

EGRESS

1× / Build

Bytes verlassen den Builder einmal, fächern sich an der Pipe auf. Keine S3-GET-Gebühren, keine Docker-Hub-Pulls.

STORAGE

0 Bytes

Die Pipe hält nichts auf Disk. Keine Registry zum Aufräumen, kein Cache-Key zum Invalidieren.

Die Wall-Time-Zahl geht von einer 30-fachen Matrix im selben regionalen Netz wie der Build-Container aus; Cross-Region-Transfers hängen an der Inter-Region-Bandbreite, nicht an der Pipe.

use-cases / push-one-build-to-thirty-ci-workers / powers

Was das Fan-out freischaltet

Sobald der Build eine URL und dreißig curls ist, fällt ein ganzer Stack an CI-Gerüst weg. Kein Artefakt-Storage zum Altern. Keine Registry-Credentials zum Rotieren. Keine Cache-Action zum Debuggen.

Der langsamste Empfänger gibt das Tempo vor

Backpressure ist in die Pipe eingebaut. Die schnellen Worker verschwenden keinen Registry-Round-Trip, um auf den langsamen zu warten — sie warten an der Pipe und trinken dann im selben Tempo. Niemand lädt erneut.

Keine Registry-Credentials zu rotieren

Nichts wird in eine Registry gepusht, also muss sich auch nichts daran authentifizieren. Die URL selbst ist das Credential — kurzlebig, auf einen Transfer beschränkt, evictet, wenn der Build fertig ist.

Keine S3-Rechnung, keine Egress-Überraschung

Bytes verlassen den Builder einmal. Die Pipe broadcastet. Du zahlst einen Egress pro Build statt dreißig Registry-Pulls pro Matrix-Run.

Kein Cache-Key zum Invalidieren

Die Pipe ist pro Build, nicht pro Key. Es gibt keinen GitHub-Actions-Cache, der danebenliegt, kein Buildx-Layer-Mysterium, kein abgestandenes Tarball vom letzten Main.

Funktioniert für jedes Tarball, nicht nur Images

Dasselbe Muster handhabt node_modules, .pnpm-store, target/, den Wheel-Cache, den Dataset-Shard. Was streamt, fächert sich auf.

use-cases / push-one-build-to-thirty-ci-workers / punchline

Ein Sender. Dreißig Empfänger. Null S3-Rechnungen.

Ein 30-fach-Push, der neunzig Sekunden und einen S3-Hit gekostet hat, dauert zwölf Sekunden und einen einzigen Egress. Niemand lädt erneut. Keine Registry-Credentials werden rotiert. Die URL evictet sich selbst, wenn die Matrix fertig ist.

  • 1 EGRESS
  • 30 EMPFÄNGER
  • 0 STORAGE
  • 0 CREDENTIALS
Pipe-API öffnen
use-cases / push-one-build-to-thirty-ci-workers / replaces

Was das ersetzt

Die Teile, die ein Matrix-CI-Flow normalerweise zusammensetzen muss — Registry, Cache-Action, Mirror, Custom-Upload-Schritt. Die Pipe faltet sie in eine URL.

  • AWS S3 (Registry-Storage + Egress)30× GET-Gebühren pro Build, Eviction-Policy, IAM-Rolle
  • GitHub Actions Cache10-GB-Limit, Key-Kollisionen, Scope-pro-Branch
  • Docker Hub PullsRate-limitiert, kostenpflichtiger Mirror gegen Throttling
  • npm / pnpm Registry-MirrorSelbst gehostetes Verdaccio nur, um die Public Registry zu umgehen
  • Custom CI-Cache-ActionBash-Glue, S3-SDK, Expiry-Logik, On-Call wenn's bricht
  • Buildx Layer-Cache-ExportLayer-Format-Eigenheiten, Cross-Runner-Cache-Misses
use-cases / push-one-build-to-thirty-ci-workers / cta

Hör auf, dasselbe Tarball dreißig Mal zu pushen. Push es einmal. Lass dreißig curls den Stream teilen.

Pipe-API lesen
use-cases / push-one-build-to-thirty-ci-workers / related

Lies die anderen