Ciclo dei vita dei container
Nel capitolo precedente abbiamo introdotto il comando docker run
, che avvia l'esecuzione di un container a partire da un'immagine esistente, docker ps
permette, invece, di visualizzare la lista dei container attivi.Presentiamo ora i vari comandi che Docker offre per gestire in modo preciso il ciclo di vita dei container.
Per creare un container senza avviarlo, esiste il comando docker create [OPTIONS] IMAGE [COMMAND]
. Questo comando crea un layer container scrivibile sopra l'immagine specificata (per maggiori dettagli su layer immagine e layer container, si rimanda al capitolo precedente); viene stampato l'ID del container creato. Questo comando può essere adoperato per predisporre un container da eseguire successivamente.
Il comando docker start [OPTIONS] CONTAINER
avvia un container precedentemente creato. Possiamo indicare il container da lanciare mediante l'ID oppure il nome.
Usare il comando docker run
, illustrato in precedenza, equivale a chiamare in sequenza docker create
e docker start
. Per arrestare un container attivo, abbiamo a disposizione due comandi: docker stop [OPTIONS] CONTAINER
e docker kill [OPTIONS] CONTAINER
. Ricordiamo che un container resta in vita finché è in esecuzione il processo principale. docker stop
invia a tale processo il segnale SIGTERM e, dopo un certo tempo (grace period, solitamente 10 secondi), il segnale SIGKILL.
In questo intervallo il processo tenta di terminare in modo “pulito” liberando le risorse ed, eventualmente, effettuando salvataggi. Il comando docker kill
invia al processo principale il segnale SIGKILL che ne causa l'immediata interruzione. In base a queste considerazioni, in condizioni ordinarie, è preferibile impiegare docker stop
per l'arresto di un container.
Si può ricorrere a docker kill
quando il container non risponde correttamente o si trova in uno stato compromesso. Il comando docker rm [OPTIONS] CONTAINER
rimuove un container. Di default il container non deve essere attivo. Per eliminare un container in esecuzione può essere adoperata e l'opzione --force (-f)
, che invia il segnale SIGKILL prima di intraprendere la cancellazione.
Se desideriamo riavviare un container non attivo è possibile impiegare ancora il comando docker start [OPTIONS] CONTAINER
. Naturalmente il container non deve essere stato rimosso. Lanciare docker restart [OPTIONS] CONTAINER
su un container in esecuzione equivale ad invocare in serie docker stop
e docker start
.
Vediamo in azione i comandi che abbiamo introdotto:
root@server-prova:~# # creo un nuovo container nginx, ma non lo avvio
root@server-prova:~# docker create nginx
1977fb8945f469290f0ff84586935545e48ffaaff140dfe109b795d433256b5a
root@server-prova:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1977fb8945f4 nginx "/docker-entrypoint.…" 5 seconds ago Created amazing_sammet
root@server-prova:~# # faccio partire il container appena creato
root@server-prova:~# docker start 1977f
1977f
root@server-prova:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1977fb8945f4 nginx "/docker-entrypoint.…" 44 seconds ago Up 5 seconds 80/tcp amazing_sammet
root@server-prova:~# # termino l'esecuzione del container usando stop
root@server-prova:~# docker stop 1977f
1977f
root@server-prova:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1977fb8945f4 nginx "/docker-entrypoint.…" About a minute ago Exited (0) 4 seconds ago amazing_sammet
root@server-prova:~# # riattivo il container
root@server-prova:~# docker start 1977f
1977f
root@server-prova:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1977fb8945f4 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 seconds 80/tcp amazing_sammet
root@server-prova:~# # rimuovo il container in esecuzione
root@server-prova:~# docker rm -f 1977f
1977f
root@server-prova:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@server-prova:~#
Adoperando docker exec [OPTIONS] CONTAINER COMMAND
potremo eseguire un nuovo comando in un container attivo. Il comando in questione ha però vita effimera: non viene rilanciato al riavvio del container. Tra le opzioni più comunemente impiegate si ricordano -d
(detached mode) e -it
con lo stesso significato illustrato nel precedente capitolo.
Osserviamo a seguire un ulteriore esempio debitamente commentato per chiarire meglio il tutto.
root@server-prova:~# # avvio il container nginx in modalità detached
root@server-prova:~# docker run -d nginx
b120cf4e894f2fed80c73bdd1d9683dab6fd068d3a9da321052dba82ddd07552
root@server-prova:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b120cf4e894f nginx "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 80/tcp priceless_kalam
root@server-prova:~# # lancio la bash nel container appena creato
root@server-prova:~# docker exec -it b120 /bin/bash
root@b120cf4e894f:/# ls
bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var
boot docker-entrypoint.d etc lib media opt root sbin sys usr
root@b120cf4e894f:/# exit
root@server-prova:~#
Informazioni sui container
Sono disponibili vari comandi per ottenere informazioni sui container esistenti. Abbiamo già fatto ampio uso di docker ps
, per ottenere la lista dei container attivi, corredata da alcuni dettagli.
Il comando docker logs [OPTIONS] CONTAINER
permette di consultare i log del container specificato: di default nei log del container confluisce l'output dei canali STDOUT e STDERR. L'opzione --follow (-f)
consente di agganciarsi allo streaming dei log, restando in attesa di nuovi messaggi.
Il comando docker port CONTAINER
mostra come le porte esposte dal container vengono mappate verso l'esterno. Esaminiamo l'output di questa istruzione: 7474/tcp -> 0.0.0.0:7474
; la prima porta che compare è quella del container, mentre la seconda è quella dell'host.
Per visualizzare i processi in esecuzione all'interno di un container è disponibile il comando docker top CONTAINER
. Chi ha familiarità con Linux potrà facilmente verificare che l'output mostrato equivale essenzialmente a quello del comando ps -ef
lanciato all'interno del container.
Se desideriamo ottenere in tempo reale un quadro complessivo sulle risorse impiegate dai container attivi possiamo usare il comando docker stats [OPTIONS]
. Vengono presentate varie informazioni, tra cui l'uso di CPU e RAM, il numero di processi in esecuzione e il traffico di rete.
Ancora una volta tocchiamo con mano quanto appena presentato attraverso un esempio commentato che ci consentirà di sperimentare al meglio i concetti esposti.
root@server-prova:~# # avvio due container: nginx e neo4j (vedi capitolo precedente)
root@server-prova:~# docker run -d nginx
6f792fc7c72432a92caa778a622ffb519ca3f1a10e81532632df6c44a001b56f
root@server-prova:~# docker run -d -p7474:7474 -p7687:7687 -e NEO4J_AUTH=neo4j/s3cr3t neo4j
70d6b30619c8907543f030e07d6b481852d1e0313b24d15d5dbfbfc365a394ca
root@server-prova:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
70d6b30619c8 neo4j "/sbin/tini -g -- /d…" 6 seconds ago Up 5 seconds 0.0.0.0:7474->7474/tcp, 7473/tcp, 0.0.0.0:7687->7687/tcp thirsty_beaver
6f792fc7c724 nginx "/docker-entrypoint.…" 12 seconds ago Up 11 seconds 80/tcp
keen_saha
root@server-prova:~# # consulto i log del container nginx
root@server-prova:~# docker logs 6f79
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
root@server-prova:~# # visualizzo il mapping delle porte del container neo4j
root@server-prova:~# docker port 70d6
7474/tcp -> 0.0.0.0:7474
7687/tcp -> 0.0.0.0:7687
root@server-prova:~# # consulto i processi in esecuzione nel container nginx
root@server-prova:~# docker top 6f79
UID PID PPID C STIME TTY TIME CMD
root 1681 1645 0 19:44 ? 00:00:00 nginx: master process nginx -g daemon off;
systemd+ 1748 1681 0 19:44 ? 00:00:00 nginx: worker process
root@server-prova:~# # visualizzo le statistiche dei container in esecuzione
root@server-prova:~# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
70d6b30619c8 thirsty_beaver 0.00% 357.9MiB / 1.947GiB 17.95% 796B / 0B 0B / 220MB 43
6f792fc7c724 keen_saha 0.00% 2.172MiB / 1.947GiB 0.11% 976B / 0B 0B / 8.19kB 2
Il comando docker inspect [OPTIONS] NAME|ID
fornisce dati dettagliati e di basso livello su tutti gli oggetti gestiti dal Docker engine, tra cui i container. L'output fornito è in formato JSON. Tra quanto viene mostrato troviamo lo stato del container, informazioni sull'immagine di partenza, sulle variabili d'ambiente, sui volumi montati e sulle impostazioni di rete.
Presentiamo ora, quindi, una visualizzazione di docker inspect
a scopo meramente esemplificativo. L'output risulta particolarmente verboso quindi per semplificare la visualizzazione su questa pagina web al posto di numerose righe è stato inserito a mano un omissis [...] che ovviamente non compare nella visualizzazione originale.
root@server-prova:~# # consulto i dettagli del container nginx
root@server-prova:~# docker inspect 6f79
[
{
"Id": "6f792fc7c72432a92caa778a622ffb519ca3f1a10e81532632df6c44a001b56f",
"Created": "2021-04-18T17:44:04.945274833Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 1681,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-04-18T17:44:05.472757925Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:62d49f9bab67f7c70ac3395855bf01389eb3175b374e621f6f191bf31b54cd5b",
"ResolvConfPath": "/var/lib/docker/containers/6f792fc7c72432a92caa778a622ffb519ca3f1a10e81532632df6c44a001b56f/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/6f792fc7c72432a92caa778a622ffb519ca3f1a10e81532632df6c44a001b56f/hostname",
"HostsPath": "/var/lib/docker/containers/6f792fc7c72432a92caa778a622ffb519ca3f1a10e81532632df6c44a001b56f/hosts",
"LogPath": "/var/lib/docker/containers/6f792fc7c72432a92caa778a622ffb519ca3f1a10e81532632df6c44a001b56f/6f792fc7c72432a92caa778a622ffb519ca3f1a10e81532632df6c44a001b56f-json.log",
"Name": "/keen_saha",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
[...]
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "00ec790341b78dc9e9b6b2254d4bb6cb477a7b7cc1d536e67e84d1434c8e908f",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "af32c3786d4b4ccda220ee8f585a98817adffcf008f8e5853ac160e79ab98c04",
"EndpointID": "00ec790341b78dc9e9b6b2254d4bb6cb477a7b7cc1d536e67e84d1434c8e908f",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
Operazioni di import/export
In questa sezione, presentiamo alcuni comandi per l'esecuzione di semplici attività di import/export relative ai container. Il comando docker cp
permette di copiare files e directories tra un container e il filesystem locale. La sintassi da impiegare è la seguente:
docker cp CONTAINER:SRC_PATH DEST_PATH
per copiare files dal container al filesystem locale;
docker cp SRC_PATH CONTAINER:DEST_PATH
per copiare files dal filesystem locale al container.
Vediamolo in azione qui a seguire.
root@server-prova:~# # avvio il container nginx
root@server-prova:~# docker run -d nginx
7a668130dd0faa1b3c75ad9f11885d77632d3031bda322a6d7e138b927d37b5d
root@server-prova:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7a668130dd0f nginx "/docker-entrypoint.…" 9 seconds ago Up 7 seconds 80/tcp cool_allen
root@server-prova:~# # lancio la bash nel container per scegliere un file da copiare nel filesystem locale
root@server-prova:~# docker exec -it 7a66 /bin/bash
root@7a668130dd0f:/# ls
bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var
boot docker-entrypoint.d etc lib media opt root sbin sys usr
root@7a668130dd0f:/# exit
root@server-prova:~# # copio il file docker-entrypoint.sh
root@server-prova:~# docker cp 7a66:/docker-entrypoint.sh .
root@server-prova:~# ls
docker-entrypoint.sh prova.txt provisioning.log 'Riferimenti KB Cloud Aruba.txt'
root@server-prova:~# # creo in locale il file nuovo.txt, che copierò all'interno del container
root@server-prova:~# touch nuovo.txt
root@server-prova:~# # lo copio nel container
root@server-prova:~# docker cp nuovo.txt 7a66:/
root@server-prova:~# # entro nel container, per verificare la presenza del file copiato
root@server-prova:~# docker exec -it 7a66 /bin/bash
root@7a668130dd0f:/# ls
bin docker-entrypoint.d home media opt run sys var
boot docker-entrypoint.sh lib mnt proc sbin tmp
dev etc lib64 nuovo.txt root srv usr
root@7a668130dd0f:/#
Il comando docker export [OPTIONS] CONTAINER
consente di esportare il filesystem di un container sotto forma di archivio tar. Precisiamo che questo comando non esporta il contenuto di eventuali volumi montati dal container; maggiori dettagli sui volumi saranno forniti nel successivo capitolo sullo storage in Docker. Se interveniamo su un container in esecuzione, apportando dei cambiamenti al filesystem, le modifiche non risulteranno persistenti sull'immagine di partenza che è immutabile.
Il comando docker commit [OPTIONS] CONTAINER_IMAGE
consente di salvare le modifiche creando una nuova immagin; a partire dall'immagine creata, potremo istanziare nuovi container con il filesystem desiderato. Questa pratica, benché utile in alcune situazioni, non è il percorso maestro per realizzare nuove immagini ed è generalmente sconsigliabile: nel prossimo capitolo, vedremo come costruire immagini Docker personalizzate in modo documentato e riproducibile, compilando in modo appropriato il Dockerfile.
L'uso di questi comandi, come ormai è per noi abituale, è immediatamente tastato sul campo.
root@server-prova:~# # avvio il container nginx
root@server-prova:~# docker run -d nginx
4747bf7124e77e5010414080a89f8d45e7089786d9dd14466166ce28f34ca4ef
root@server-prova:~# # esporto in locale il filesystem del container appena creato
root@server-prova:~# docker export 4747 > archivio.tar
root@server-prova:~# ls
archivio.tar nuovo.txt provisioning.log
docker-entrypoint.sh prova.txt 'Riferimenti KB Cloud Aruba.txt'
root@server-prova:~# # altero il filesystem del container nginx, creando il file test.txt
root@server-prova:~# docker exec -it 4747 /bin/bash
root@4747bf7124e7:/# touch test.txt
root@4747bf7124e7:/# ls
bin docker-entrypoint.d home media proc sbin test.txt var
boot docker-entrypoint.sh lib mnt root srv tmp
dev etc lib64 opt run sys usr
root@4747bf7124e7:/# exit
root@server-prova:~# # genero una nuova immagine, a partire dal container modificato
root@server-prova:~# docker commit 4747 nginx_modificato:latest
sha256:201a75a7b548601dac146182b1a59414ff654095e04a7a1aaf8169669ccf6b60
root@server-prova:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx_modificato latest 201a75a7b548 5 seconds ago 133MB
alpine latest 6dbb9cc54074 4 days ago 5.61MB
nginx latest 62d49f9bab67 5 days ago 133MB
neo4j latest 7d45ab82e213 7 days ago 559MB
root@server-prova:~#
I prossimi passi
In questo capitolo abbiamo appreso come controllare il ciclo di vita dei container: creazione, avvio, arresto, riavvio ed esecuzione di nuovi processi. Abbiamo esplorato i comandi più importanti per monitorare lo stato dei container esistenti e appreso come realizzare alcune attività elementari di import/export. Finora abbiamo sempre operato con immagini preesistenti, recuperate dal Docker Hub. Nel prossimo capitolo comprenderemo come costruire immagini personalizzate, descritte nel Dockerfile.