Blog

Wie man den kleinstmöglichen Docker-Container eines beliebigen Images erstellt

Mark van Holsteijn

Aktualisiert Oktober 22, 2025
5 Minuten

Sobald Sie anfangen, ernsthaft mit Docker zu arbeiten, werden Sie bald feststellen, dass das Herunterladen von Images aus der Registry ein echter Engpass beim Starten von Anwendungen ist. In diesem Blog-Beitrag zeigen wir Ihnen, wie Sie die Größe jedes Docker-Images auf nur wenige Prozent des Originals reduzieren können. Ist Ihr Image also zu dick, versuchen Sie, Ihr Docker-Image zu strippen! Das in diesem Blog vorgestellte Dienstprogramm strip-docker-image macht Ihre Container schneller und gleichzeitig sicherer!

Wir arbeiten recht intensiv an unserer hochverfügbaren Docker-Container-Plattform mit CoreOS und Consul, die aus einer Reihe von Containern besteht (NGiNX, HAProxy, der Registrator und Consul). Diese Container laufen auf jedem der Knoten in unserem CoreOS-Cluster und beim Booten des Clusters werden mehr als 600 MB von den 3 Knoten im Cluster heruntergeladen. Das ist ziemlich zeitaufwändig. [bash] cargonauts/consul-http-router latest 7b9a6e858751 7 days ago 153 MB cargonauts/progrium-consul latest 32253bc8752d 7 weeks ago 60.75 MB progrium/registrator latest 6084f839101b 4 months ago 13.75 MB [/bash] Die Größe der Images wirkt sich nicht nur nachteilig auf die Boot-Zeit unserer Plattform aus, sondern erhöht auch die Angriffsfläche des Containers. Mit 153Mb an Dienstprogrammen im NGiNX-basierten consul-http-router gibt es eine Menge Dinge im Container, die Sie nutzen können, sobald Sie sich darin befinden. Da wir daran dachten, diesen Router in einer DMZ zu betreiben, wollten wir die Menge der Tools, die für einen potenziellen Hacker herumliegen, minimieren. Von unserem Kollegen Adriaan de Jonge haben wir bereits gelernt, wie man den kleinstmöglichen Docker-Container für ein Go-Programm erstellt. Können wir dies wiederholen, indem wir einfach die ausführbare Datei von NGiNX aus der offiziellen Distribution extrahieren und auf ein Scratch-Image kopieren? Und es stellt sich heraus, dass wir das können!

Finden der benötigten Dateien

Mit dem Dienstprogramm dpkg können wir alle Dateien auflisten, die von NGiNX installiert werden [bash] docker run nginx dpkg -L nginx ... /. /usr /usr/sbin /usr/sbin/nginx /usr/share /usr/share/doc /usr/share/doc/nginx ... /etc/init.d/nginx [/bash]

Auffinden abhängiger gemeinsamer Bibliotheken

Wir haben also die Liste der Dateien im Paket, aber wir haben nicht die gemeinsam genutzten Bibliotheken, auf die die ausführbare Datei verweist. Glücklicherweise können diese mit dem Dienstprogramm ldd abgerufen werden. [bash] docker run nginx ldd /usr/sbin/nginx ... linux-vdso.so.1 (0x00007fff561d6000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd8f17cf000) libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007fd8f1598000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007fd8f1329000) libssl.so.1.0.0 => /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007fd8f10c9000) libcrypto.so.1.0.0 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007fd8f0cce000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fd8f0ab2000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd8f0709000) /lib64/ld-linux-x86-64.so.2 (0x00007fd8f19f0000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd8f0505000) [/bash]

Verfolgen und Einbeziehen symbolischer Links

Jetzt haben wir die ausführbare Datei und die referenzierten gemeinsamen Bibliotheken. Es stellt sich heraus, dass ldd normalerweise den symbolischen Link benennt und nicht den tatsächlichen Dateinamen der gemeinsamen Bibliothek. [bash] docker run nginx ls -l /lib/x86_64-linux-gnu/libcrypt.so.1 ... lrwxrwxrwx1 root root 16 Apr 15 00:01 /lib/x86_64-linux-gnu/libcrypt.so.1 -> libcrypt-2.19.so [/bash] Indem wir die symbolischen Links auflösen und sowohl den Link als auch die Datei einbeziehen, sind wir bereit, das Nötigste aus dem Container zu exportieren!

