Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 5 di 9
  • livello intermedio
Indice lezioni

Docker e le immagini

Breve panoramica su come ottenere e gestire le immagini su Docker: ecco come utilizzare i tag, i digest ed i comandi pull e run.
Breve panoramica su come ottenere e gestire le immagini su Docker: ecco come utilizzare i tag, i digest ed i comandi pull e run.
Link copiato negli appunti

La lezione precedente si concludeva con l’esecuzione di un comando: docker run hello-world. Il comando, apparentemente intuitivo, chiedeva all’engine Docker di eseguire il container hello-world, con l’unico scopo di stampare a video un messaggio, per poi ritornare il prompt all’utente. Ma proviamo a capire meglio cosa è successo.

Tutte le istruzioni che servono per il funzionamento di un container sono definite nella sua immagine. Per capire la correlazione tra container e immagini si può pensare all’immagine come ad un negativo fotografico che una volta sviluppato dà vita alla foto così come la conosciamo. O ancora, si può pensare all’immagine come ad una classe di un qualunque linguaggio OOP e al container come all’oggetto da essa istanziato.

Quando chiediamo a Docker di eseguire un container a partire dalla sua immagine, quest’ultima deve essere presente sul disco locale. In caso contrario, Docker ci avvertirà del problema (Unable to find image 'hello-world:latest' locally) e provvederà a scaricarla in maniera autonoma (latest: Pulling from library/hello-world).

Per sapere quali immagini sono state scaricate da Docker sul nostro computer, utilizziamo il comando docker images:

$ docker images
REPOSITORY      TAG      IMAGE ID            CREATED          SIZE
hello-world     latest   c54a2cc56cbb        3 months ago     1.848 kB

Immagini, repository e tag

Con il termine repository intendiamo un contenitore di immagini correlate. Ad esempio, il repository hello-world conterrà varie versioni dell’immagine hello-world. Nel mondo Docker, si utilizza più correttamente il termine tag per esprimere il concetto di versionamento delle immagini. Nell’esempio precedente, l’immagine è stata taggata come latest ed è l’unico tag disponibile per il repository hello-world come facilmente verificabile qui. La cosa non lascia sorpresi, vista la semplicità intrinseca dell’immagine, ma basta vedere la taglist di un repository a caso per capire l’importanza dei tag (ad esempio la taglist del repository Redis). Se un repository contiene più di un tag, è possibile riferirsi ad una data immagine con la coppia repository:tag (es: redis:3.0.0).

Il tag latest è il tag di default: ogni qualvolta ci riferiamo ad un repository senza specificare il nome del tag, Docker farà implicitamente riferimento al tag latest, e se questo non esiste verrà mostrato un errore. Come best practice, quindi, la forma repository:tag sarebbe preferibile in quanto permette una maggiore prevedibilità riguardo il contenuto dell’immagine, evitando possibili conflitti tra container ed eventuali errori dovuti alla mancanza del tag latest.

Union filesystem

Una peculiarità delle immagini Docker è la loro stratificazione in layer, ognuno dei quali contribuisce alla definizione di quello che sarà poi il file system del container. Particolare di questi layer è la loro immutabilità: i layer sono infatti accessibili in sola lettura e non sono modificabili direttamente. Questa, che potrebbe sembrare una limitazione, è invece un grande punto di forza di Docker, che in questo modo offre la possibilità a più immagini di condividere un layer comune. Ad esempio, le immagini redis:3.0.0 e nginx:1.7 si basano entrambe su un layer comune (debian:jessie), sebbene la prima immagine appartenga ad un key/value store e la seconda ad un webserver.

Figura 1. La struttura a strati di due immagini Docker (click per ingrandire)

La struttura a strati di due immagini Docker

L’immagine spiega abbastanza chiaramente la situazione, ma per dimostrarlo faremo una prova scaricando le immagini di cui sopra. Per iniziare, ci procureremo l’immagine di redis, e siccome non vogliamo eseguire il container utilizziamo il comando pull al posto del precedente run:

$ docker pull redis:3.0.0
3.0.0: Pulling from library/redis
193224d99eda: Pull complete
a3ed95caeb02: Pull complete
5d614b26c26f: Pull complete
8274a6625da0: Pull complete
86d9ae0920b7: Pull complete
f4f11f46a20e: Pull complete
c3192ae156a0: Pull complete
317cb6aa0b20: Pull complete
a1a961e320bc: Pull complete
Digest: sha256:06ce8790b8f63ad1ee9eec1aec5513c34331a350f66a370572405cb15508ecdc
Status: Downloaded newer image for redis:3.0.0

Completato questo comando, abbiamo disponibile in locale la nostra immagine. Si faccia attenzione al fatto che, in realtà, non abbiamo scaricato l’immagine redis:3.0.0 ma nove diversi layer (uno per ogni riga Pull complete) che sovrapposti daranno luogo all’immagine redis:3.0.0.

L’ultima informazione che il comando ci fornisce è un hash che rappresenta il contenuto crittografico dell’immagine scaricata. Questa funzionalità è stata introdotta nella versione 1.10 di Docker col nome di content addressable storage, ed ha sostituito l’algoritmo precedente che generava tale hash in maniera casuale. L’utilizzo di un hash crittografico basato sul contenuto dell’immagine è utile in quanto è un riferiemento assolutamente univoco, laddove la sola coppia repository:tag non basterebbe come garanzia. Conoscendo l'hash dell’immagine, infatti, possiamo utilizzare il comando pull con una sintassi leggermente differente:

$ docker pull redis@sha256:06ce8790b8f63ad1ee...370572405cb15508ecdc

Così facendo siamo sicuri di avere in locale esattamente sempre e soltanto una data immagine di redis, qualunque sia l’immagine attualmente associata al tag 3.0.0. Per tale motivo, in scenari di produzione è sempre meglio affidarsi all'hash (detto, più propriamente, digest) per identificare le immagini.

Chiudiamo questa breve parentesi sugli identificativi delle immagini e procediamo a scaricare la seconda immagine dell’esempio:

$ docker pull nginx:1.7
1.7: Pulling from library/nginx
193224d99eda: Already exists
a3ed95caeb02: Pull complete
eb250aa1fe8b: Pull complete
26547bfb8cca: Pull complete
9118cfaa8eaa: Pull complete
a6efe51e1a3b: Pull complete
a2318bfd27ef: Pull complete
Digest: sha256:02537b932a849103ab21c75fac25c0de622ca12fe2c5ba8af2c7cb23339ee6d4
Status: Downloaded newer image for nginx:1.7

Come si vede, il layer 193224d99eda esiste già in locale (Already exists), essendo stato scaricato precedentemente durante il pull dell’immagine redis:3.0.0. Non sarà quindi necessario un nuovo download.

$ docker images
REPOSITORY      TAG            IMAGE ID       CREATED         SIZE
hello-world     latest         c54a2cc56cbb   3 months ago    1.848 kB
redis           3.0.0          6b81c9436dd1   17 months ago   111.1 MB
nginx           1.7            d5acedd7e96a   17 months ago   93.45 MB

Secondo l’output precedente la somma delle due immagini appena scaricate è di poco superiore ai 204MB, ragion per cui ci aspetteremmo di avere sul disco 204MB di spazio disponibile in meno. In realtà, non è esattamente così che funziona: tale dimensione, infatti, è solo virtuale e non tiene conto del fatto che il layer 193224d99eda sia in realtà condiviso. Ragion per cui la dimensione effettiva delle due immagini è circa 119MB (ovvero 204MB-85MB).

Ti consigliamo anche