Recuperare un'immagine Docker esistente e distribuirla in locale

Completato

Docker è una tecnologia che consente di distribuire applicazioni e servizi in modo semplice e rapido. Un'applicazione Docker viene eseguita usando un'immagine Docker. Un'immagine Docker è un ambiente preassemblato che contiene il codice dell'applicazione e l'ambiente in cui viene eseguito il codice.

Nello scenario aziendale descritto in precedenza si vuole analizzare la fattibilità della creazione di un pacchetto dell'app e della relativa esecuzione con Docker. Si decide di compilare e distribuire un'immagine Docker che esegue un'app Web di prova.

In questa unità: concetti chiave e processi coinvolti nell'esecuzione di un'app in contenitori archiviata in un'immagine Docker.

Panoramica di Docker

Docker è uno strumento per l'esecuzione di app in contenitori. Un'app in contenitori include l'app e il file system che costituisce l'ambiente in cui viene eseguita. Ad esempio, un'app in contenitori può essere costituita da un database e da altre informazioni di configurazione e software associato necessari per eseguire l'app.

Un'app in contenitori in genere ha un impatto molto ridotto rispetto a una macchina virtuale configurata per eseguire la stessa app. perché una macchina virtuale deve gestire l'intero sistema operativo e l'ambiente di supporto associato. Un contenitore Docker non ha questo sovraccarico perché Docker usa il kernel del sistema operativo del computer host per supportare il contenitore. Il download e l'avvio di un'immagine Docker sono più veloci ed efficienti in termini di spazio rispetto al download e all'esecuzione di una macchina virtuale che offre funzionalità simili.

Per creare un'app in contenitori si crea un'immagine che contiene un set di file e una sezione di informazioni di configurazione usate da Docker. Per eseguire l'app, si chiede a Docker di avviare un contenitore basato sull'immagine. All'avvio del contenitore, Docker usa la configurazione dell'immagine per determinare quale applicazione eseguire all'interno del contenitore. Docker fornisce le risorse del sistema operativo e la sicurezza necessaria. Garantisce che i contenitori siano in esecuzione simultaneamente e rimangano relativamente isolati.

Importante

Docker non offre il livello di isolamento disponibile con le macchine virtuali. Una macchina virtuale implementa l'isolamento a livello hardware. I contenitori Docker condividono le risorse e le librerie del sistema operativo sottostanti. Tuttavia, Docker garantisce che un contenitore non possa accedere alle risorse di un altro, a meno che i contenitori non siano configurati per farlo.

Se si eseguono attività di sviluppo e test in locale, è possibile eseguire Docker sul computer desktop o portatile. Per i sistemi di produzione, Docker è disponibile per gli ambienti server, tra cui molte varianti di Linux e Microsoft Windows Server 2016. Molti fornitori supportano Docker anche nel cloud. Ad esempio, è possibile archiviare le immagini Docker in Registro Azure Container ed eseguire i contenitori con le istanze di Azure Container.

In questo modulo si userà Docker in locale per creare ed eseguire un'immagine. L'immagine verrà quindi caricata in Registro Azure Container ed eseguita in un'istanza di Azure Container. Questa versione di Docker è adatta per le operazioni di sviluppo e test locali delle immagini Docker.

Immagini Docker per Windows e Linux

Docker è stato inizialmente sviluppato per Linux e successivamente esteso per supportare Windows. Le singole immagini Docker sono basate su Windows o su Linux, ma non possono essere basate contemporaneamente su entrambi. Il sistema operativo dell'immagine determina il tipo di ambiente del sistema operativo usato all'interno del contenitore.

Gli autori delle immagini Docker che vogliono offrire funzionalità simili nelle immagini basate su Linux e in quelle basate su Windows possono compilare le immagini separatamente. Ad esempio, Microsoft offre immagini Docker per Windows e Linux contenenti un ambiente ASP.NET Core che è possibile usare come base per le applicazioni ASP.NET Core in contenitori.

I computer Linux con Docker installato possono eseguire solo contenitori Linux. I computer Windows con Docker installato possono eseguire entrambi i tipi di contenitori. Windows esegue entrambi usando una macchina virtuale per eseguire un sistema Linux e quindi usa il sistema Linux virtuale per eseguire i contenitori Linux.