getpwnam funktioniert nicht

Aber nachdem ich alle wichtigen Dateien in ein Scratch-Image kopiert hatte, startete NGiNX nicht mehr. Es schien, dass NGiNX versucht, die Benutzerkennung 'nginx' aufzulösen, was nicht gelingt. [bash] docker run -P --entrypoint /usr/sbin/nginx stripped-nginx -g "daemon off;" ... 2015/06/29 21:29:08 [emerg] 1#1: getpwnam("nginx") failed (2: No such file or directory) in /etc/nginx/nginx.conf:2 nginx: [emerg] getpwnam("nginx") ist fehlgeschlagen (2: No such file or directory) in /etc/nginx/nginx.conf:2 [/bash] Es stellte sich heraus, dass die Shared Libraries für den Namenswechsel-Dienst, der /etc/passwd und /etc/group liest, zur Laufzeit geladen und nicht in den Shared Libraries referenziert werden. Durch Hinzufügen dieser Shared Libraries ( (/lib//libnss) zum Container funktionierte NGiNX!

strip-docker-image Beispiel

Jetzt steht Ihnen das Dienstprogramm strip-docker-image zur Verfügung! [bash] strip-docker-image -i image-name -t target-image-name [-p package] [-f file] [-x expose-port] [-v] [/bash] Die Optionen werden im Folgenden erklärt: [bash] -i image-name to strip [/bash] -t target-image-name der Image-Name des gestrippten Images -p package package to include from image, multiple -p allowed. -f file file to include from image, multiple -f allowed. -x port to expose. -v verbose. Das folgende Beispiel erstellt ein neues nginx-Image mit dem Namen stripped-nginx basierend auf dem offiziellen Docker-Image: [bash] strip-docker-image -i nginx -t stripped-nginx -x 80 -p nginx -f /etc/passwd -f /etc/group -f '/lib//libnss' -.f /bin/ls -f /bin/cat -f /bin/sh -f /bin/mkdir -f /bin/ps -f /var/run -f /var/log/nginx -f /var/cache/nginx [/bash] Neben dem nginx-Paket fügen wir die Dateien /etc/passwd, /etc/group und /lib//libnss shared libraries hinzu. Die Verzeichnisse /var/run, /var/log/nginx und /var/cache/nginx sind für den Betrieb von NGiNX erforderlich. Außerdem haben wir /bin/sh und ein paar praktische Dienstprogramme hinzugefügt, um ein wenig herumschnüffeln zu können. Das gestrippte Image ist nun auf unglaubliche 5,4% der ursprünglichen 132,8 Mb auf nur 7,3Mb geschrumpft und ist immer noch voll funktionsfähig! [bash] docker images | grep nginx ... stripped-nginx latest d61912afaf16 vor 21 Sekunden 7.297 MB nginx 1.9.2 319d2015d149 vor 12 Tagen 132.8 MB [/bash] Und es funktioniert! [bash] ID=$(docker run -P -d --entrypoint /usr/sbin/nginx stripped-nginx -g "daemon off;") docker run --link $ID:stripped cargonauts/toolbox-networking curl -s -D - https:// stripped ... HTTP/1.1 200 OK [/bash] Für HAProxy checken Sie das Beispielverzeichnis.

Fazit

Es ist möglich, die offiziellen Images zu verwenden, die von Docker gewartet und verteilt werden, und sie auf das Wesentliche zu reduzieren, damit sie einsatzbereit sind! Das beschleunigt die Ladezeiten und reduziert die Angriffsfläche dieses speziellen Containers. Das Skript und die Handbuchseite finden Sie im Github-Repository. Bitte senden Sie mir Ihre Beispiele für unglaublich geschrumpfte Docker-Images!

Verfasst von

Mark van Holsteijn

Mark van Holsteijn is a senior software systems architect at Xebia Cloud-native solutions. He is passionate about removing waste in the software delivery process and keeping things clear and simple.

Contact

Let’s discuss how we can support your journey.