🐳 De start van het Docker image-dieet: de stamboom ontrafelen met docker history

Soms lanceer je een ogenschijnlijk lichte app, maar bij het controleren van de imagegrootte zie je dat deze gemakkelijk meer dan 1 GB bedraagt. "Wat heb ik er in hemelsnaam allemaal in gestopt?" vraag je je dan verbaasd af. Dit is precies het moment waarop je de 'stamboom' van je image moet uitpluizen.

Docker-laagdieet

"Wat heb je gegeten om zo groot te worden?"

Een Docker-image is als een ui met meerdere lagen. docker history is het röntgenapparaat dat deze lagen één voor één afpelt om de boosdoener te vinden.

De basisgebruik is uiterst eenvoudig:

# Basisgebruik
docker history [opties] <imagename:tag>

# Voorbeeld: de geschiedenis van mijn app controleren
docker history my-app:latest

Als je de opdracht uitvoert, zie je de geschiedenis van de meest recente laag tot de basisimage, in omgekeerde volgorde.

IMAGE          CREATED          CREATED BY                                      SIZE
a6215f271958   5 minutes ago    /bin/sh -c #(nop)  CMD ["/bin/sh"]               0B
<missing>      7 weeks ago      /bin/sh -c #(nop) ADD file:f28242cf608f6...     7.81MB

Let goed op de kolom SIZE. Als daar honderden MB's staan waar 0B zou moeten staan, dan heb je je dieetkandidaat gevonden. Met wat ervaring zul je al snel 'verdachte plekken' herkennen.

**💡 Handige tip: --no-trunc**

Standaard wordt de uitvoer afgekapt als de opdracht te lang is. Voeg de optie --no-trunc toe om de volledige opdracht te zien, wat essentieel is voor een nauwkeurige analyse.

docker history --no-trunc my-app:latest


Praktijkvoorbeeld: "De boosdoener was chown"

Ik zal je een waargebeurd verhaal vertellen. Ik bouwde een projectbestand van 150 MB, maar de image bleek meer dan 300 MB te zijn. De boosdoener waren twee ogenschijnlijk onschuldige regels in de Dockerfile.

[Inefficiënte methode: twee lagen creëren]

# 1. Bestanden kopiëren (standaard gekopieerd als root-eigenaar)
COPY . .

# 2. Eigendom wijzigen voor beveiliging (uitgevoerd als aparte opdracht)
RUN chown -R appuser:appgroup /app

Na het bouwen hiervan en controleren met docker history, kreeg ik dit resultaat:

IMAGE          CREATED BY                                        SIZE
<layer_id_2>   /bin/sh -c chown -R appuser:appgroup /app         150MB  <-- (Het probleem!)
<layer_id_1>   /bin/sh -c #(nop) COPY dir:abc in /app            150MB

Hier komt de verraderlijke aard van Docker-lagen naar voren. Wanneer je in stap 1 een bestand van 150 MB kopieert, wordt er één laag gecreëerd. Maar wanneer je in stap 2 chown uitvoert, denkt Docker: "Hé, de bestandsinformatie (eigendom) is gewijzigd? Dan moet ik een nieuwe laag maken met de gewijzigde status!" en kopieert het de bestaande 150 MB opnieuw om een nieuwe laag te stapelen.

Het resultaat is dat de inhoud identiek is, maar er een dubbele opslag is van bestanden met alleen een ander eigendom, waardoor de grootte verdubbelt.


De oplossing: een dieet van één regel!

De oplossing is simpel: specificeer de eigenaar direct bij het kopiëren om de lagen samen te voegen tot één.

[Efficiënte methode: één laag creëren]

# Kopiëren en tegelijkertijd het eigendom specificeren!
COPY --chown=appuser:appgroup . .

Als je de Dockerfile zo aanpast en docker history opnieuw uitvoert, zie je een dramatisch resultaat:

IMAGE          CREATED BY                                               SIZE
<layer_id_1>   /bin/sh -c #(nop) COPY --chown=appuser... dir:abc       150MB

Zie je het? Er is slechts één laag gecreëerd en de imagegrootte is weer slank: 150 MB. Door twee commando's samen te voegen tot één, is de grootte gehalveerd.


Conclusie: controleer altijd de 'geschiedenis' na het bouwen!

Vergeet niet dat een Docker image één laag per commando creëert.

Net zoals je code test na het schrijven, is het een goede gewoonte om na elke build docker history --no-trunc uit te voeren. Als je jezelf afvraagt "Waarom is deze apt-get zo zwaar?" of "Waarom is deze laag gesplitst?", zul je gaandeweg een zeer licht en efficiënt systeem opbouwen.

Onnodige lagen zijn immers de vijand van je systeem!


Vond je dit nuttig? Geef dan een like!

Lees ook gerelateerde artikelen.

Gerelateerde artikelen

Docker gedeeld geheugen (shm_size en ipc) volledig begrijpen

Docker: Communicatie tussen containers via hostpoorten zonder netwerkdeling

Docker Volume kopiëren, ‘waarom’ is dat nodig?