In questo modulo si potrà compilare ed eseguire un'immagine basata su Linux.

Registri Docker e hub Docker

Le immagini Docker vengono archiviate e sono disponibili nei registri. Un registro è un servizio Web a cui Docker può connettersi per caricare e scaricare le immagini dei contenitori. Il registro più noto è l'hub Docker, che è un registro pubblico. Molte persone e organizzazioni pubblicano le immagini nell'hub Docker ed è possibile scaricare ed eseguire queste immagini usando Docker sul desktop, in un server o nel cloud. È possibile creare un account di Docker Hub e caricare le immagini gratuitamente.

Un registro è organizzato come una serie di repository. Ogni repository contiene più immagini Docker che condividono un nome comune, e in genere lo stesso scopo e le stesse funzionalità. Queste immagini normalmente hanno versioni diverse, identificate con un tag. Questo meccanismo consente di pubblicare e conservare più versioni delle immagini per motivi di compatibilità. Quando si scarica e si esegue un'immagine, è necessario specificare il registro, il repository e il tag di versione dell'immagine. I tag sono etichette di testo ed è possibile usare il proprio sistema di numerazione delle versioni (1.0, 1.1, 1.2, 2.0 e così via).

Si supponga di voler usare l'immagine Docker di ASP.NET Core Runtime. Questa immagine è disponibile in due versioni:

  • 8.0 (LTS): mcr.microsoft.com/dotnet/aspnet:8.0
  • 6.0 (LTS): mcr.microsoft.com/dotnet/aspnet:6.0

Si supponga ora di voler usare le immagini Docker per gli esempi di .NET Core. In questo caso sono disponibili quattro versioni tra cui scegliere:

  • mcr.microsoft.com/dotnet/samples:dotnetapp
  • mcr.microsoft.com/dotnet/samples:dotnetapp-chiseled
  • mcr.microsoft.com/dotnet/samples:aspnetapp
  • mcr.microsoft.com/dotnet/samples:aspnetapp-chiseled

Nota

A una singola immagine possono essere assegnati più tag. Per convenzione, alla versione più recente di un'immagine viene assegnato il tag latest, oltre a un tag che descrive il numero di versione. Quando si rilascia una nuova versione di un'immagine, è possibile riassegnare il tag latest per fare riferimento alla nuova immagine.

Un repository è anche l'unità di privacy per un'immagine. Se non si vuole condividere un'immagine, è possibile rendere privato il repository. È possibile concedere l'accesso ad altri utenti con cui si vuole condividere l'immagine.

Sfogliare l'hub Docker ed eseguire il pull di un'immagine

Nota

Non è necessario completare nessuno degli esempi o eseguire alcun codice nelle sezioni seguenti. Si eseguirà questa operazione nella prossima unità.

Spesso accade che in Docker Hub sia disponibile un'immagine che corrisponde maggiormente al tipo di app che si vuole aggiungere a un contenitore. È possibile scaricare questa immagine ed estenderla con il codice dell'applicazione personalizzato.

L'hub Docker contiene molte migliaia di immagini. È possibile eseguire ricerche in un registro ed esplorarlo usando Docker dalla riga di comando o dal sito Web di Docker Hub. Il sito Web consente di cercare, filtrare e selezionare le immagini in base al tipo e all'editore. La figura seguente illustra un esempio di pagina di ricerca.

Screenshot della pagina di ricerca di Docker Hub in cui sono elencate varie immagini di contenitore.

Per recuperare un'immagine, usare il comando docker pull con il nome dell'immagine. Per impostazione predefinita, Docker scarica l'immagine con il tag latest da tale repository in Docker Hub se si specifica solo il nome del repository. Tenere presente che è possibile modificare il comando per effettuare il pull di tag diversi e da repository diversi. Questo esempio recupera l'immagine con il tag aspnetapp dal repository mcr.microsoft.com/dotnet/core/samples:aspnetapp. Questa immagine contiene una semplice app Web ASP.NET Core.

Nota

