Salta el contingut

Pas 2 - Imatges: noms, capes i format

Al pas anterior vam descarregar hello-world, ubuntu:24.04 i alpine. Abans d'executar contenidors més seriosos, val la pena entendre què és exactament una imatge: com s'anomena, d'on ve, de què està feta i per què algunes descàrregues diuen Already exists.

Objectius del pas

  • Descompondre el nom complet d'una imatge: registre, espai de noms, repositori, etiqueta i digest.
  • Entendre que una etiqueta (tag) és mòbil i un digest és immutable.
  • Veure que una imatge està formada per capes compartides entre imatges.
  • Obrir una imatge i reconèixer el format estàndard OCI.

2.1 El nom complet d'una imatge

Quan escrivim nginx, Docker completa el nom amb valors per defecte. El nom complet té aquesta forma:

[registre/][espai_de_noms/]repositori[:etiqueta][@digest]
Part Exemple Valor per defecte
Registre docker.io, ghcr.io, quay.io, mcr.microsoft.com docker.io (Docker Hub)
Espai de noms library, bitnami, el vostre usuari library (imatges oficials)
Repositori nginx, mysql, hello-world obligatori
Etiqueta 1.27-alpine, 8.4, latest latest
Digest sha256:d715f14f... cap

Per tant, aquestes comandes descarreguen exactament la mateixa imatge:

docker pull nginx
docker pull nginx:latest
docker pull docker.io/library/nginx:latest

La primera la descarrega; les altres dues responen Image is up to date, perquè ja és local.

Alguns exemples reals per reconèixer cada part:

Nom Registre Espai de noms Repositori Etiqueta
mysql:8.4 docker.io library mysql 8.4
bitnami/redis:7.4 docker.io bitnami redis 7.4
ghcr.io/home-assistant/home-assistant:stable ghcr.io home-assistant home-assistant stable
mcr.microsoft.com/dotnet/aspnet:8.0 mcr.microsoft.com dotnet aspnet 8.0

Quines imatges de Docker Hub són fiables?

A Docker Hub hi ha tres tipus d'imatges: Docker Official Images (espai library, mantingudes per Docker i els projectes originals), Verified Publisher (empreses verificades) i imatges de la comunitat (qualsevol usuari). Per defecte, feu servir imatges oficials o verificades. Podeu cercar-ne des del terminal amb docker search nginx, però la pàgina web mostra molta més informació: etiquetes disponibles, variables d'entorn i exemples d'ús.

2.2 Etiquetes: latest no vol dir "la més nova"

Una etiqueta és només una etiqueta de text que apunta a una imatge. Una mateixa imatge pot tenir diverses etiquetes alhora. Per exemple, en un moment donat, nginx:1.27, nginx:1.27.3, nginx:mainline i nginx:latest poden apuntar a la mateixa imatge.

Les etiquetes són mòbils: quan surt una versió nova, el mantenidor mou latest (i 1.27, mainline...) cap a la imatge nova. Per això:

  • latest és simplement l'etiqueta que es fa servir si no n'especifiqueu cap. No garanteix res.
  • Si dues persones fan docker pull nginx amb un mes de diferència, poden obtenir imatges diferents.
  • En entorns reals, especifiqueu sempre una versió: nginx:1.27-alpine en lloc de nginx.

Moltes imatges ofereixen variants a l'etiqueta:

Variant Significat Mida aproximada
nginx:1.27 Basada en Debian ~190 MB
nginx:1.27-alpine Basada en Alpine Linux, molt lleugera ~50 MB
python:3.12 Debian completa amb eines de compilació ~1 GB
python:3.12-slim Debian mínima ~130 MB

Comproveu-ho vosaltres mateixos:

docker pull nginx:1.27
docker pull nginx:1.27-alpine
docker images nginx

2.3 El digest: la identitat real de la imatge

Una etiqueta pot canviar, però el digest no. És un hash SHA-256 calculat a partir del contingut de la imatge: si canvia un sol byte, canvia el digest.

docker images --digests nginx

Podeu descarregar o executar una imatge pel seu digest, i tindreu la garantia que sempre serà exactament la mateixa:

docker pull nginx@sha256:<digest-copiat-de-la-sortida-anterior>

IMAGE ID i digest no són el mateix

IMAGE ID és un identificador local (el hash de la configuració de la imatge). El digest (RepoDigests) identifica la imatge al registre. Tots dos són hashes SHA-256, però serveixen per a coses diferents.

2.4 Les capes

Recordeu la sortida d'un docker pull d'una imatge gran:

1.27: Pulling from library/nginx
a2318d6c47ec: Pull complete
095d327c79ae: Pull complete
bbfaa25db775: Pull complete
7bb6fb0cfb2b: Pull complete
0723edc10c17: Pull complete
24b3fdc4d1e3: Pull complete
3122471704d5: Pull complete
Digest: sha256:...

Cada línia és una capa. Una imatge no és un únic fitxer gegant, sinó una pila de capes de només lectura. Cada capa conté els fitxers que s'han afegit, modificat o eliminat respecte de la capa anterior:

flowchart TB
    W["Capa d escriptura del contenidor (lectura i escriptura)"]
    L3["Capa 3 - configuracio de nginx"]
    L2["Capa 2 - paquets de nginx"]
    L1["Capa 1 - sistema base Debian"]
    W --- L3 --- L2 --- L1
    classDef rw fill:#16A34A,stroke:#166534,color:#FFFFFF
    classDef ro fill:#2563EB,stroke:#1E40AF,color:#FFFFFF
    class W rw
    class L1,L2,L3 ro

