IL BLOG DEGLI RHCE ITALIANI

Cos’è un Linux Container? Esploriamo Docker ed la gestione dei Container.

Gianni Salinetti

docker-logo

Negli ultimi anni nel mondo IT la virtualizzazione ha avuto uno sviluppo preponderante affermandosi sia in ambito di architetture on-premise che cloud in cui è ambita la possibilità di fare horizontal scaling su più nodi di calcolo. Spesso la virtualizzazione tradizionale da questo punto di vista risulta essere pesante per via dello strato di hardware virtualizzato gestito con cui la VM deve interfacciarsi e dell’esecuzione di un set completo di processi, servizi, network layers ecc, come in un’installazione bare-metal. Questo in alcuni casi può rallentare o appesantire di molti il provisioning di risorse e di conseguenza l’erogazione dei servizi.

Il progetto Docker parte dall’esigenza di implementare, tramite un engine open source per la gestione dei container, una soluzione più performante che garantisse un buon livello di isolamento applicativo e di risorse.

Cos’è un container? Innanzitutto un container NON È una macchina virtuale. Un container è un’applicazione isolata (con tutte le sue dipendenze) eseguita in namespace separati (network namespace, file system, users, IPC). Il livello di isolamento è rafforzato da SELinux che impedisce ai processi all’interno di un container di agire all’esterno di esso. I container condividono il kernel della macchina host e non hanno uno strato di virtualizzazione tramite hypervisor. E’ possibile creare un container partendo da template di filesystem basati sulle distribuzioni più diffuse (RHEL, Fedora, CentOS, Ubuntu, Debian, ecc) e importarvi i relativi binari.
I Docker container non hanno un init e quindi non eseguono servizi. Nella maggior parte dei casi il processo con PID 1 all’interno del container è lo stesso processo eseguito nel momento della creazione o l’entry point del container, ovvero un processo che è stato configurato in fase di provisioning per essere eseguito automaticamante alla creazione del container. Ad esempio, un container PostgreSql avrà come entry point l’esecuzione del processo server del db stesso.


Setup

L’installazione base di Docker è molto semplice. Per utilizzare Docker in RHEL/CentOS è necessario installare il pacchetto omonimo con il comando:

yum install docker

Oppure, se si lavora con Fedora 22+ si può installare utilizzando l’utility dnf che è il nuovo package manager di default.

dnf install docker

Una volta installato è possibile avviare e opzionalmente abilitare il servizio in systemd con i comandi:

systemctl enable docker
systemctl start docker

Docker Images

Le immagini utilizzate per eseguire i container possono essere create dall’amministratore o dallo sviluppatore o scaricate da un Registry, che può essere pubblico o privato. Nella sua configurazione di default Docker utilizza il Docker Hub (docker.io) ovvero il registro pubblico dove varie community pubblicano le proprie immagini con le personali customizzazioni. Da un punto di vista di sicurezza questa pratica può mettere a rischio sistemi di produzione in quanto le immagini caricate sul public registry non sono sottoposte a controlli accurati sul loro effettivo contenuto. Se si utilizza RHEL la best practice consigliata è la configurazione di registry.access.redhat.com come default registry. Tutte le Docker images in questo registry sono testate e certificate da Red Hat stessa.
La customizzazione del default registry viene fatta editando il file /etc/sysconfig/docker.

Per ricercare un’immagine nei registry si può utilizzare il comando

docker search PATTERN

Per scaricare un’immagine individuata con la ricerca si utilizza il comando

docker pull IMAGE_NAME

Durante il download si può notare che verranno scaricati diversi layer parallelamente.

Una volta scaricate una o più immagini si può visualizzare l’elenco totale di tutte le immagini disponibili localmente con il comando

docker images

Ad ogni immagine viene associato un IMAGE_ID che corrisponde alle prime 12 cifre di un hash SHA256 calcolato sull’immagine. Lo stesso hash rimane l’identificativo univoco della Docker image scaricata.