Gli esempi in questa unità hanno lo scopo di illustrare la sintassi dei vari comandi di Docker. Non è necessario eseguire questi comandi durante la lettura di questa unità. Gli esercizi che seguono consentono di lavorare direttamente con Docker.

docker pull mcr.microsoft.com/dotnet/samples:aspnetapp

Quando si recupera un'immagine, Docker la archivia in locale e la rende disponibile per i contenitori in esecuzione. È possibile visualizzare le immagini nel registro locale con il comando docker image list.

docker image list

L'output ha un aspetto simile all'esempio seguente:

REPOSITORY TAG IMAGE ID CREATED SIZE
mcr.microsoft.com/dotnet/samples   aspnetapp           6e2737d83726        6 days ago          263MB

Si usa l'ID nome immagine per fare riferimento all'immagine in molti altri comandi di Docker.

Eseguire un contenitore Docker

Per avviare un contenitore, usare il comando docker run. Specificare l'immagine da eseguire con il relativo nome o ID. Se non è ancora stato eseguito il comando docker pull per l'immagine già, Docker esegue questa operazione.

docker run mcr.microsoft.com/dotnet/samples:aspnetapp

In questo esempio, il comando risponde con il messaggio seguente:

warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
 No XML encryptor configured. Key {d8e1e1ea-126a-4383-add9-d9ab0b56520d} may be persisted to storage in unencrypted form.
Hosting environment: Production
Content root path: /app
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.

Questa immagine contiene un'app Web, quindi è ora in ascolto delle richieste in arrivo sulla porta HTTP 80. Tuttavia, se si apre un Web browser e si passa a http://localhost:80, l'app non verrà visualizzata.

Per impostazione predefinita, Docker non consente alle richieste di rete in ingresso di raggiungere il contenitore. È necessario indicare a Docker di assegnare un numero di porta specifico dal computer a un numero di porta specifico nel contenitore aggiungendo l'opzione -p a docker run. Questa istruzione abilita le richieste di rete per il contenitore sulla porta specificata.

Inoltre, l'app Web in questa immagine non è concepita per essere usata in modo interattivo dalla riga di comando. Quando si avvia l'app, si vuole che Docker la avvii in background e la lasci in esecuzione. Usare il flag -d per indicare a Docker di avviare l'app Web in background.

Premere CTRL+C per arrestare l'immagine e riavviarla come illustrato nell'esempio seguente:

docker run -p 8080:80 -d mcr.microsoft.com/dotnet/samples:aspnetapp

Il comando esegue il mapping della porta 80 del contenitore alla porta 8080 del computer. Se si visita la pagina http://localhost:8080 in un browser, si noterà l'app Web di esempio.

Screenshot dell'app Web di esempio in esecuzione in un browser.

Contenitori e file

Se un contenitore in esecuzione apporta modifiche ai file nella propria immagine, tali modifiche esistono solo nel contenitore in cui vengono apportate le modifiche. A meno che non si eseguano passaggi specifici per mantenere lo stato di un contenitore, le modifiche andranno perse quando il contenitore viene rimosso. Analogamente, più contenitori basati sulla stessa immagine che vengono eseguiti simultaneamente non condividono i file nell'immagine. Ogni contenitore ha una propria copia indipendente. I dati scritti da un contenitore nel relativo file system non sono visibili agli altri contenitori.

È possibile aggiungere a un contenitore volumi con accesso in scrittura. Un volume rappresenta un file system che può essere montato dal contenitore e reso disponibile all'applicazione in esecuzione nel contenitore. I dati presenti in un volume vengono mantenuti quando si arresta il contenitore e più contenitori possono condividere lo stesso volume. I dettagli relativi alla creazione e all'uso dei volumi non rientrano nell'ambito di questo modulo.

È buona norma evitare di dover apportare modifiche al file system dell'immagine per le applicazioni distribuite con Docker. Usarlo solo per i file temporanei che si può rischiare di perdere.

Gestire i contenitori Docker

È possibile visualizzare i contenitori attivi con il comando docker ps.

docker ps

