in Informatica, Tutorial, Tutorial Docker

Progettare e distribuire applicazioni su Raspberry Pi con Docker – Installazione ed utilizzo

In un precedente articolo avevo parlato del problema della gestione delle dipendenze nei progetti Python3. La soluzione che avevo proposto era quella di creare delle istanze isolate di interpreti Python su una stessa piattaforma utilizzando virtualenv. In quel caso, il problema principale era dato dalla collisione fra le dipendenze richieste da applicazioni diverse tra loro, ma era anche quello di potere avere un ambiente isolato per ogni app. Oggi si parla di una soluzione diversa e più generale, utilizzando Docker e i suoi container.

Introduzione

Quando si procede nello sviluppare un’applicazione, anche complessa, si vuole avere la possibilità di potere distribuirla in maniera omogenea su multiple piattaforme, ma spesso la fase di sviluppo avviene su una piattaforma specifica con dipendenze altrettanto specifiche. 

Una soluzione a questo problema è data da Docker, una piattaforma per la gestione di strutture software chiamate containers. La maniera in cui Docker funziona è simile all’utilizzo delle macchine virtuali, tramite entrambi si ottiene l’isolamento di ambienti in cui eseguire applicazioni ma la differenza sta nel come: utilizzando VM, ogni macchina virtuale avrà un’intero sistema operativo ad essa dedicato, su cui far eseguire la propria applicazione con le librerie ad essa necessarie, mentre, utilizzando i container Docker, si condividerà un unico Kernel ed i vari container saranno lanciati come processi indipendenti.

Schematizzazione di tre tipi diversi di approccio, a sinistra quello con Macchine Virtuali, al centro Docker, a destra virtualenv.

Questo approccio risulta essere molto leggero (non dovendo utilizzare un’intero sistema operativo ogni volta) e di facile condivisione, grazie anche agli strumenti forniti da Docker stesso, che lo rendono di semplice utilizzo. Docker esegue nativamente su piattaforma Linux, ed è un’ottima soluzione alla problematica di organizzare un’ambiente per una particolare applicazione su Raspberry Pi, senza doversi preoccupare troppo delle dipendenze da librerie, runtime, linguaggi vari.

Installazione e primi passi

La fase di installazione descritta qui di seguito vale per qualsiasi piattaforma Linux, anche se esistono altre procedure più dettagliate: si è scelto di optare per questa data la semplicità e velocità di utilizzo. D’ora in poi verrà data per scontata un po’ di dimestichezza con Raspberry Pi e lo strumento di linea di comando, per una veloce infarinatura è possibile fare riferimento a questo nostro tutorial sul setup della scheda.

Per installare Docker Community Edition su Linux è possibile utilizzare lo script fornito al seguente indirizzo. Una volta avviato il proprio Raspberry, ed aperta una shell via ssh,  si potrà procedere con:

curl -fsSL https://get.docker.com -o get-docker.sh
chmod +x get-docker.sh
./get-docker.sh

Quando il processo d’installazione sarà terminato, bisognerà aggiungere il proprio utente al gruppo docker per potere far sì di avere i privilegi per utilizzarne il motore, quindi effettuare un riavvio (dove nome_utente è il vostro nome utente, su Raspberry quello predefinito è pi):

sudo usermod -a -G docker nome_utente

A questo punto è utile iniziare ad avere un approccio pratico e, con la scusa, testare che il tutto si sia concluso con successo. Come accennato nell’introduzione, tramite Docker è possibile organizzare un’applicazione assieme alle sue dipendenze all’interno di un container. Questi container possono poi essere condivisi tramite dockerhub, un sito simile a github, sotto forma di immagini. Un’immagine può poi essere scaricata dall’hub utilizzando il comando docker pull. Per testare l’installazione, si può scaricare l’immagine hello-world resa disponibile dalla community Docker proprio per questo scopo, tramite:

docker pull hello-world

Al termine del download, sarà possibile visualizzare una lista delle immagini al momento disponibili in locale eseguendo:

docker image ls

Un container può essere eseguito a partire da un’immagine scaricata tramite il comando run, specificando il nome dell’immagine scaricata. Per testare l’immagine scaricata poco fa, si può eseguire da terminale:

docker run hello-world

Esempio di output su Raspberry Pi3 B+ dopo l’esecuzione dei comandi descritti 

Per visualizzare tutti contenitori attivi, si può utilizzare il seguente comando:

docker ps -a

Sarà possibile vedere che il contenitore lanciato risulta essere stoppato; inoltre, precedentemente non abbiamo specificato un nome da dare al contenitore, ne è stato generato uno automaticamente. Qui di seguito i comandi per stoppare e rimuovere i contenitori:

docker stop <nome-container>
docker rm <nome-container>

Rimozione di un container

Un’applicazione interattiva

Proviamo ora ad applicare quanto visto fino ad adesso: nel mio scorso articolo ho introdotto la libreria paho.mqtt per il linguaggio Go. Alla fine della discussione sulla libreria, ho proposto un semplice programma con un client MQTT che sottoscriveva al topic test, stampando il topic ed il payload dei messaggi ricevuti. 

Ho creato un’immagine Docker che contiene quell’esempio e che, quando avviata, manda in esecuzione questa semplice applicazione; il tutto è reperibile effettuando un pull tramite:

docker pull abathargh/mqtt-sub-test

Dopodiché, stando attenti ad avere mosquitto in esecuzione sul Raspberry, si può avviare il container all’interno del quale è presente l’applicazione tramite:

docker run --rm --name sub-test --net=host -p 1883:1883 abathargh/mqtt-sub-test

Dove i vari flag hanno i seguenti effetti:

  • –rm fa sì che il container venga rimosso automaticamente una volta stoppato;
  • –name permette di definire un nome per il container, in questo caso sub-test;
  • –net=host rimuove l’isolamento di rete del contenitore e gli da visibilità rispetto al sistema che lo hosta.  Questa soluzione è utilizzata per semplificare l’esempio: più in là verranno discusse modalità migliori per ottenere l’interconnessione tra container;
  • -p definisce un regola di inoltro dei dati provenienti da una porta esterna al container ad una interna ad esso, in questo caso la 1883 è la porta predefinita del protocollo MQTT.

Provando a mandare dei messaggi MQTT al topic test il client nel container li riceverà, stampandoli.

Per questo articolo è tutto, nel caso in cui ci fossero dubbi, curiosità o necessità di chiarimenti, non esitate a lasciare un commento nella sezione sottostante!

Scrivi un commento

Commento