in Informatica, Tutorial, Tutorial Docker

Progettare e distribuire applicazioni su Raspberry Pi con Docker – I Dockerfile

Nello scorso articolo abbiamo visto come installare Docker su Raspberry Pi o su qualsiasi  piattaforma Linux. Oggi parleremo di come creare dei container partendo da delle immagini docker, usando i Dockerfile.

Quanto contenuto in questo articolo è applicabile su qualsiasi piattaforma, non solo su Raspberry. Ad esempio, ho scritto un breve articolo poche settimane fa su come installare Docker Desktop su Windows Home 10.

Le immagini e l’hub Docker

Un Dockerfile contiene un insieme di istruzioni per la costruzione di un’immagine da usare per istanziare un contenitore. 

All’interno di questo file vengono utilizzate altre immagini e dei particolari comandi per costruire immagini composite, ambienti per l’esecuzione delle nostre applicazioni. Un’immagine può offrire gli strumenti di base necessari all’esecuzione dei nostri programmi, ma può anche essere modificata per aggiungere dettagli specifici.

Le immagini docker vengono condivise su Docker Hub, un sito di hosting simile a github utilizzato per offrire e trovare immagini, sia da enti e organizzazioni, che da privati. Questo sarà il punto di partenza per potere costruire nostre immagini a partire da altre presenti online.

Un primo esempio

Nel primo articolo avevo parlato di come Docker risolve il problema del deploy di un’applicazione e delle sue dipendenze; un contenitore può essere eseguito su macchine diverse e contiene al suo interno tutto ciò che è necessario all’applicazione per funzionare, senza che la piattaforma su cui gira Docker faccia una differenza. Questo aspetto agnostico  dal sistema operativo è riflesso anche nella sintassi dei Dockerfile, che raggruppa operazioni comuni eseguite sul sistema operativo con parole chiave non legate ad una particolare architettura.

Pensiamo al seguente scenario: abbiamo necessità di creare un’applicazione per esporre dei servizi, ad esempio utilizzando Flask:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
	return "Hello world!"

Questo è un semplicissimo esempio, ma quanto spiegato vale anche per applicazioni ben più complesse. Ora presumiamo di volere creare un ambiente che raccolga tutte le dipendenze necessarie per lanciare il programma, mantenendo portabilità e isolamento.

Il Dockerfile

Per potere ottenere questo risultato useremo un Dockerfile per creare un’immagine Docker, che è una specie di modello da cui Docker può partire per creare un contenitore.

Creiamo una cartella e salviamo al suo interno il programma python sopra introdotto, chiamandolo app.py. Creiamo anche un file contenente le dipendenze della nostra applicazione, chiamandolo requirements.txt. Al suo interno inseriamo flask e gunicorn, il server HTTP che useremo.

A questo punto, sempre nella stessa cartella, creiamo un file col nome Dockerfile e inseriamo al suo interno le seguenti istruzioni:

FROM python:3.8-slim-buster

WORKDIR /app
COPY . .
RUN pip3 install -r requirements.txt
EXPOSE 8080

CMD ["gunicorn", "-b", "0.0.0.0:8080", "app:app"]

Queste istruzioni descrivono quanto segue:

  • FROM è utilizzato per dichiarare un’immagine base da utilizzare per costruire la nostra, in questo caso usiamo un’immagine per python 3.8 basata su una versione molto leggera di Debian Buster;
  • WORKDIR serve a specificare la directory dove eseguire i comandi, che verrà creata nel caso non fosse già esistente;
  • COPY . . effettua una copia di ogni file della cartella sul nostro computer, trasferendo ogni documento anche all’interno del container;
  • RUN esegue un comando e costruisce un’immagine intermedia contenente quanto ottenuto come output del comando, dalla prossima riga l’immagine utilizzata sarà quella originale modificata dal RUN;
  • EXPOSE annota che il contenitore sarà in ascolto sulla porta 8080 TCP;
  • CMD esgeue il comando, da esprimere con la notazione di array json, come punto d’entrata del container.

Creazione dell’immagine ed esecuzione

Una volta scritto e salvato il Dockerfile, costruiamo l’immagine usando il comando:

docker build -t flask-example:test .

che creerà un’immagine chiamata flask-example con il tag test. Il tag è utile per creare diverse versioni di una stessa immagine. Nelle immagini sottostanti si può notare come i comandi vengano eseguiti e come l’immagine appaia tra quelle disponibili dopo la fase di build.

Dopo aver creato l’immagine ed avere visto che è effettivamente presente tra quelle a disposizione, procediamo a creare un container per eseguire la nostra applicazione:

docker run --name flask-example -p 8080:8080 -d flask-example:test

Notiamo come il flag -p specifica che vogliamo che il traffico sulla porta 8080 dal nostro computer sia inoltrato sulla porta 8080 in ingresso al container. Il flag -d  specifica che vogliamo il container in modalità detached, slegata dal nostro terminale.

Aprendo ora un qualsiasi browser all’indirizzo localhost:8080 potremo osservare quanto atteso.

Abbiamo quindi visto un metodo generale per la creazione di immagini tramite Dockerfile. Un’immagine così generata è utilizzabile su qualsiasi piattaforma su cui sia installato Docker.

La comodità di utilizzare e costruire immagini per le proprie applicazioni sta anche nella possibilità di condividerle sull’Hub Docker, dove chiunque può scaricarle ed utilizzarle.

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