L'output include lo stato del contenitore, Up se in esecuzione o Exited se terminato, oltre ad altri valori come i flag della riga di comando specificati all'avvio dell'immagine e altre informazioni. Docker consente di eseguire più contenitori dalla stessa immagine contemporaneamente, quindi a ogni contenitore viene assegnato un ID univoco, nonché un nome univoco leggibile dall'utente. La maggior parte dei comandi di Docker usati per gestire singoli contenitori possono usare l'ID o il nome per fare riferimento a un contenitore specifico.

Nell'output seguente è possibile visualizzare due contenitori. Il campo PORTE indica che il contenitore con ID elegant_ramanujan è l'immagine in esecuzione con la porta 80 dell'host Docker mappata alla porta 8080 del computer. L'istanza youthful_heisenberg rappresenta è il contenitore per l'esecuzione precedente dell'immagine. Il campo COMANDO indica il comando eseguito dal contenitore per avviare l'applicazione nell'immagine. In questo caso è dotnet aspnetapp.dll per entrambi i contenitori. Anche l'ID immagine per i contenitori è lo stesso, perché entrambi i contenitori eseguono la stessa immagine.

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
57b9587583e3        mcr.microsoft.com/dotnet/core/samples:aspnetapp   "dotnet aspnetapp.dll"   42 seconds ago      Up 41 seconds       0.0.0.0:8080->80/tcp   elegant_ramanujan
d27071f3ca27        mcr.microsoft.com/dotnet/core/samples:aspnetapp   "dotnet aspnetapp.dll"   5 minutes ago      Up 5 minutes       0.0.0.0:8081->80/tcp   youthful_heisenberg

Nota

docker ps è un collegamento per docker container ls. I nomi di questi comandi si basano sulle utilità di Linux ps e ls, in cui sono elencati rispettivamente i processi in esecuzione e i file.

È possibile arrestare un contenitore attivo con il comando docker stop, specificando l'ID del contenitore.

docker stop elegant_ramanujan

Se si esegue di nuovo docker ps, si noterà che il contenitore elegant_ramanujan non è più presente nell'output. Il contenitore esiste ancora, ma non ospita più un processo in esecuzione. È possibile includere i contenitori arrestati nell'output di docker ps includendo il flag -a:

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
57b9587583e3        mcr.microsoft.com/dotnet/core/samples:aspnetapp   "dotnet aspnetapp.dll"   2 minutes ago       Exited (0) 21 seconds ago                       elegant_ramanujan
d27071f3ca27        mcr.microsoft.com/dotnet/core/samples:aspnetapp   "dotnet aspnetapp.dll"   7 minutes ago      Up 7 minutes       0.0.0.0:8081->80/tcp   youthful_heisenberg

È possibile riavviare un contenitore arrestato con il comando docker start. Il processo principale del contenitore viene di nuovo avviato.

docker start elegant_ramanujan

In genere, dopo aver arrestato un contenitore, è necessario rimuoverlo. La rimozione di un contenitore elimina tutte le risorse rimaste. Dopo la rimozione di un contenitore, tutte le modifiche apportate all'interno del relativo file system vanno perse definitivamente.

docker rm elegant_ramanujan

Non è possibile rimuovere un contenitore in esecuzione, ma è possibile forzare l'arresto e la rimozione di un contenitore con il flag -f al comando docker rm. Questo è un modo rapido per arrestare e rimuovere un contenitore, ma deve essere usato solo se l'app all'interno del contenitore non deve eseguire un arresto normale.

docker container rm -f elegant_ramanujan

Rimuovere le immagini Docker

È possibile rimuovere un'immagine dal computer locale con il comando docker image rm. Specificare l'ID immagine dell'immagine da rimuovere. Nell’esempio seguente viene rimossa l'immagine per l'app Web di esempio.

docker image rm mcr.microsoft.com/dotnet/core/samples:aspnetapp

I contenitori che eseguono l'immagine devono essere terminati per poter rimuovere l'immagine. Se l'immagine è ancora in uso da un contenitore, verrà visualizzato un messaggio di errore simile al seguente. In questo esempio l'errore si verifica perché il contenitore youthful_heisenberg continua a usare l'immagine.

Error response from daemon: conflict: unable to delete 575d85b4a69b (cannot be forced) - image is being used by running container c13165988cfe