Per eliminare una Docker image scaricata:

docker rmi IMAGE_ID

Le immagini scaricate vengono copiate nella direcotry /var/lib/docker/ ma in questa directory non si troveranno file omonimi alle immagini in quanto Docker utilizza gli hash per gestire le immagini.

Le immagini Docker sono multilayer. Un’immagine è composta da N strati read-only che rappresentano le modifiche al filesystem (in un modo simile a degli snapshot cumulativi). Docker utilizza una strategia Copy-on-Write per le immagini e i container al fine di ottimizzare l’uso di risorse e le performance.
Quando si scarica una nuova immagine si può vedere il comando

docker pull

scaricare contemporaneamente ognuno di questi layer. Questo approcco ha il vantaggio di poter utilizzare layer comuni su immagini diverse: si pensi ad una immagine base Fedora modificata per avere un http server e alla stessa immagine modificata installando PostgreSql. Queste tre immagini avranno in comune un layer di base e verranno poi aggiunti layer successivi.

Quando si avvia un nuovo container partendo dall’immagine viene creato un layer read/write in cima alla pila. questo layer scrivibile è di fatto la principale differenza tra un container e la sua immagine. Avviare più container dalla stessa immagine significa creare più layer r/w “appoggiati” sullo stack ro.

container-layers

Per lo storage Docker fa uso, in RHEL/Fedora/CentOS, del driver/framework Device Mapper. Originariamente Docker girava su Ubuntu e Debian e utilizzava AUFS come backend di storage. Anche se inizialmente Red Hat ha cercato di integrare AUFS nel mainline del kernel, successivamente si è optato per una tecnologia differente ed è nata una collaborazione con Docker Inc. per integrare il driver devicemapper.

Quando si installa Docker utilizzando il driver devicemapper viene creato un thin pool (a partire da block device disponibili o da loop device).
Nel pool viene creato un base device, ovvero un thin device con un filesystem: ogni nuovo image layer sarà uno snapshot copy-on-write di questo base device. I layer dei container saranno anch’essi snapshot copy-on-write dell’immagine da cui sono creati. Il driver devicemapper alloca spazio ai vari layer quando viene effettuatata un’operazione di scrittura.

two_dm_container


Esecuzione di Container

Una volta scaricate le immagini necessarie si possono avviare i container con il comando

docker run IMAGE_NAME

Le opzioni applicabili sono numerose e permettono di influenzare il comportamento del container sotto molti aspetti. Per un elenco più dettagliato delle opzioni del comando run: https://docs.docker.com/engine/reference/run/

In questo modo verrà avviato un container che eseguirà un eventuale entry point.

Si può eseguire un qualsiasi altro processo (a condizione che i binari esistano nel filesystem) con il comando

docker run -it IMAGE_NAME COMMMAND

Le opzioni -i e -t rispettivamente abilitano lo stdin e una pseudo tty. Ad esempio, se si vuole eseguire una shell bash su un generico container “centos” scaricato dal public registry:

docker run -it docker.io/centos /bin/bash

L’approccio CoW permette di ridurre drasticamente i tempi di avvio di un container in quanto è necessario soltanto creare il thin layer r/w. Notare che quando viene creato il nuovo container viene restituito un UUID e che lo stesso, omonimo, corrisponde ad una sottodirectory di /var/lib/docker/containers.

E’ possibile eseguire un ulteriore processo anche una volta che il container è stato avviato (ad esempio una shell per fare un eventuale troubleshooting) con

docker exec -it <CONTAINER_NAME_OR_ID> COMMAND

CONTAINER_NAME_OR_ID corrisponde al nome pseudocasuale generato per il container o il suo ID univoco.

A volte può essere necessario eseguire un container in modalità detached, assicurandosi che il suo entry point non venga eseguito in foreground (ad esempio perché non si vogliono messaggi in stdout). Per fare ciò si può passare una semplice opzione -d (detached):

docker run -d docker.io/wildfly

Questo comando eseguirà un’instanza standalone di wildfly senza inviare i messaggi a stdout come fa di default WildFly/JBoss con il suo CONSOLE handler.


Persistent Storage

E’ possibile avviare un container utilizzando storage persistente dell’host ovvero una porzione di file system montato sotto un mount point specificato all’avvio:

docker run [OPTIONS] -v LOCAL_DIR:CONTAINER_MOUNT_POINT IMAGE_NAME [COMMAND]

Ad esempio, per montare le directory /bin e /sbin nel container e accedere così a tutta una serie di utility command line che potrebbero non essere installate nel container:

docker run -it -v /bin:/mnt/bin -v /sbin:/mnt/sbin docker.io/centos /bin/bash

I mount point all’interno del container vengono creati dinamicamente.


Port Mapping e Networking

Quando viene eseguito, un container ha un indirizzo IP assegnato dinamicamente nella subnet definita (default 172.17.0.0/16). Non sappiamo ad ogni modo l’indirizzo del container in modo univoco e inoltre questo non è raggiungibile da un host remoto. Per rendere un servizio accessibile dall’esterno in modo persistente, a prescindere dall’indirizzo ip interno del container possiamo assegnare uno o più port mapping all’esecuzione del container.

docker run -p LOCAL_PORT:CONTAINER_PORT IMAGE_ID [COMMAND]

Ad esempio, per avviare un container httpd e rendere disponibile la porta 80 del container sulla 8080 dell’host:

docker run -p 8080:80 docker.io/httpd

Dal punto di vista della gestione della rete Docker utilizza di default un Linux Bridge denominato docker0, al quale assegna indirizzo 172.17.0.1/16. Al bridge docker0 vengono agganciate le interfacce vethxxxxxxx che corrispondono all’endpoint lato host delle interfacce ethX nel container, separate graziea un network namespace dedicato.

Viene definita una rotta sul network 172.17.0.0/16 per il device docker0. Questo permette di pingare il container creato una volta noto il suo indirizzo.

Un metodo semplice per visualizzare la configurazione di rete del container è l’esecuzione del comando

docker inspect CONTAINER_NAME_OR_ID

In questo modo si produce un output in formato JSON contenente tutte le impostazioni di runtime del container. Di seguito un ipotetico output di un container postgresql:

[
    {
        "Id": "6eab63c34478e87e7d99e7db28b6353e1c521350ca4c6016c9b0750d1477815b",
        "Created": "2016-07-07T18:11:18.753318833Z",
        "Path": "/docker-entrypoint.sh",
        "Args": [
            "postgres"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 18763,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2016-07-07T18:11:19.810927964Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:247a11721cbdbd3f3ed1001116b88f8cc0a4087b228ac61db7b6c6927995b9d4",
        "ResolvConfPath": "/var/lib/docker/containers/6eab63c34478e87e7d99e7db28b6353e1c521350ca4c6016c9b0750d1477815b/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/6eab63c34478e87e7d99e7db28b6353e1c521350ca4c6016c9b0750d1477815b/hostname",
        "HostsPath": "/var/lib/docker/containers/6eab63c34478e87e7d99e7db28b6353e1c521350ca4c6016c9b0750d1477815b/hosts",
        "LogPath": "",
        "Name": "/adoring_ramanujan",
        "RestartCount": 0,
        "Driver": "devicemapper",
        "MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c181,c431",
        "ProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c181,c431",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "journald",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "ShmSize": 67108864,
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "KernelMemory": 0,
            "Memory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": -1,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null
        },
        "GraphDriver": {
            "Name": "devicemapper",
            "Data": {
                "DeviceId": "542",
                "DeviceName": "docker-253:3-1441817-37934a3cdd7e3d7ff1fd54951988241d02a43a29b0defa0c2b5818c882e79c68",
                "DeviceSize": "107374182400"
            }
        },
        "Mounts": [
            {
                "Name": "ba5f53004f49fd22b5f6e42bd91dd80c0ad37fd146951d69ed1dec99a63dbe57",
                "Source": "/var/lib/docker/volumes/ba5f53004f49fd22b5f6e42bd91dd80c0ad37fd146951d69ed1dec99a63dbe57/_data",
                "Destination": "/var/lib/postgresql/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
        "Config": {
            "Hostname": "6eab63c34478",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "5432/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/lib/postgresql/9.5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.7",
                "LANG=en_US.utf8",
                "PG_MAJOR=9.5",
                "PG_VERSION=9.5.3-1.pgdg80+1",
                "PGDATA=/var/lib/postgresql/data"
            ],
            "Cmd": [
                "postgres"
            ],
            "Image": "docker.io/postgres",
            "Volumes": {
                "/var/lib/postgresql/data": {}
            },
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "c28f03093e9b7972a1199762a54538ac56a238f2c57c4f3ae9237577c6b531c7",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "5432/tcp": null
            },
            "SandboxKey": "/var/run/docker/netns/c28f03093e9b",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "884f6a93231c0869d7e25ff729fcb31e8602b76c3ceeecc03b9aa030bf004572",
            "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": "c292fc6b3e9bfb0b348001751cc4eb91d8d9d552931c501b5663a2f2fc5fdcdd",
                    "EndpointID": "884f6a93231c0869d7e25ff729fcb31e8602b76c3ceeecc03b9aa030bf004572",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02"
                }
            }
        }
    }
]

 

Come si può vedere questo JSON contiene tutte le informazioni che ci servono sul container e in particolare i “NetworkSettings” ci danno non solo l’indirizzo IP (172.17.0.2/16) del nostro container ma anche la porta esposta (5432/tcp per postgresql), il default gateway (che è giustamente l’indirizzo ip che vediamo assegnato al device docker0) e il mac address generato per il device eth0 interno al container.

Un altro metodo possibile per visualizzare l’indirizzo IP del container senza accedervi  o eseguire comandi docker è il file /var/lib/docker/containers/<CONTAINER_ID>/hosts. Questo è il file hosts che verrà copiato nella directory /etc/hosts del container e contiene le risoluzioni nomi di eventuali altri container e, sempre, la risoluzione tra IP assegnato e hostname generato. L’hostname generato corrisponde ai primi 12 caratteri dell’hash del container.
Oltre al file host si può notare che nella directory è presente molto altro: il file resolv.conf, il file hostname contente l’hostname generato del container, e i file hostconfig.json e config.v2.json. Quest’ultimo in particolare è esattamente il contenuto dell’output del comando docker inspect lanciato prima. Altra via, dunque, di visualizzare le impostazioni generali.

Un altro modo per avere informazioni di rete più dettagliate sui container agganciati al bridge docker0 è l’uso del comando

docker network inspect bridge

Questo mostrerà un output in formato json con informazioni sul bridge docker0 e su tutti i container attivi al momento, tra cui MAC address e indirizzo IP.


Stop e Commit

Per fermare un container avviato

docker stop CONTAINER_NAME_OR_ID

Una volta fermato un container il suo thin layer r/w non è stato ancora completamente eliminato. Se si sono fatte delle modifiche a questo layer (nel caso più tipico installazioni e configurazioni) si può creare un nuovo layer read-only andando di fatto a generare una nuova Docker image che condivide tutti i precedenti layer più il nuovo. Per fare questo si esegua il comando:

docker commit CONTAINER_NAME_OR_ID [REPOSITORY[:TAG]]

E’ buona abitudine, anche se opzionale, assegnare alla nuova immagine un riferimento al registry e al nome e un tag. Ad esempio, per creare una nuova immagine dopo aver modificato la configurazione di un container JBoss:

docker commit high_morse docker.io/jboss/JBossEAP7:latest

JBossEAP7 è il nome scelto facoltativmente per l’immagine e latest è il tag di default. E’ prassi comune assegnare la versione al tag: le immagini con il tag latest vengono preferite nella creazione di container nel caso esistano più immagini omonime.

Il comando docker commit restuisce un hash calcolato al momento. Si può riscontrare che lo stesso hash corrisponde ad un file omonimo di metadati json in /var/lib/docker/image/devicemapper/imagedb/content/sha256/ e alla directory omonima in /var/lib/docker/image/devicemapper/imagedb/metadata/sha256/

Per eliminare definitivamente un container si esegue il comando

docker rm CONTAINER_NAME_OR_ID

Questo comando elimina anche l’omonima directory in /var/lib/docker/containers.


DOCKER REMOTE API

Non sempre possiamo accedere direttamente al client docker. In tal caso possiamo utilizzare le remote API. Di default Docker è in ascolto su /var/run/docker.sock ma ovviamente può essere messo in ascolto su un inet socket e diventare raggiungibile dall’esterno. Questa possibilità apre a possibili rischi di sicurezza e va quindi valutata con molta attenzione.

Nel seguente esempio otteniamo lo stesso output ottenuto con il comando Docker inspect, ovvero il json di configurazione a runtime del container:

curl --unix-socket /var/run/docker.sock "GET /containers/6eab63c34478e87e7d99e7db28b6353e1c521350ca4c6016c9b0750d1477815b/json"

Notare che è un semplicissimo metodo GET dove l’unico parametro variabile è il nome del container.

Possiamo allo stesso modo ottenere un elenco dei container attivi:

curl --unix-socket /var/run/docker.sock "GET /containers/json"

Oppure ottenere un elenco delle immagini disponibili localmente:

curl --unix-socket /var/run/docker.sock "GET /images/json"

Per poi andare a vedere nel dettaglio le informazioni di una singola immagine:

curl --unix-socket /var/run/docker.sock "GET /images/docker.io/postgres:latest/json"

Questo mi riporta un output esteso in formato JSON delle caratteristiche dell’immagine, compresi, ad esempio, i suoi entry point (ovvero i comandi che vengono eseguiti all’avvio del container).

Questo è ad esempio l’output del comando appena descritto che mostra le caratteristiche in un’immagine postgres presa dal Docker Hub.

{
    "Architecture": "amd64",
    "Author": "",
    "Comment": "",
    "Config": {
        "AttachStderr": false,
        "AttachStdin": false,
        "AttachStdout": false,
        "Cmd": [
            "postgres"
        ],
        "Domainname": "",
        "Entrypoint": [
            "/docker-entrypoint.sh"
        ],
        "Env": [
            "PATH=/usr/lib/postgresql/9.5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "GOSU_VERSION=1.7",
            "LANG=en_US.utf8",
            "PG_MAJOR=9.5",
            "PG_VERSION=9.5.3-1.pgdg80+1",
            "PGDATA=/var/lib/postgresql/data"
        ],
        "ExposedPorts": {
            "5432/tcp": {}
        },
        "Hostname": "b0cf605c7757",
        "Image": "e1e1bf742f6a850ebb2cd78daddc184f82ebe58ce8b01f2fac85c15af4368e05",
        "Labels": {},
        "OnBuild": [],
        "OpenStdin": false,
        "StdinOnce": false,
        "Tty": false,
        "User": "",
        "Volumes": {
            "/var/lib/postgresql/data": {}
        },
        "WorkingDir": ""
    },
    "Container": "4c659084edf3be4d7e00155cb16e903f10a31806fb214b3c1ecddf13b93c1a33",
    "ContainerConfig": {
        "AttachStderr": false,
        "AttachStdin": false,
        "AttachStdout": false,
        "Cmd": [
            "/bin/sh",
            "-c",
            "#(nop) CMD ["postgres"]"
        ],
        "Domainname": "",
        "Entrypoint": [
            "/docker-entrypoint.sh"
        ],
        "Env": [
            "PATH=/usr/lib/postgresql/9.5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "GOSU_VERSION=1.7",
            "LANG=en_US.utf8",
            "PG_MAJOR=9.5",
            "PG_VERSION=9.5.3-1.pgdg80+1",
            "PGDATA=/var/lib/postgresql/data"
        ],
        "ExposedPorts": {
            "5432/tcp": {}
        },
        "Hostname": "b0cf605c7757",
        "Image": "e1e1bf742f6a850ebb2cd78daddc184f82ebe58ce8b01f2fac85c15af4368e05",
        "Labels": {},
        "OnBuild": [],
        "OpenStdin": false,
        "StdinOnce": false,
        "Tty": false,
        "User": "",
        "Volumes": {
            "/var/lib/postgresql/data": {}
        },
        "WorkingDir": ""
    },
    "Created": "2016-05-24T06:23:40.855876854Z",
    "DockerVersion": "1.9.1",
    "GraphDriver": {
        "Data": {
            "DeviceId": "447",
            "DeviceName": "docker-253:3-1441817-96047bb9151fe579547e21b394dd18af970db17768552e81c6fbd6037a03b83a",
            "DeviceSize": "107374182400"
        },
        "Name": "devicemapper"
    },
    "Id": "sha256:247a11721cbdbd3f3ed1001116b88f8cc0a4087b228ac61db7b6c6927995b9d4",
    "Os": "linux",
    "Parent": "",
    "RepoDigests": [],
    "RepoTags": [
        "docker.io/postgres:latest"
    ],
    "Size": 265813152,
    "VirtualSize": 265813152
}

