Zum Inhalt springen

Multi-Arch Images für Docker per Docker Hub

Oben: Raspberry Pi Zero WH: 1 ARMv6 Prozessor, 1 Kern, 512MB RAM, 15€
Unten: „Rambo“, 2 Xeon Prozessoren, 32 Kerne (64 mit Hyperthreading), 128GB RAM, >2500€

Docker ist omnipräsent, ebenso wie es extrem günstige linuxfähige System on a Chip (SoC)-Geräte sind. Nach Beagleboard, Pandaboard, diversen Raspberry Pi etc sind wir bei 15€ pro System inkl. WiFi angekommen. Unfassbar für ein vollwertiges System, dessen Fähigkeiten für so manchen Büroarbeitsplatz ausreichen würden.

Die logische Konsequenz: Wenn man auf jedem Stück Blech die neuesten Linux-Distributionen und Kernel-Versionen laufen lassen kann, warum dann auch nicht Docker?

Man möchte allerdings die bestmöglichste Hardware (bzw Cloud-Service) zum Bau von Images für alle Plattformen nutzen und verwendet daher Cross-Compilation (typischerweise unter amd64/x86_64).

Die technischen Details sind nichts neues, deshalb erspare ich sie euch bis auf eine kurze Umschreibung: QEMU als Emulator, binfmt_misc um architekturfremde Binaries durch QEMU ausführen zu lassen. Und um das ganze mit Docker zu verheiraten, schiebt man das statische QEMU binary in den Build-Context und zwar an die Location, die man dem Kernel vorher global konfiguriert hat. Mehr dazu steht beispielsweise hier.

Zwei Dingen fehlten mir jedoch bis dahin:

  1. Ich lasse Docker Hub automatisch Images aus GitHub Repositories bauen und möchte, dass Docker Hub mir für alle von mir gewünschten Architekturen automatisch Images baut.
  2. Ich möchte einen gemeinsamen tag für alle Plattformen haben, d.h. egal auf welchem system docker pull rmoriz/multiarch-test:latest soll das passende Image zurückliefern.

Die Integration Dockerhub lässt sich mit etwas Shell-Frickelei lösen, hat man dort doch relativ großzügige root-Rechte, kann den gesamten Build-Prozess mit Shellscripts anpassen oder überschreiben und natürlich Pakete installieren. Sogar das Setzen von binfmt war problemlos möglich. Erstaunlicherweise war das größte Problem die dort eingesetze steinalte Docker EE-Version auf Client-Seite. Auch hier kann man glücklicherweise stattdessen ein eigenes, neueres Binary ausführen.

Um mehrere Architekturen hinter einem tag zu verbergen, muss man Manifests anlegen. Alles noch experimental, erfordert das neueste docker-cli und schlecht dokumentiert.

Der grobe Ablauf:

  1. Installiere QEMU Pakete, eigener docker client
  2. registriere binfmt handler
  3. baue alle images mit jeweils eigenen Tags für jede Architektur
  4. exportiere alle images auf festplatte, patche im Image-Manifest die Architektur auf die Zielarchitektur (hier wird IMMER die aktuelle dockerd-Architektur übernommen)
  5. importiere den Kram wieder
  6. pushe die Images in die Registry
  7. Erstelle ein Manifest
  8. Annotate das Manifest, damit die Archtekturen stimmen (eventuell durch 4. überflüssig geworden)
  9. pushe das Manifest in die Registry
  10. done

Große Frickelei, für euch an zwei Abenden durch trial+error gebaut:

Source Code hier: https://github.com/rmoriz/multiarch-test

Beispiel Log des Builds: https://gist.github.com/rmoriz/4204f1f30eeda3892248e797024ed794

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

* Die DSGVO-Checkbox ist ein Pflichtfeld

*

Ich stimme zu