Hello Java from Docker

Partendo dal banale Hello World vedremo come integrare all’interno di un container Docker il download di un nostro progetto d’esempio da GitHub, compilarlo ed avviarlo.

Senza la presunzione di riassumerne tutto il funzionamento in poche righe, possiamo spendere due parole sul suo funzionamento. Docker permette la definizione, composizione e in qualche modo anche la gestione dei Container. Questa parola è molto usata nell’informatica e in questo caso possiamo associare a Container il significato di versione light di un sistema operativo dove poter far girare i nostri servizi, essendo sicuro che questo non vada in conflitto con altre cose. Il parallelo che si usa per capire il funzionamento dei Container è quello con le Virtual Machine, riepilogato nella seguente immagine

© Docker

© Docker

Quando vogliamo mettere le nostre applicazioni su una Virtual Machine questa ha un suo sistema operativo dedicato, quindi dovendo gestire diverse applicazioni su VM simili c’è uno spreco di risorse gestite. I Container sono un’astrazione che permette di gestire i processi isolati ma che condivisono il kernel del sistema operativo. Per questo motivo i Container sono più veloci e snelli rispetto alle classiche VM. Docker, sfruttando il concetto di Container, ci permette di definirne uno in un modo molto semplice e che può essere estremamente utile nelle fasi di sviluppo, test e anche produzione. L’architettura di Docker può essere rappresentata nel seguente diagramma dove abbiamo il Docker client che rappresenta il tool che utilizziamo da riga di comando. Questo si collega al demone Docker che a sua volta gestisce i Docker container.

Prima di tutto dobbiamo avere Docker installato sul nostro sistema, se così non fosse vi rimando alla guida ufficiale sul sito di Docker che vi spiega come installarlo nei diversi sistemi operativi. Per verificare che l’installazione sia stata effettuata correttamente possiamo lanciare il seguente comando

 

In questo simpatico esempio di Hello World possiamo trovare già le informazioni di cosa è successo dietro alle quinte. Il client Docker ha comunicato al demone di far partire l’immagine hello-world. Localmente non avevamo questa immagine e quindi il demone si è collegato a Docker Hub, ha scaricato l’immagine localmente e ha creato un nuovo container a partire da questa immagine facendolo partire. Il container nella sua definizione interna ha un eseguibile che crea l’output appena riportato. Se volessimo creare anche noi una esempio simile a quello riportato il file possiamo creare la seguente immagine

 

 

Con questi tre comandi all’interno del file Dockerfile, che è il file principale di configurazione per un’immagine Docker, stiamo dicendo le seguenti cose

1) Parti dall’immagine di ubuntu, ultima versione

2) Copia il file hello.txt nella root dell’immagine

3) Esegui il comando cat hello.txt

Passiamo quindi ad effettuare il build per verificarne il funzionamento.

 

Ogni comando riportato nel file di build crea un container intermedio dove viene eseguito il comando corrente. L’immagine finale verrà salvata in locale, come è possibile vedere dall’elenco delle immagini

 

Hello World Java

Passiamo ora ad un Hello World più vicino ai nostri interessi. Come immagine base in questo caso utilizzeremo quella ufficiale java, che ovviamente ha al suo interno già installato Java. Il Dockerfile sarà quindi il seguente

 

In questo caso possiamo vedere l’output del nostro Hello World semplicemente lanciando la build

 

Ovviamente potevamo partire da un immagine base e installare Java da soli, ma avendo a disposizione delle immagini ufficiali rilasciate dai diversi produttori software talvolta può essere conveniente sfruttarle senza creare Dockerfile lunghi.

 

Hello World Maven

Dopo aver provato l’ebbrezza di compilare un Hello World dentro il nostro container dobbiamo provare a fare la build di un progetto Maven e lanciarlo. Prima di tutto dobbiamo definire un semplice progetto che ci permette di lanciare un webserver. L’unica classe di questo progetto è quella che trovate riportata di seguito

 

Non soffermandosi troppo sull’utilità di questa classe, vediamo che lanciandola possiamo avere un inutile webserver sulla pagina 8080. Questa classe, insieme al progetto Maven che crea il relativo jar, è disponibile su github al repository https://github.com/fpaparoni/ExampleWebserver. Ora definiremo un Dockerfile che scaricherà il progetto da github, lo compilerà e lancerà

 

 

L’immagine di partenza che utilizziamo è quella ufficiale rilasciata da Maven, che ovviamente ha installato Maven e Java. Successivamente con il comando EXPOSE mettiamo in ascolto la porta 8080 e scarichiamo il progetto dal repository git. Passiamo quindi alla directory appena creata con il comando WORKDIR e creiamo il JAR con il classico comando di Maven. Lanciamo quindi l’eseguibile Java dopo essere entrati nella directory target. Passiamo quindi al build della nostra nuova immagine

 

 

e al successivo run del nuovo container dove con il parametro -p8080:8080 stiamo mappando la porta 8080 del container con la porta 8080 del nostro sistema operativo

 

 

Collegandoci all’indirizzo localhost:8080 troveremo in ascolto il nostro webserver d’esempio lanciato dal container Docker. A questo punto dell’articolo vi sarebbe dovuto già venire in mente la domanda “Si ma ho lanciato questi container, ma poi come faccio a vederli? come faccio a fermarli??”. Con il comando docker ps -a possiamo vedere tutti i container presenti sul nostro sistema e in seguito possiamo stopparli con il comando docker stop <CONTAINER-ID> o addirittura cancellarli con il comando docker rm <CONTAINER-ID>.

 

Docker Compose e Spring Boot

Passiamo ora ad un esempio che permette di vedere qualcosa di più complesso del semplice hello world. L’applicazione che vogliamo far girare un’applicazione è realizzata con Spring Boot, un esempio di crud che trovate all’indirizzo https://github.com/fpaparoni/spring-boot-crud, che utilizza un database MySQL per memorizzare le informazioni. Abbiamo quindi bisogno di avviare diversi processi che dialogano tra di loro, quindi possiamo utilizzare Docker Compose, tool che serve per definire e lanciare applicazioni basate su molteplici container Docker. L’installazione di questo tool è semplicemente il download del binario per la vostra piattaforma, ma vi rimando comunque alla documentazione ufficiale.

Prima di addentrarci nella configurazione del file relativo a Docker Compose, dobbiamo definire le immagini relative al database e alla nostra applicazione. Partiamo con il database MySQL, dove rispetto all’immagine ufficiale andremo ad aggiungere uno script che verrà eseguito all’avvio dove verrà creato il database e la tabella che ci interessa

e lanciamo la build

 

Passiamo quindi all’applicazione Spring Boot. In questo caso il file di build scaricherà il progetto da git, lo compilerà, copierà un file di properties custom dove abbiamo inserito l’host MySQL a cui collegarsi ed infine avvierà l’applicazione in modalità debug, così potremo anche collegarci dal nostro IDE.

 

 

e anche per questa lanciamo la corrispondente build

 

 

Ora che abbiamo definito queste due immagini passiamo alla definizione del file docker-compose.yml

 

 

In questo file definiamo una lista di servizi da lanciare, il primo dei quali è MySQL con l’immagine custom-mysql che abbiamo definito precedentemente. Per questa immagine specifichiamo la porta da esporre e un healthcheck che viene utilizzato per capire se il database è raggiungibile e utilizzabile. C’è poi la definizione del servizio con l’applicazione crud. In questo caso le porte esposte sono due, una per l’applicazione e l’altra per raggiungerla con il debug remoto. Definiamo inoltre un link tra questa immagine e il servizio custom-mysql, in questo modo il servizio spring-boot-crud potrà accedere al servizio database. Facciamo quindi partire Docker Compose lanciando il seguente comando dalla directory dove è presente il file che riporta la precedente composizione di servizi

 

 

Come è possibile vedere dai log, partirà prima MySQL e successivamente l’applicazione in quando abbiamo messo come condizione che il servizio MySQL sia raggiungibile ed utilizzabile. Per raggiungere l’applicazione basta andare sulla porta 8080 dal nostro browser, mentre invece se vogliamo agganciare il debug remoto basta configurarlo come riportato ad esempio nella seguente immagine dove all’interno di Eclipse viene configurato un server remoto dove collegarsi

 

Conclusioni

Potremmo continuare con molti altri esempi, visto che ovviamente gli scenari per utilizzare Docker sono tantissimi. Di sicuro per approfondire l’argomento è interessante vedere sia l’utilizzo di Docker da plugin Maven (ne esistono diversi) e Docker Swarm che permette di gestire un cluster di macchine virtuali. Tutti gli esempi sono scaricabili dal progetto Github riportato di seguito

 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *