Minimale Docker-Images, die an sich selbst glaubten*

[Verweis auf das amerikanische Kinderbuch 'Der kleine Zug, der es versuchen wollte' ('The Little Engine That Could') — Anm. d. Übers.] *

Minimale Docker-Images, die an sich selbst glaubten*

Wie man automatisch kleine Docker-Images für seine Bedürfnisse erstellt

Ein unerwartetes Obsession

In den letzten Monaten war ich fasziniert von der Idee: Wie klein kann ein Docker-Image werden, ohne dass die Anwendung dabei nicht mehr funktioniert?

Ich weiß, die Idee ist seltsam.

Bevor ich tiefer in die Details und technischen Feinheiten eintauche, möchte ich erklären, warum mich dieses Problem so fasziniert und wie es Sie betrifft.

Warum die Größe wichtig ist

Indem wir den Inhalt des Docker-Images reduzieren, verringern wir gleichzeitig die Anzahl der Schwachstellen. Zudem machen wir die Images sauberer, da sie nur das enthalten, was zur Ausführung der Anwendungen benötigt wird.

Es gibt noch einen kleinen Vorteil — die Images werden etwas schneller heruntergeladen, aber für mich ist das nicht besonders wichtig.

Bitte beachten Sie: Wenn Sie sich um die Größe sorgen, sind Alpine-Images von Natur aus klein und sollten wahrscheinlich Ihren Anforderungen entsprechen.

Distroless-Images

Das Distroless-Projekt bietet eine Sammlung von grundlegenden "distroless"-Images, die keine Paketmanager, Shells oder andere Tools enthalten, die Sie normalerweise in der Kommandozeile sehen. Daher können Paketmanager wie pip und apt nicht verwendet werden:

FROM gcr.io/distroless/python3
RUN pip3 install numpy

Dockerfile, das ein distroless-Python 3-Image verwendet

Sende den Build-Kontext an den Docker-Daemon  2.048kB
Schritt 1/2 : FROM gcr.io/distroless/python3
 ---> 556d570d5c53
Schritt 2/2 : RUN pip3 install numpy
 ---> Wurde ausgeführt in dbfe5623f125
/bin/sh: 1: pip3: nicht gefunden

Pip ist im Image nicht vorhanden

Normalerweise wird dieses Problem durch Multi-Stage-Builds gelöst:

FROM python:3 als builder
RUN pip3 install numpy

FROM gcr.io/distroless/python3
COPY --from=builder /usr/local/lib/python3.7/site-packages /usr/local/lib/python3.5/

Multi-Stage-Build

Das Ergebnis ist ein Image mit einer Größe von 130MB. Das ist gar nicht so schlecht! Zum Vergleich: Das standardmäßige Python-Image wiegt 929MB, während die "schlanke" Version (3.7-slim) 179MB wiegt, und das Alpine-Image (3.7-alpine) wiegt 98,6MB, während das grundlegende distroless-Image im Beispiel 50,9MB beträgt.

Es könnte berechtigt sein zu erwähnen, dass wir im vorherigen Beispiel ein gesamtes Verzeichnis kopieren, /usr/local/lib/python3.7/site-packagesin dem möglicherweise unerwünschte Abhängigkeiten liegen. Dennoch ist klar, dass die Größenunterschiede aller vorhandenen Basis-Python-Images variieren.

Zum Zeitpunkt des Verfassens dieser Zeilen unterstützt Google Distroless nicht allzu viele Images: Java und Python befinden sich noch in der experimentellen Phase, und Python existiert nur für 2.7 und 3.5.

Winzige Images

Kehren wir zu meiner Besessenheit zurück, kleine Images zu erstellen.

Eigentlich wollte ich sehen, wie Distroless-Images aufgebaut sind. Das Distroless-Projekt nutzt das von Google entwickelte Build-Tool bazel. Um Bazel zu installieren und eigene Images zu erstellen, musste ich jedoch ordentlich Arbeit investieren (um ehrlich zu sein, es macht Spaß und ist lehrreich, das Rad neu zu erfinden). Ich wollte die Erstellung von verkleinerten Images vereinfachen: der Vorgang des Erstellens eines Images sollte so einfach wie möglich sein, banal. Keine Konfigurationsdateien, nur eine Zeile in der Konsole: einfach ein Image für <Anwendung> bauen.

Wenn Sie also eigene Images erstellen möchten, beachten Sie bitte: Es gibt dieses einzigartige Docker-Image, scratch. Scratch ist ein "leeres" Image, es enthält keine Dateien und wiegt standardmäßig — wow! — 77 Bytes.

FROM scratch

Das Scratch-Image

Die Idee hinter dem Scratch-Image ist, dass man beliebige Abhängigkeiten vom Hostsystem in dieses kopieren kann und sie entweder innerhalb des Dockerfiles verwendet oder die Dateien direkt in das Image kopiert apt und von Grund auf installieren), oder später, wenn das Docker-Image erstellt wurde. Dies ermöglicht eine vollständige Kontrolle über den Inhalt des Docker-Containers und somit auch über die Größe des Images.

Jetzt müssen wir eine Möglichkeit finden, diese Abhängigkeiten zu bündeln. Bestehende Tools wie apt laden Pakete herunter, sind jedoch an die aktuelle Maschine gebunden und unterstützen schließlich kein Windows oder MacOS.

Also habe ich angefangen, ein eigenes Tool zu entwickeln, das automatisch ein Basis-Image mit der kleinsten möglichen Größe erstellt und gleichzeitig jede Anwendung ausführen kann. Ich verwendete Pakete von Ubuntu/Debian, holte die Pakete direkt aus den Repositories und fand ihre Abhängigkeiten rekursiv. Das Programm sollte automatisch die neueste stabile Version des Pakets herunterladen und dabei die Sicherheitsrisiken so weit wie möglich minimieren.

Ich nannte das Tool fetchy, weil es… findet und bringt… was man braucht [von engl. „fetch“, „bringen“ — Anm. d. Übers.]. Das Tool funktioniert über eine Befehlszeilenoberfläche, bietet aber gleichzeitig auch eine API.

Um ein Image mithilfe von fetchy (nehmen wir diesmal das Python-Image), Sie müssen die CLI nur so verwenden: fetchy dockerize python. Es könnte nach dem Zielbetriebssystem und dem Codenamen gefragt werden, da fetchy derzeit nur Debian- und Ubuntu-basierte Pakete verwendet werden.

Jetzt können Sie auswählen, welche Abhängigkeiten in unserem Kontext völlig überflüssig sind und diese ausschließen. Zum Beispiel benötigt Python perl, funktioniert jedoch hervorragend ohne installierten Perl.

Ergebnisse

Das Python-Image, das mit dem Befehl fetchy dockerize python3.5 erzeugt wurde, wiegt nur 35 MB (ich bin mir ziemlich sicher, dass es in Zukunft noch weiter optimiert werden kann). Dadurch konnten wir von dem distroless-Image weitere 15 MB einsparen.

Alle bisher erstellten Images können angezeigt werden. hier.

Projekt — hier.

Wenn Ihnen Funktionen fehlen, erstellen Sie einfach eine Anfrage – ich helfe Ihnen gerne 🙂 Noch mehr, ich arbeite derzeit an der Integration anderer Paketmanager in fetchy, damit die Notwendigkeit für mehrstufige Builds entfällt.

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster