Winzige Docker-Images, die an sich glaubten*

[Verweis auf das amerikanische Kinderbuch „Der kleine Zug, der es schaffen kann“ — Anm. d. Übers.]

Winzige Docker-Images, die an sich glaubten*

Wie man automatisch winzige Docker-Images für eigene Bedürfnisse erstellt

Ungewöhnliche Besessenheit

In den letzten Monaten war ich von der besessenen Idee eingenommen: Wie klein kann ein Docker-Image sein, so dass die Anwendung trotzdem funktioniert?

Ich verstehe, die Idee ist seltsam.

Bevor ich in die Details und technischen Feinheiten eintauche, möchte ich erläutern, warum mich dieses Problem so interessiert hat und wie es Sie betrifft.

Warum die Größe wichtig ist

Durch die Reduzierung des Inhalts des Docker-Images verringern wir gleichzeitig die Liste der Sicherheitsanfälligkeiten. Zusätzlich machen wir die Images sauberer, da sie nur das enthalten, was zur Ausführung von Anwendungen benötigt wird.

Es gibt einen weiteren kleinen Vorteil: Die Images werden etwas schneller heruntergeladen, aber das ist meiner Meinung nach nicht so wichtig.

Hinweis: Wenn Ihnen die Größe wichtig ist, sind Alpine-Images von Natur aus klein und passen sicherlich zu Ihnen.

Distroless-Images

Das Projekt Distroless bietet eine Auswahl an Basis-„distroless“-Images, die keine Paketmanager, Shells und anderen Utilities enthalten, die Sie normalerweise in der Befehlszeile sehen. Daher kann man Paketmanager wie pip und apt nicht verwenden:

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

Dockerfile, das ein Distroless-Image von Python 3 verwendet

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

Pip ist im Image nicht vorhanden

In der Regel wird dieses Problem durch eine Multi-Stage-Build 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 von 130MB. Gar nicht so schlecht! Zum Vergleich: Das Standard-Python-Image wiegt 929MB und das „abgespeckte“ (3,7-slim) — 179MB, Alpine-Image (3,7-alpine) — 98,6MB, während das verwendete Basis-Distroless-Image im Beispiel — 50,9MB wiegt.

Man könnte berechtigterweise anmerken, dass wir im vorherigen Beispiel ein ganzes Verzeichnis kopieren, /usr/local/lib/python3.7/site-packagesin dem sich möglicherweise unnötige Abhängigkeiten befinden. Es ist jedoch klar, dass die Größenunterschiede aller bestehenden Basis-Python-Images schwanken.

Zum Zeitpunkt des Schreibens unterstützt Google Distroless nicht viele Images: Java und Python befinden sich noch im experimentellen Stadium, und Python existiert nur für 2,7 und 3,5.

Winzige Images

Kommen wir zurück zu meiner Obsession, kleine Images zu erstellen.

Ich wollte mir eigentlich ansehen, wie distroless-Images aufgebaut sind. Das Distroless-Projekt verwendet Googles Build-Werkzeug bazel. Um Bazel zu installieren und eigene Images zu erstellen, musste ich jedoch hart arbeiten (um ganz ehrlich zu sein, das Rad neu zu erfinden macht Spaß und ist lehrreich). Ich wollte die Erstellung von reduzierten Images vereinfachen: Der Akt der Bildgenerierung sollte so einfach wie möglich sein, banal. Es sollten keine Konfigurationsdateien notwendig sein, nur ein einziger Befehl in der Konsole: einfach ein Image für bauen.

Also, wenn ihr eigene Images erstellen möchtet, wisst ihr: Es gibt ein einzigartiges Docker-Image, scratch. Scratch ist ein "leeres" Image, es enthält keine Dateien, obwohl es standardmäßig — wow! — 77 Byte wiegt.

FROM scratch

Das Scratch-Image

Die Idee des Scratch-Images ist, dass man beliebige Abhängigkeiten von der Host-Maschine kopieren kann und sie entweder innerhalb des Dockerfile verwenden kann (das ist wie sie zu kopieren und von Grund auf neu zu installieren) oder später, wenn das Docker-Image materialisiert ist. Das ermöglicht eine vollständige Kontrolle über den Inhalt des Docker-Containers und somit auch über die Größe des Images. apt Nun müssen wir diese Abhängigkeiten irgendwie sammeln. Existierende Werkzeuge wie

erlauben das Herunterladen von Paketen, sind jedoch an die aktuelle Maschine gebunden und unterstützen letztendlich nicht Windows oder macOS. apt Also habe ich mich daran gemacht, ein eigenes Werkzeug zu entwickeln, das automatisch das Basis-Image mit der geringstmöglichen Größe zusammenstellt und zudem jede Anwendung ausführen kann. Ich habe Pakete von Ubuntu/Debian genutzt, habe Abfragen (ware Pakete direkt aus Repositories) gemacht und ihre Abhängigkeiten rekursiv gefunden. Das Programm sollte die neueste stabile Version des Pakets automatisch herunterladen und dabei die Sicherheitsrisiken so gering wie möglich halten.

Ich nannte das Werkzeug

fetchy , weil es… findet und bringt… was benötigt wird [vom engl. „fetch“, „bringen“ — Anm. d. Ü.] Das Werkzeug funktioniert über eine Kommandozeilen-Schnittstelle, bietet jedoch gleichzeitig auch eine API.Um ein Image mit Hilfe von

(nehmen wir diesmal das Python-Image), müsst ihr nur die CLI so verwenden: , weil es… findet und bringt… was benötigt wird [ fetchy dockerize python . Möglicherweise wird nach dem Zielbetriebssystem und dem Codenamen gefragt, daderzeit nur Pakete auf Debian- und Ubuntu-Basis verwendet werden. , weil es… findet und bringt… was benötigt wird [ verwendet derzeit nur Pakete, die auf Debian und Ubuntu basieren.

Jetzt kann man wählen, welche Abhängigkeiten im unserem Kontext völlig unnötig sind und sie ausschließen. Zum Beispiel hängt Python von Perl ab, funktioniert aber auch ohne installierten Perl problemlos.

Ergebnisse

Das Python-Image, erstellt mit dem Befehl fetchy dockerize python3.5 wiegt nur 35 MB (ich bin mir sicher, dass es in Zukunft noch weiter erleichtert werden kann). Somit konnte mit dem distroless-Image noch einmal 15 MB eingespart werden.

Alle bisher gesammelten Images können angesehen werden hier.

Projekt — hier.

Wenn Ihnen Funktionen fehlen, erstellen Sie einfach eine Anfrage — ich helfe gerne 🙂 Darüber hinaus arbeite ich derzeit an der Integration anderer Paketmanager in fetchy, sodass die Notwendigkeit mehrstufiger Builds entfällt.

Quelle: habr.com

60GB SSD 8Gb DDR4