Container-Images mit mehreren Architekturen für IoT-Geräte

Dieses Dokument ist der erste Teil einer Reihe, in der die Erstellung einer automatisierten CI-Pipeline (Continuous Integration, CI) zum Erstellen von Container-Images mit mehreren Architekturen in Google Cloud erläutert wird. Die in diesem Dokument erläuterten Konzepte gelten für jede Cloud-Umgebung.

Die Reihe besteht aus diesem Dokument und einer zugehörigen Anleitung. In diesem Dokument wird die Struktur einer Pipeline zum Erstellen von Container-Images und die allgemeinen Schritte erläutert. Diese Anleitung führt Sie durch ein Beispiel für das Erstellen einer Pipeline.

Diese Reihe richtet sich an IT-Fachleute, die komplexe Pipelines zum Erstellen von Container-Images vereinfachen oder optimieren möchten, oder um diese Pipelines zu erweitern, damit Images für mehrere Architekturen erstellt werden können. Es wird davon ausgegangen, dass Sie mit Cloud-Technologien und Containern vertraut sind.

Wenn Sie eine CI-Pipeline implementieren, optimieren Sie die Erstellung von Artefakten. Sie benötigen keine speziellen Tools und Hardware, um Container-Images für eine bestimmte Architektur zu erstellen. Wenn Ihre aktuelle Pipeline beispielsweise in einer x86_64-Architektur ausgeführt wird und nur Container-Images für diese Architektur erzeugt werden, müssen Sie möglicherweise zusätzliche Tools und Hardware bereitstellen, wenn Sie Container-Images für andere Architekturen erstellen möchten, z. B. für die ARM-Familie.

Die Domain des Internet der Dinge (IoT) erfordert häufig mehrere Architekturen. Wenn Sie eine große Anzahl von Geräten mit verschiedenen Hardware- und Betriebssystem-Stacks haben, ist das Erstellen, Testen und Verwalten von Softwareanwendungen für ein bestimmtes Gerät eine große Herausforderung. Die Verwendung eines mehrstufigen Erstellungsprozesses vereinfacht die Verwaltung von IoT-Anwendungen.

Herausforderung beim Erstellen von Container-Images für mehrere Architekturen

In den meisten Implementierungen sind Container-Images architekturabhängig. Wenn Sie beispielsweise ein Container-Image für die Architektur xx86_64 erstellen, kann es nicht in einer Architektur der ARM-Familie ausgeführt werden.

Sie können diese Beschränkung auf verschiedene Arten umgehen:

  1. Erstellen Sie die Container-Images in den Zielarchitekturen, für die Sie das Container-Image benötigen.
  2. Hier finden Sie dedizierte Tools und eine Hardwareflotte. Ihre Flotte benötigt mindestens ein Gerät für jede Architektur, für die Sie ein Container-Image erstellen müssen.
  3. Container-Images mit mehreren Architekturen erstellen.

Welche Strategie für Sie am besten geeignet ist, hängt unter anderem von folgenden Faktoren ab:

  • Komplexität der Pipeline
  • Anforderungen an die Automatisierung
  • Zum Erstellen, Implementieren und Verwalten der Umgebung für die Erstellung von Container-Images verfügbare Ressourcen

Wenn Ihre Laufzeitumgebung beispielsweise nur eingeschränkten Zugriff auf eine Stromversorgung hat, müssen Sie die Container-Images möglicherweise in einer anderen Umgebung als der Laufzeitumgebung erstellen.

Das folgende Diagramm veranschaulicht die Entscheidungspunkte bei der Auswahl einer brauchbaren Strategie.

Flussdiagramm zur Entscheidung für die beste Strategie zum Erstellen von Container-Images mit mehreren Architekturen.

Container-Images in den Zielarchitekturen erstellen

Eine Möglichkeit besteht darin, jedes Container-Image zu erstellen, das Sie direkt in der Laufzeitumgebung benötigen, die den Container selbst unterstützt, wie das folgende Diagramm zeigt.

Erstellen Sie den Pfad vom Quellcode-Repository zur Laufzeitumgebung.

Führen Sie für jeden Build folgende Schritte aus:

  1. Laden Sie den Quellcode des Container-Images aus einem Quellcode-Repository auf jedem Gerät in der Laufzeitumgebung herunter.
  2. Erstellen Sie das Container-Image in der Laufzeitumgebung.
  3. Speichern Sie das Container-Image im Container-Image-Repository, das für jedes Gerät in der Laufzeitumgebung lokal gespeichert ist.

Der Vorteil dieser Strategie besteht darin, dass Sie neben der für die Laufzeitumgebung erforderlichen Hardware keine Hardware bereitstellen und verwalten müssen. Diese Strategie hat auch Nachteile. Zuerst müssen Sie den Build-Prozess für jede Hardwareinstanz in Ihrer Laufzeitumgebung wiederholen, damit Ressourcen verschwendet werden. Wenn Sie beispielsweise Ihre containerisierten Arbeitslasten in einer Laufzeitumgebung bereitstellen, in der Geräte keinen kontinuierlichen Stromverbrauch haben, verschwenden Sie Zeit und Leistung, indem Sie für jedes Gerät Build-Aufgaben ausführen. Sie müssen eine neue Version einer Arbeitslast bereitstellen. Sie müssen auch die Tools verwalten, um auf den Quellcode jedes Container-Images zugreifen zu können, um Container-Images in Ihrer Laufzeitumgebung zu erstellen.

Spezielle Tools und Hardwareflotten verwalten

Eine zweite Strategie besteht darin, eine Hardwareflotte zu verwalten, die ausschließlich für Aufgaben zur Erstellung von Container-Images vorgesehen ist. Das folgende Diagramm veranschaulicht die Architektur dieser Strategie.

Erstellen Sie den Pfad vom Quellcode-Repository zu einer dedizierten Build-Umgebung.

Führen Sie für jeden Build folgende Schritte aus:

  1. Laden Sie den Quellcode des Container-Images auf ein Gerät in der Flotte herunter, das über die erforderliche Hardwarearchitektur und die Ressourcen zum Erstellen des Container-Images verfügt.
  2. Erstellen Sie das Container-Image.
  3. Speichern Sie das Container-Image in einem zentralen Container-Image-Repository.
  4. Laden Sie das Container-Image auf jedes Gerät in der Laufzeitumgebung herunter, wenn Sie eine neue Instanz dieses Images bereitstellen müssen.

Bei dieser Strategie stellen Sie mindestens eine Instanz jeder Hardwarearchitektur bereit, für die Sie Container-Images erstellen müssen. In einer trivialen Produktionsumgebung haben Sie möglicherweise mehr als eine Instanz, um die Fehlertoleranz Ihrer Umgebung zu erhöhen und die Build-Zeiten zu verkürzen, wenn mehrere gleichzeitige Build-Jobs vorhanden sind.

Diese Strategie bietet einige Vorteile. Zuerst können Sie jeden Build-Job nur einmal ausführen und das resultierende Container-Image in einem zentralen Container-Image-Repository wie Container Registry speichern. Außerdem können Sie Testsuites auf den Geräten im Gebäudepool ausführen, die eng an die Hardwarearchitekturen in Ihren Laufzeitumgebungen angepasst sind. Der Hauptvorteil dieser Strategie besteht darin, dass Sie eine dedizierte Infrastruktur und Tools bereitstellen und pflegen müssen, um die Aufgaben auszuführen, mit denen Container-Images erstellt werden. Normalerweise benötigt jede Gebäudeaufgabe nicht viele Ressourcen oder ausreichend Zeit, damit diese Infrastruktur die meiste Zeit inaktiv ist.

Container-Images mit mehreren Architekturen erstellen

In dieser dritten Strategie verwenden Sie eine allgemeine Pipeline, um Container-Images mit mehreren Architekturen zu erstellen, wie das folgende Diagramm zeigt.

Erstellen Sie den Pfad vom Quellcode-Repository zur allgemeinen Pipeline für mehrere Architekturen.

Führen Sie für jeden Build folgende Schritte aus:

  1. Laden Sie den Quellcode des Container-Images herunter.
  2. Erstellen Sie das Container-Image.
  3. Speichern Sie das Container-Image in einem zentralen Container-Image-Repository.
  4. Laden Sie das Container-Image auf jedes Gerät in der Laufzeitumgebung herunter, wenn Sie eine neue Instanz dieses Images bereitstellen müssen.

Der Hauptvorteil dieser Strategie besteht darin, dass Sie keine speziellen Hardware oder Tools bereitstellen und verwalten müssen. Sie können zum Beispiel vorhandene CI-/CD-Pipelines und -Tools verwenden, um Container-Images mit mehreren Architekturen zu erstellen. Auch die Leistung einer allgemeinen Hardwarearchitektur, wie x86_64, kann im Vergleich zu einer energieeffizienten Architektur wie der ARM-Familie hilfreich sein.

Diese Strategie kann auch Teil einer umfassenderen Initiative sein, in der Sie DevOps-Prinzipien anwenden. Sie können beispielsweise eine CI/CD-Pipeline für spezielle Hardware implementieren.

Pipeline zum Erstellen von Container-Images mit mehreren Architekturen implementieren

In diesem Abschnitt beschreiben wir eine Referenzimplementierung einer CI/CD-Pipeline, die der dritten Strategie folgt – dem Erstellen von Container-Images für mehrere Architekturen.

Die Referenzimplementierung hat die folgenden Komponenten:

  • Ein Quellcode-Repository zur Verwaltung des Quellcodes für Container-Images. Sie können beispielsweise Cloud Source Repositories oder GitLab-Repositories verwenden.
  • Eine CI/CD-Laufzeitumgebung zum Erstellen von Container-Images wie Cloud Build.
  • Eine Plattform zum Verwalten von Containern und Container-Images, die Container-Images mit mehreren Architekturen unterstützen, z. B. Docker
  • Eine Container-Image-Registry, z. B. Container Registry. Wenn Sie die Container-Images näher an den Knoten speichern möchten, auf denen die Images erforderlich sind, können Sie eine Container-Image-Registry, z. B. Docker Registry, direkt in der aktuellen Umgebung ausführen.

In dieser Referenzarchitektur werden mit Moby BuildKit und QEMU Docker-Container-Images mit mehreren Architekturen erstellt. In diesem Fall erkennt Moby BuildKit automatisch die in der EEMU-Hardwareemulation verfügbaren Architekturen und lädt automatisch die entsprechenden Binärdateien herunter, die in der Funktion binfmt_BAR des Linux-Kernelregistriert sind.

Das folgende Diagramm veranschaulicht den technischen Stack, der für die Erstellung aller Container-Images mit mehreren Architekturen verantwortlich ist, die von dieser Referenzarchitektur unterstützt werden.

Ähnliche Komponenten für diese Referenzarchitektur mit mehreren Architekturen.

Da in dieser Referenzarchitektur Docker-Image-Manifeste verwendet werden, müssen Sie nicht für jede Zielhardwarearchitektur ein Container-Image-Tag bereitstellen. Sie können dasselbe Tag für mehrere Architekturen verwenden. Wenn Sie beispielsweise die 1.0.0-Version eines Container-Images mit mehreren Architekturen erstellen, benötigen Sie kein eindeutiges Tag für jede Hardwarearchitektur, wie z. B. 1.0.0-x86_64 oder 1.0.0_ARMv7. Verwenden Sie für alle Hardwarearchitekturen, die Sie erstellen, das gleiche 1.0.0-Tag, und verwenden Sie Docker-Image-Manifeste, um jedes Container-Image korrekt zu identifizieren.

Das folgende Beispiel zeigt das Image-Manifest für das offizielle Alpine Linux-Image. Dort finden Sie Informationen zu den Architekturen, die eine bestimmte Version dieses Container-Images unterstützt:

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 528,
         "digest": "sha256:ddba4d27a7ffc3f86dd6c2f92041af252a1f23a8e742c90e6e1297bfa1bc0c45",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 528,
         "digest": "sha256:401f030aa35e86bafd31c6cc292b01659cbde72d77e8c24737bd63283837f02c",
         "platform": {
            "architecture": "arm",
            "os": "linux",
            "variant": "v7"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 528,
         "digest": "sha256:2c26a655f6e38294e859edac46230210bbed3591d6ff57060b8671cda09756d4",
         "platform": {
            "architecture": "arm64",
            "os": "linux"
         }
      }
   ]
}

Wenn Sie eine automatisierte Pipeline zum Erstellen von Container-Images erstellen, empfehlen wir, dass Sie umfassende Testsuiten einbinden, mit denen die Einhaltung der Anforderungen jedes Container-Images validiert wird. Beispielsweise können Sie Tools wie Chef InSpec, Serverspec und RSpec verwenden, um als Bestandteil der Build-Pipeline Compliance-Testsuiten für Ihre Container-Images auszuführen.

Pipeline zum Erstellen von Container-Images optimieren

Nachdem Sie die Pipelines zum Erstellen Ihrer Container-Images validiert und konsolidiert haben, optimieren Sie die Pipelines. Migration zu Google Cloud: Umgebung optimieren enthält Informationen zur Optimierung Ihrer Umgebung. Dabei wird ein Optimierungs-Framework beschrieben, mit dem Sie Ihre Umgebung im Vergleich zum aktuellen Status effizienter gestalten können. Indem Sie dem Optimierungs-Framework folgen, durchlaufen Sie mehrere Iterationen, durch die Sie den Status der Umgebung ändern können.

Eine der ersten Aktivitäten der jeweiligen Iteration ist das Festlegen einer Reihe von Anforderungen und Zielen für diese Iteration. Eine Voraussetzung ist beispielsweise, Ihre Bereitstellungsprozesse zu modernisieren und von manuellen Bereitstellungsprozessen zu vollständig automatisierten, containerisierten Prozessen zu migrieren. Weitere Informationen zur Modernisierung Ihrer Bereitstellungsprozesse finden Sie unter Migration zu Google Cloud: Von manuellen zu automatisierten, containerisierten Bereitstellungen migrieren.

Nächste Schritte