In questa sezione ci faremo un’idea di base del funzionamento di un container, in modo da avere gli strumenti minimi per affrontare il prossimo capitolo.
Faccio una premessa, io sono solito utilizzare il client per mac. I comandi sono gli stessi per tutti i sistemi operativi, tuttavia può capitare che qualche immagine non sia compatibile con alcuni sistemi operativi o architetture. Questo risulterà più chiaro nel prossimo capitolo ed in particolare quando parleremo di immagini ad architettura multipla e di manifest.
Lanciare il primo container
Iniziamo con l’istruzione di base, quella che permette di creare un container a partire da un immagine, ovvero:
docker container run
L’istruzione “docker container run”, istanzia un container a partire da una specifica immagine.
Coma da tradizione, quando si inizia a prendere confidenza con una nuova tecnologia, si comincia sempre con un “Hello world”. Guarda caso esiste proprio un’immagine che si chiama “hello-world”.
Eseguiamo quindi il comando
docker container run hello-world
Nel mio caso, l’output generato è il seguente:
Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 0e03bdcc26d7: Pull complete Digest: sha256:8e3114318a995a1ee497790535e7b88365222a21771ae7e53687ad76563e8e76 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
Interpretazione dell’output
Le prime righe dell’output prodotto dal run sono particolarmente interessanti perché ci permettono di intuire cosa sta succedendo under-the-hood.
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:8e3114318a995a1ee497790535e7b88365222a21771ae7e53687ad76563e8e76
Status: Downloaded newer image for hello-world:latest
Come prima cosa vediamo che Docker cerca di recuperare l’immagine richiesta da un repository locale all’host, ma senza avere successo.
Per ora tralasciamo la stringa “:latest”, avremo modo di parlarne molto presto.
Dal momento che abbiamo richiesto un’immagine che non abbiamo mai scaricato prima d’ora, essa viene recuperata dal docker daemon, come vediamo dalla seconda riga.
Subito dopo viene indicato l’esito del pull dell’immagine, l’hash a 256 bit ottenuto mediante l’algoritmo di encryption sha256 e la conferma di avvenuto download.
Tutto ciò che segue è l’output del container che il demone di Docker inoltra al client a sua volta scrive sullo standard output.
Visualizzare i container
Abbiamo creato un container, ora verifichiamo i dettagli mediante il comando che fornisce la lista dei container presenti sul nostro host:
docker container ls
Eseguendo questa istruzione, però, ci accorgiamo di qualcosa di strano. La lista non mostra nessun container relativo all’immagine “hello-world”.
Com’è possibile?
Eppure lo abbiamo creato! Abbiamo anche visto l’output!
Quando abbiamo di questi dubbi, la soluzione più efficace è quella di utilizzare l’help del comando.
docker container ls --help
Ottenendo questo output
Usage: docker container ls [OPTIONS] List containers Aliases: ls, ps, list Options: -a, --all Show all containers (default shows just running) -f, --filter filter Filter output based on conditions provided --format string Pretty-print containers using a Go template -n, --last int Show n last created containers (includes all states) (default -1) -l, --latest Show the latest created container (includes all states) --no-trunc Don't truncate output -q, --quiet Only display numeric IDs -s, --size Display total file sizes
Ecco svelato il problema!
Eseguendo il comando nella versione di default, ovvero senza flag aggiuntivi, vengono mostrati solo i container in esecuzione.
Questo significa che il container che abbiamo appena creato non è più in esecuzione. Nel caso specifico, hello-world termina dopo aver stampato un messaggio.
Per vedere tutti i container, compresi quelli che non sono in esecuzione, dobbiamo aggiungere il flag –all o -a.
La nuova versione del comando diventa quindi:
docker container ls --all
Dalla quale otteniamo un output di questo tipo:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9f0b8fee671c hello-world "/hello" About a minute ago Exited (0) About a minute ago laughing_visvesvaraya
Ora il container che abbiamo generato a partire dall’immagine hello-world è visibile.
Nella colonna status si nota che il container è terminato. Vedremo dettagliatamente questi aspetti nel capitolo dedicato ai container.
Eliminare un container
Sebbene in molti casi può risultare comodo avere accesso ai container terminati, questa volta non ce ne facciamo niente e decidiamo di eliminare il container appena creato.
Per eliminare il container non più in uso dalla lista, il comando è:
docker container rm
Per container_id si intende il codice identificativo del container visibile nella prima colonna del comando docker container ls. In questo caso, l’istruzione da eseguire sarà:
docker container rm 9f0b8fee671c
In generale, quando viene richiesto di inserire il container id, è sufficiente inserire i primi caratteri dell’hash a condizione che non ci sia un altro container con lo stesso prefisso.
Container rimossi automaticamente
Quando sappiamo già non ci interessa persistere un container una volta terminato, possiamo eseguirlo direttamente con il flag –rm. Questa particolare notazione su occuperà di rimuovere automaticamente il container quando terminerà la sua esecuzione.
Nel caso di hello world avremmo potuto eseguire il comando in questo modo:
docker container run --rm hello-world
Start & Stop vs Pause & Unpause
Spesso si fa confusione tra questi comandi, ma il concetto è molto semplice.
Nel primo caso i container vengono terminati e riavviati. Nel secondo caso vengono “congelati” e “risvegliati”.
Per fermare e riavviare i container si usano:
docker container start docker container stop
Per sospendere e risvegliare un container, invece si usano:
docker container pause docker container unpause
I comandi saranno sempre seguiti dal o dai container_id dei container ai quali vogliamo applicare l’istruzione.
Il modo migliore per spiegare cosa cambia tra i due è mediante un esempio. In questo caso ho scelto di utilizzare un’immagine di Alpine Linux sulla quale eseguirò lo start e lo stop di un container.
Pause e unpause hanno la stessa notazione, quindi eviterò di riportarli.
Proviamo con il primo set di comandi, ovvero container start e container stop. Dato che abbiamo imparato che i container possono terminare l’esecuzione appena dopo l’avvio, mettiamo le mani avanti e impostiamo uno sleep di 1000 secondi. In questo modo il container rimarrà in esecuzione per 1000 secondi prima di terminare.
Per impostare lo sleep è sufficiente digitare il comando ‘sleep 1000’ in coda all’istruzione di run.
docker container run alpine sleep 1000
Quando parleremo nel dettaglio di Dockerfile, la modalità con la quale viene invocato questo comando sarà più chiara, per ora immaginate che il comando specificato in coda al comando run, sovrascrive l’ultimo comando che eseguirebbe il container all’avvio.
Ora per 1000 secondi il terminale rimarrà occupato, poi, secondo il normale flusso, il container terminerà rilasciando il terminale.
Apriamo allora un nuovo tab e cerchiamo il nostro container in esecuzione con:
docker container ls
Questa volta vediamo che l container figura nella lista. Nel mio case il container id è ‘61652fca85f0′, quindi per fermare il container mi basterà digitare:
docker container stop 616
Al termine di questa istruzione il container non sarà più in esecuzione, quindi se proviamo a cercarlo con docker container ls non lo troveremo nella lista.
Per visualizzarlo, ci basterà eseguire il comando docker container ls –all, e lo troveremo con stato Exited(137) e non più Exited(0).
Per far ripartire il container, ci basterà eseguire:
docker container start 616
Eseguendo docker container ls vediamo che il container è attivo perché la colonna relativa allo stato riporterà: Up.
Curiosità
Abbiamo assimilato i rudimenti della CLI per quanto riguarda i container.
Dopo aver letto lo scorsa sezione, a qualcuno potrebbe venire la curiosità di sapere cosa succede sotto il cofano quando viene avviato un container.
Se ti riconosci in questa descrizione, le prossime righe sono per te!
Quando lanciamo il comando docker container run, il Client converte l’istruzione in una chiamata POST all’endpoint che il demone di Docker ha predisposto a tale scopo.
Il demone invoca containerd che che chiede a runc di istanziare il container.
runc crea il container e termina, mentre il processo containerd-shim diventerà il nuovo padre del container.
—
Prosegui su: Immagini