Quan arrenqueu un contenidor, Docker hi afegeix una capa d'escriptura a sobre. Tot el que el contenidor modifica va a parar a aquesta capa; la imatge de sota no canvia mai. Per això de la mateixa imatge en podeu arrencar deu contenidors: comparteixen les capes de lectura i cadascun té la seva capa d'escriptura.

Les capes es comparteixen

Proveu això:

docker pull python:3.12-slim
docker pull python:3.13-slim

En la segona descàrrega veureu línies com aquestes:

3.13-slim: Pulling from library/python
7cf63256a31a: Already exists
b8bd1e1d5e5d: Pull complete
...

Already exists vol dir que aquella capa (el sistema base Debian) ja era al disc perquè l'havia portat la primera imatge. Docker no la torna a descarregar ni la desa dues vegades. Aquest mecanisme estalvia molt d'espai i ample de banda.

Inspeccionar les capes

docker image history nginx:1.27-alpine

Mostra cada capa, la instrucció que la va crear i la seva mida. És el primer contacte amb les instruccions d'un Dockerfile (RUN, COPY, CMD...), que escriurem nosaltres al Pas 8.

Per veure totes les metadades de la imatge (capes, variables d'entorn, ordre per defecte, ports declarats...):

docker image inspect nginx:1.27-alpine
docker image inspect --format '{{.Config.Cmd}}' nginx:1.27-alpine
docker image inspect --format '{{.Os}}/{{.Architecture}}' nginx:1.27-alpine

2.5 El format d'una imatge per dins: OCI

Les imatges segueixen un estàndard obert, l'OCI Image Format Specification de l'Open Container Initiative. Per això una imatge construïda amb Docker es pot executar amb Podman, containerd o Kubernetes.

Podem exportar una imatge a un fitxer .tar i mirar-ne el contingut:

mkdir /tmp/imatge && cd /tmp/imatge
docker save hello-world:latest -o hello.tar
tar -xf hello.tar
ls -R
.:
blobs  hello.tar  index.json  manifest.json  oci-layout  repositories

./blobs/sha256:
03b62250a3cb...  74cc54e27dc4...  e6590344b1a5...  ...
Element Contingut
oci-layout Declara que el directori segueix el format OCI
index.json Punt d'entrada: apunta al manifest de la imatge
blobs/sha256/ Tots els objectes, cadascun anomenat pel seu hash
Manifest (un blob JSON) Llista la configuració i les capes, amb els seus digests
Configuració (un blob JSON) Arquitectura, variables d'entorn, Cmd, Entrypoint, historial...
Capes (blobs tar o tar.gz) Els fitxers de cada capa

Podeu llegir els JSON amb cat (o millor, amb jq si el teniu instal·lat) i descomprimir una capa amb tar -tf blobs/sha256/<hash> per veure'n els fitxers. Al cas de hello-world hi trobareu un únic fitxer: el binari /hello.

flowchart LR
    IDX[index.json] --> M[Manifest]
    M --> CFG[Configuracio JSON]
    M --> C1[Capa 1 tar]
    M --> C2[Capa 2 tar]
    M --> C3[Capa N tar]
    classDef a fill:#7C3AED,stroke:#5B21B6,color:#FFFFFF
    classDef b fill:#2563EB,stroke:#1E40AF,color:#FFFFFF
    classDef c fill:#16A34A,stroke:#166534,color:#FFFFFF
    class IDX,M a
    class CFG b
    class C1,C2,C3 c

Imatges multiarquitectura

Moltes imatges oficials existeixen per a diverses arquitectures (amd64, arm64...). Al registre hi ha un índex que apunta a un manifest per a cada arquitectura, i Docker descarrega automàticament el que correspon a la vostra màquina. Per això docker pull nginx funciona igual en un PC i en un Mac amb processador Apple Silicon o en una Raspberry Pi.

Miniactivitat - Anatomia d'una imatge

  1. Escriviu el nom complet (registre, espai de noms, repositori i etiqueta) de mysql, bitnami/postgresql:16 i ghcr.io/linuxserver/nginx.
  2. Descarregueu nginx:1.27 i nginx:1.27-alpine. Quina diferència de mida hi ha? Quantes capes té cadascuna (docker image history)?
  3. Descarregueu python:3.12-slim i després python:3.13-slim. Quantes capes surten com a Already exists?
  4. Exporteu alpine:3.20 amb docker save, obriu el manifest i indiqueu quantes capes té i quin és el Cmd per defecte que trobeu a la configuració.

2.6 Neteja d'imatges

docker rmi nginx:1.27            # elimina una imatge (o una etiqueta)
docker image prune               # elimina les imatges "penjades" (sense etiqueta)
docker image prune -a            # elimina totes les imatges que no fa servir cap contenidor
docker system df                 # espai ocupat per imatges, contenidors i volums

No es pot eliminar una imatge en ús

Si algun contenidor (fins i tot aturat) s'ha creat a partir d'una imatge, docker rmi fallarà. Primer cal eliminar el contenidor. Si una imatge té diverses etiquetes, docker rmi només treu l'etiqueta indicada fins que no en queda cap.

Resum del pas

Concepte Idea clau
Nom complet registre/espai/repositori:etiqueta@digest; per defecte docker.io/library/...:latest
Etiqueta Nom mòbil; especifiqueu sempre una versió concreta
Digest Hash immutable del contingut
Capes Pila de capes de només lectura, compartides entre imatges
Capa d'escriptura La que afegeix cada contenidor; desapareix amb el contenidor
OCI Format estàndard: índex, manifest, configuració i capes

Següent pas: fins ara els contenidors s'aturaven de seguida. Al Pas 3 arrencarem un servidor que es queda funcionant en segon pla.