I contenitori Docker sono in aumento come best practice per l'implementazione e la gestione di sistemi distribuiti nativi del cloud. I contenitori sono istanze di immagini Docker. Si scopre che c'è molto da sapere e capire sulle immagini.
In questo tutorial in due parti, sto approfondendo le immagini di Docker. Nella prima parte ho discusso i principi di base, le considerazioni sulla progettazione e l'ispezione degli interni delle immagini. In questa parte, copro la costruzione delle tue immagini, la risoluzione dei problemi e il lavoro con i repository di immagini.
Quando esci dall'altra parte, avrai una solida comprensione di quali sono esattamente le immagini Docker e come utilizzarle efficacemente nelle tue applicazioni e nei tuoi sistemi.
Ci sono due modi per costruire immagini. È possibile modificare e il contenitore esistente e quindi eseguirne il commit come nuova immagine, oppure scrivere un Dockerfile e crearlo su un'immagine. Analizzeremo entrambi i pro e i contro.
Con le build manuali, tratti il tuo contenitore come un normale computer. Tu installi i pacchetti, scrivi i file, e quando tutto è detto, lo commetti e finisci con una nuova immagine che usi come modello per creare molti altri contenitori identici o anche basare altre immagini su.
Iniziamo con l'immagine alpina, che è un'immagine molto piccola e spartana basata su Alpine Linux. Possiamo eseguirlo in modalità interattiva per entrare in una shell. Il nostro obiettivo è aggiungere un file chiamato "yeah" che contenga il testo "funziona!" alla directory radice e quindi creare una nuova immagine da essa chiamata "yeah-alpine".
Eccoci qui. Bello, siamo già nella directory principale. Vediamo cosa c'è.
> finestra mobile run -it alpine / bin / sh / # ls bin dev ecc. home lib linuxrc media mnt proc root run sbin srv sys tmp usr var
Quale editor è disponibile? No vim, no nano?
/ # vim / bin / sh: vim: non trovato / # nano / bin / sh: nano: non trovato
Oh bene. Vogliamo solo creare un file:
/ # echo "funziona!" > yeah / # cat yeah funziona!
Sono uscito dalla shell interattiva e posso vedere il contenitore denominato "vibrant_spenc" con finestra mobile ps --all
. Il --tutti
flag è importante perché il contenitore non è più in esecuzione.
> docker ps --all CONTAINER ID IMAGE COMMAND CREATED STATUS NOMI c8faeb05de5f alpine "/ bin / sh" 6 minuti fa Exited vibrant_spence
Qui, creo una nuova immagine dal contenitore "vibrate_spence". Ho aggiunto il messaggio di commit "mio, mio, mio" per buona misura.
> docker commit -m "mio, mio, mio" vibrant_spence yeah-alpine sha256: e3c98cd21f4d85a1428 ... e220da99995fd8bf6b49aa
Controlliamolo. Sì, c'è una nuova immagine e nella sua storia puoi vedere un nuovo livello con il commento "mio, mio, mio".
> immagini docker TAG REPOSITIVO ID IMMAGINE TAGLIA yeah-alpine ultima e3c98cd21f4d 4.8 MB python latest 775dae9b960e 687 MB d4w / nsenter latest 9e4f13a0901e 83.8 kB ubuntu-with-ssh latest 87391dca396d 221 MB ubuntu latest bd3d4369aebc 127 MB ciao-mondo ultimo c54a2cc56cbb 1.85 kB alpine latest 4e38e38c8ce0 4.8 MB nsqio / nsq latest 2a82c70fe5e3 70.7 MB> cronologia docker yeah-alpine IMAGE CREATED SIZE COMMENTO e3c98cd21f4d 40 secondi fa 66 B mio, mio, mio 4e38e38c8ce0 7 mesi fa 4.8 MB
Ora per la vera prova. Eliminiamo il contenitore e creiamo un nuovo contenitore dall'immagine. Il risultato atteso è che il file "yeah" sarà presente nel nuovo contenitore.
> finestra mobile rm vibrant_spence vibrant_spence> finestra mobile run -it yeah-alpine / bin / sh / # cat sì funziona! / #
Cosa posso dire? Sì, funziona!
La creazione di immagini da contenitori modificati è interessante, ma non ci sono responsabilità. È difficile tenere traccia delle modifiche e sapere quali sono le modifiche specifiche. Il modo disciplinato per creare immagini è costruirle usando un Dockerfile.
Il Dockerfile è un file di testo simile a uno script di shell, ma supporta diversi comandi. Ogni comando che modifica il file system crea un nuovo livello. Nella prima parte abbiamo discusso l'importanza di dividere correttamente l'immagine in strati. Il Dockerfile è un grande argomento di per sé.
Qui, mostrerò semplicemente un paio di comandi per creare un'altra immagine, "oh-yeah-alpine", basata su un Dockerfile. Oltre a creare il famigerato file "yeah", installiamo anche vim. La distribuzione alpina di Linux utilizza un sistema di gestione dei pacchetti chiamato "apk". Ecco il file Docker:
FROM alpine # Copia il file "yeah" dall'host COPY yeah / yeah # Aggiorna e installa vim usando apk RUN apk update && apk aggiungi vim CMD cat / yeah
L'immagine di base è alpina. Copia il file "yeah" dalla stessa directory host in cui si trova il Dockerfile (il percorso di contesto della build). Quindi, funziona aggiornamento apk
e installa vim. Infine, imposta il comando che viene eseguito quando viene eseguito il contenitore. In questo caso stamperà sullo schermo il contenuto del file "sì".
OK. Ora che sappiamo in cosa stiamo andando, costruiamo questa cosa. L'opzione "-t" imposta il repository. Non ho specificato un tag, quindi sarà l'impostazione predefinita "latest".
> docker build -t oh-yeah-alpine. Invio del contesto di costruzione al daemon Docker 3.072 kB Passaggio 1/4: FROM alpine ---> 4e38e38c8ce0 Passaggio 2/4: COPIA sì / sì ---> 1b2a228cc2a5 Rimozione del contenitore intermedio a6221f725845 Passaggio 3/4: Aggiornamento apk RUN && apk add vim ---> L'esecuzione in e2c0524bd792 preleva http://dl-cdn.alpinelinux.org/... /APKINDEX.tar.gz recupera http: //dl-cdn.alpinelinux.org... /x86_64/APKINDEX.tar.gz v3. 4.6-60-gc61f5bf [http://dl-cdn.alpinelinux.org/alpine/v3.4/main] v3.4.6-33-g38ef2d2 [http://dl-cdn.alpinelinux.org/... / v3. 4 / community] OK: 5977 pacchetti distinti disponibili (1/5) Installazione di lua5.2-libs (5.2.4-r2) (2/5) Installazione di ncurses-terminfo-base (6.0-r7) (3/5) Installazione ncurses-terminfo (6.0-r7) (4/5) Installazione di ncurses-libs (6.0-r7) (5/5) Installazione di vim (7.4.1831-r2) Esecuzione di busybox-1.24.2-r9.trigger OK: 37 MiB in 16 pacchetti ---> 7fa4cba6d14f Rimozione del contenitore intermedio e2c0524bd792 Passaggio 4/4: CMD cat / yeah ---> Esecuzione in 351b4f1c1eb1 ---> e124405f28f4 Rimozione del contenitore intermedio 351b4f1c1eb1 Successf ully costruito e124405f28f4
Sembra buono. Cerchiamo di verificare che l'immagine sia stata creata:
> immagini docker | grep oh-yeah oh-yeah-alpine latest e124405f28f4 Circa un minuto fa 30.5 MB
Nota come l'installazione di vim e delle sue dipendenze ha gonfiato le dimensioni del contenitore dal 4,8 MB dell'immagine di base alpina a un enorme 30,5 MB!
È tutto molto bello. Ma funziona?
> docker run oh-yeah-alpine funziona!
Oh sì, funziona!
Nel caso in cui siate ancora sospettosi, andiamo nel contenitore ed esaminiamo il file "yeah" con il nostro vim appena installato.
> docker run -it oh-yeah-alpine / bin / sh / # vim yeah funziona! ~ ~ ... ~ "sì" 1L, 10C
Non te l'ho detto, ma in origine quando ho provato a costruire l'immagine oh-yeah-alpin, è rimasto sospeso per diversi minuti. Il problema era che ho appena inserito il Dockerfile nella mia home directory. Quando Docker crea un'immagine, prima impacchetta tutta la directory in cui si trova il Dockerfile (comprese le sottodirectory) e la rende disponibile per i comandi COPY nel Dockerfile.
Docker non sta cercando di essere intelligente e analizzare i tuoi comandi di COPY. Imballa tutto il resto. Nota che il contenuto della build non finirà nell'immagine, ma rallenterà il tuo comando di compilazione se il tuo contesto di compilazione è inutilmente grande.
In questo caso, ho semplicemente copiato Dockerfile e "yeah" in una sottodirectory e ho eseguito il comando di creazione docker in tale sottodirectory. Ma a volte hai una struttura ad albero complicata da cui vuoi copiare sottodirectory e file specifici e ignorarne altri. Inserisci il file .dockerignore.
Questo file ti consente di controllare esattamente cosa entra nel contesto della build. Il mio trucco preferito è escludere prima tutto e quindi iniziare a includere i bit e i pezzi di cui ho bisogno. Ad esempio, in questo caso potrei creare il seguente file .dockerignore e mantenere il file Docker e "yeah" nella mia home directory:
# Escludi TUTTO il primo * # Ora includi le cose in modo selettivo!
Non è necessario includere il "Dockerfile" o il file ".dockerignore" nel contesto della build.
La copia dei file nell'immagine a volte è ciò di cui hai bisogno, ma in altri casi potresti desiderare che i tuoi contenitori siano più dinamici e lavorino con i file sull'host. È qui che entrano in gioco volumi e supporti.
Montare le directory host è un gioco di palla diverso. I dati sono di proprietà dell'host e non dal contenitore. I dati possono essere modificati quando il container viene fermato. Lo stesso contenitore può essere avviato con diverse directory host montate.
La codifica delle immagini è molto importante se si sviluppa un sistema basato su microservizi e si generano molte immagini che a volte devono essere associate tra loro. Puoi aggiungere tutti i tag che desideri a un'immagine.
Hai già visto il tag "più recente" predefinito. A volte, ha senso aggiungere altri tag, come "testato", "release-1.4" o il commit git che corrisponde all'immagine.
Puoi taggare un'immagine durante una compilazione o dopo. Ecco come aggiungere un tag a un'immagine esistente. Nota che mentre si chiama un tag, puoi anche assegnare un nuovo repository.
> tag docker oh-yeah-alpine oh-yeah-alpine: cool-tag> tag docker oh-yeah-alpine oh-yeah-alpine-2> immagini docker | grep oh-yeah oh-yeah-alpine-2 ultimo e124405f28f4 30,5 MB oh-yeah-alpino cool-tag e124405f28f4 30,5 MB oh-yeah-alpine ultimo e124405f28f4 30,5 MB
Puoi anche annullare il contrassegno rimuovendo un'immagine dal nome del tag. Questo è un po 'spaventoso perché se rimuovi l'ultimo tag per sbaglio, perdi l'immagine. Ma se costruisci le immagini da un Dockerfile, puoi semplicemente ricostruire l'immagine.
> docker rmi oh-yeah-alpine-2 Senza tag: oh-yeah-alpine-2: latest> docker rmi oh-yeah-alpine: cool-tag Senza tag: oh-yeah-alpine: cool-tag
Se provo a rimuovere l'ultima immagine taggata, ottengo un errore perché è utilizzato da un contenitore.
> finestra mobile rmi oh-yeah-alpine Risposta di errore da demone: conflitto: impossibile rimuovere il riferimento del repository "oh-yeah-alpine" (necessario forzare) - contenitore a1443a7ca9d2 sta utilizzando l'immagine di riferimento e124405f28f4
Ma se rimuovo il contenitore ...
> Finestra mobile rmi oh-yeah-alpino Senza tag: oh-yeah-alpino: ultima Deleted: sha256: e124405f28f48e ... 441d774d9413139e22386c4820df Eliminato: sha256: 7fa4cba6d14fdf ... d8940e6c50d30a157483de06fc59 Eliminato: sha256: 283d461dadfa6c ... dbff864c6557af23bc5aff9d66de Eliminato: sha256: 1b2a228cc2a5b4 ... 23c80a41a41da4ff92fcac95101e Eliminato: sha256: fe5fe2290c63a0 ... 8af394bb4bf15841661f71c71e9a> immagini docker | grep oh-yeah
Sì. È andato. Ma non preoccuparti. Possiamo ricostruirlo:
> docker build -t oh-yeah-alpine. > immagini docker | grep oh-yeah oh-yeah-alpine ultimo 1e831ce8afe1 1 minuto fa 30,5 MB
Sì, è tornato. Dockerfile per la vittoria!
Le immagini sono molto simili sotto alcuni aspetti ai repository git. Sono anche costruiti da una serie ordinata di commit. È possibile pensare a due immagini che utilizzano le stesse immagini di base delle diramazioni (anche se non è possibile unire o ribasare in Docker). Un registro immagini è l'equivalente di un servizio di hosting git centrale come GitHub. Indovina qual è il nome del registro immagini ufficiale di Docker? Esatto, Docker Hub.
Quando esegui un'immagine, se non esiste, Docker tenterà di estrarlo da uno dei registri immagine configurati. Per impostazione predefinita va a Docker Hub, ma puoi controllarlo nel tuo file "~ / .docker / config.json". Se si utilizza un registro diverso, è possibile seguire le relative istruzioni, che in genere implicano l'accesso utilizzando le proprie credenziali.
Eliminiamo l'immagine "ciao-mondo" e tiriamo di nuovo usando il tirare il docker
comando.
> immagini docker | grep hello-world ciao-world ultimo c54a2cc56cbb 7 mesi fa 1,85 kB> docker rmi ciao-mondo ciao-mondo
È andato. Tiriamo ora.
> docker pull hello-world Come usare il tag predefinito: ultimo aggiornamento: estrazione dalla libreria / hello-world 78445dd45222: pull completo Digest: sha256: c5515758d4c5e1e ... 07e6f927b07d05f6d12a1ac8d7 Stato: nuova immagine scaricata per ciao-mondo: ultime> immagini dockere | grep hello-world hello-world latest 48b5124b2768 2 settimane fa 1,84 kB
L'ultimo ciao-mondo è stato sostituito con una versione più recente.
Spingere le immagini è un po 'più coinvolto. Per prima cosa è necessario creare un account su Docker Hub (o altro registro). Successivamente, si accede. Quindi è necessario taggare l'immagine che si desidera premere in base al nome dell'account ("g1g1" nel mio caso).
> login docker -u g1g1 -pLogin riuscito> tag docker hello-world g1g1 / hello-world> immagini docker | grep hello g1g1 / hello-world latest 48b5124b2768 2 settimane fa 1,84 kB hello-world latest 48b5124b2768 2 settimane fa 1,84 kB
Ora, posso spingere l'immagine con tag g1g1 / ciao-mondo.
> docker push g1g1 / hello-world La push fa riferimento a un repository [docker.io/g1g1/hello-world] 98c944e98de8: montato dalla libreria / hello-world più recente: digest: sha256: c5515758d4c5e ... f6d12a1ac8d7 dimensioni: 524
Le immagini Docker sono i modelli dei tuoi contenitori. Sono progettati per essere efficienti e offrono il massimo riutilizzo utilizzando un driver di archiviazione del file system di sovrapposizione.
Docker fornisce molti strumenti per elencare, ispezionare, creare e codificare le immagini. Puoi spostare e spostare le immagini in registri di immagini come Docker Hub per gestire e condividere facilmente le tue immagini.