L’output JSON correttamente formattato è ottenuto mettendo in pipe alla fine della curl un modulo Python, json.tool, nel seguente modo:

curl --unix-socket /var/run/docker.sock "GET /images/docker.io/postgres:latest/json" | python -m json.tool

Appare chiaro ormai che tramite le remote API si può fare tutto ciò che si fa con la CLI. Facciamo ancora qualche esempio interessante.
Per visualizzare i processi attivi in un container che sta girando:

curl --unix-socket /var/run/docker.sock "GET /containers/6eab63c34478e87e7d99e7db28b6353e1c521350ca4c6016c9b0750d1477815b/top"

Altra cosa interessante: apriamo un tail sullo standard output e standard error del nostro container. Immaginiamo il potenziale di questo comando per monitare remotamente i container attivi su un cluster OpenShift ad esempio…

curl --unix-socket /var/run/docker.sock "GET /containers/6eab63c34478e87e7d99e7db28b6353e1c521350ca4c6016c9b0750d1477815b/logs?stderr=1&amp;stdout=1&amp;timestamps=1&amp;follow=1"

Si possono cercare immagini sul Registry predefinito. Con il seguente comando ad esempio si ricercano nel Docker Hub tutte le immagini che hanno nel nome o nella descrizione la stringa “openshift”:

curl --unix-socket /var/run/docker.sock "GET /images/search?term=openshift"

CONCLUSIONI

Abbiamo visto diversi aspetti di gestione dei container. Ovviamente non abbiamo fatto altro che scalfire a malapena la superficie. In futuro produrremo altri blogpost per approfondire alcuni dei temi trattati qui. Il tema è più che mai attuale e in questo momento è importante non rimanere indietro ed essere preparati sulle architetture cloud basate sui microservizi che si stanno man mano diffondendo sempre di più.

Nel frattempo vi ricordo che Docker e i Container sono uno dei temi centrali del corso DO280 – OpenShift Enterprise Administration. Se volete sapere di più sul corso (in tutta sincerità uno dei corsi Red Hat attualmente più interessanti del panorama del training ufficiale) visitate la nostra pagina di introduzione del corso: https://www.extraordy.com/do280.

 

arch-diagram
 

Info about author

Gianni Salinetti

Prenota subito il tuo corso ufficiale Red Hat

GUARDA I CORSI