Deploy di un Applicazione Spring Boot su una VM in Google Cloud usando Compute Engine, Cloud Sql e Load Balancing [Parte 1]

D

INTRODUZIONE

In questo articolo andremo a deployare su Google Cloud  Platform un architettura molto comune nel mondo Enterprise. L esempio sara’  composto da:

  • Servizio Spring boot che espone un API REST deployato  su una VM di Google Cloud
  • Il servizio utilizzerà’  un database  Mysql con soluzione AS Service offerto da Google Cloud Sql

La soluzione finale e’  illustrata nel seguente immagine

codice sorgente servizio

Il codice sorgente  dell applicazione che andremo a deployare e’  molto banale e lo trovatoe pubblicato al seguente REPO.

Partiamo dall’ application.properties del progetto che lo trovato compilato con le  settings per girare in locale l applicazione.

# loggin props
spring.application.name=hello-ws
logging.level.root = DEBUG
logging.level.web = DEBUG
logging.level.it.italiancoders = DEBUG
logging.level.sql = DEBUG
logging.level.org.hibernate.SQL=DEBUG
#logging.file.path=C:\\logs
#logging.file.name=${logging.file.path}\\app.log

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo_db
spring.datasource.username=root
spring.datasource.password=<PASSWORD>
spring.jpa.hibernate.ddl-auto=create
hello.message = Ciao Mondo

Sostanzialmente l applicazione utilizza un Database Mysql su cui salva il messaggio di hello world identificato dalla propieta’ hello.message .

Infine trovate il controller HelloController il quale espone  una API REST in GET e dal path /hello la quale ritorna banalmente il messaggio di hello world letto dal database.

Per  comodità’ abbiamo preparato anche l immagine docker che  andremo a deployare sulla nostra VM.

FROM openjdk:8-jdk-alpine
EXPOSE 8080
COPY target/demo.jar demo.jar
ENTRYPOINT ["java", "-jar", "demo.jar"]

Abbiamo pubblicato l immagine  del servizio su Docker Hub: dariofrongillo/demo-gcloud.

Se volete testare sulla vostra macchina tale applicazione basterà’  che vi installiate un database mysql con all’interno un database con il nome demo-db o tirando su il database con docker, ad es:

docker run -p 3306:3306 --name hb-mysql-exampl -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=demo-db -d mysql

 

deploy su google cloud

Andiamo adesso a configurare l ambiente su Google Cloud della nostra demo. Nei seguenti step do per scontato che:

  • Siete iscritti a Google Cloud
  • Conosciate un minimo i servizi di Compute Engine e di Cloud Sql di Google Cloud

 

creazione progetto

Creiamo innanzitutto un nuovo progetto Google Cloud  dal nome italiancoders-demo

I progetti Google Cloud costituiscono la base per la creazione, l’abilitazione e l’utilizzo di tutti i servizi Google Cloud, compresa la gestione delle API, l’abilitazione della fatturazione, l’aggiunta e la rimozione di collaboratori e la gestione delle autorizzazioni per le risorse di Google Cloud. Per maggiori info su cosa e’  un progetto in google cloud vi rimando alla seguente pagina.

creazione database

Inizieremo con la creazione del nostro database MySql su google cloud. Utilizzeremo Cloud Sql il  quale fornisce database relazionali come MySql, PostgreSQL, Sql Server in modalità’ As A Service ovvero come servizio gestito completamente da Google. In breve basterà’ configurare dalla console di google cloud il nostro Database e Cloud Sql automatizzerà’ backup, replica, failover per garantire HA e provisioning dello storage.

Per creare il nostro database MySql, cerchiamo nella console la voce Cloud Sql e  procediamo con la creazione del nostro Database MySql.

Modifichiamo anche la questione connettività’ impostandola a Privata.

Su questo punto conviene spendere  due parole;  vedo molto spesso configurare  la connettività’ pubblica aprendo al mondo il database anche quando non serve ( il CIDR 0.0.0.0/0 e’ da persone malvage 😛 ).   Nell  architettura disegnata  nella immagine ad inizio articolo  si evince che il database e’  utilizzato solo all’ interno della infrastruttura Cloud e  quindi di conseguenza  possiamo rendere disponibile il DB solo all’interno della rete privata VPC del nostro progetto di cui farà’ parte  anche la VM su cui girerà’ la nostra Spring Boot Application. Se avete  bisogno di connettervi dalla vostra macchina per magari far girare script o fare alcune verifiche   potete  impostare la connettività’ pubblica  ma senza autorizzare   nessuna rete esterna.  Per connettervi potrete usare il Cloud Sql Proxy che instaura per voi una connessione sicura verso il database. Leggi il seguente ARTICOLO per saperne di piu’.

Nelle altre configurazioni potrete anche impostare  il tipo di macchina, storage, backup recovery, HA che in questo articolo non specificheremo. A questo punto potremo verificare l istanza di My Sql creata.

La seguente immagine mostra l esito di creazione del nostro servizio My Sql il quale ha il seguente IP e Connection Name:

  • 10.19.192.3
  • italiancoders-demo:europe-west2:demo-db

 

creazione vm

A questo punto andiamo a creare la VM su cui deployeremo il nostro servizio Spring.

Colleghiamoci in SSH alla macchina e innanzitutto verifichiamo che essa sia in grado di collegarsi al’ istanza DB My Sql. Dalla console Attraverso il bottone Connect e’ possibile collegarsi in SSH dal browser.

Procediamo quindi a installare un client Mysql sulla VM e verifichiamo che riusciamo a connetterci al DB utilizzando l IP privato dell istanza.

sudo apt-get update
...
sudo apt-get install -y default-mysql-client
...

mysql -h 10.19.192.3 -u root -p
...
MySQL [(none)]> 
...

 

Come possiamo vedere  la VM riesce a connettersi al DB facendo parte entrambi della medesima VPC. A questo punto possiamo   procedere a deployare la nostra applicazione Spring sulla nostra macchina

INSTALLIAMO DOCKER

La mia VM monta un Debian 10; Per installare Docker potete fare riferimento a questo ARTICOLO.

lanciamo la nostra applicazione

Se lanciassimo l immagine dariofrongillo/demo-gcloud senza specificare nessuna opzione essa lancerebbe  la nostra applicazione con i puntamenti specificati nel application properties del jar ( il quale contiene i puntamenti di sviluppo). Spring offre una feature molto versatile per esternalizzare le application properties: Spring  a Runtime va a cercare se e’ presente nel path da dove viene lanciato il jar un file application.properties in una subfolder dal nome config, se e’ presente tale file verrà’ caricato. Andremo quindi a creare nella VM una folder /config su cui monteremo un volume docker  che punterà’ alla folder /config all’interno del container. Creiamo quindi la folder config e una seconda folder logs  che fungera’ da contenitore dei logs ( anche su questa folder monteremo un volume docker).

mkdir logs
mkdir config

Andiamo a preparare in locale l application properties che caricheremo nella folder config della VM

# loggin props
spring.application.name=hello-ws
logging.level.root = DEBUG
logging.level.web = DEBUG
logging.level.it.italiancoders = DEBUG
logging.level.sql = DEBUG
logging.level.org.hibernate.SQL=DEBUG
logging.file.path=/logs
logging.file.name=${logging.file.path}/app.log

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:google:mysql://italiancoders-demo:europe-west2:demo-db/demo_db
spring.datasource.username=root
spring.datasource.password=<PASSWORD>
spring.jpa.hibernate.ddl-auto=create
hello.message = Ciao Mondo

A questo punto possiamo caricare il file application.properties appena creato nella folder config della VM utilizzando la funzionalita’ Upload File della shell virtuale del nostro browser ( ricordiamo di fare una move per spostare  l application.properties dentro la folder config).

A questo punto possiamo lanciare la nostra applicazione

sudo docker run -p 8080:8080 -d -v  "$(pwd)/config":/config -v "$(pwd)/logs":/logs dariofrongillo/demo-gcloud

Possiamo vedere dai log contenuti nella folder /logs che  l applicazione e’   correttamente running.

creiamo il servizio http load balanced

Nella precedente sezione abbiamo lanciato la nostra applicazione Spring che girerà’ sulla porta 8080 della VM. Potremmo aprire il firewall della porta 8080 al mondo intero per permettere ai client esterni di interrogare tale API. Questa non e’ l opzione più corretta; Cosa accadrebbe se il carico della nostra applicazione e’ troppo alto e avessimo bisogno di avviare una seconda VM da utilizzare per bilanciare  il carico dell API ? La soluzione che utilizzeremo, come evidenziato nel immagine ad inizio articolo,  prevede di esporre su Internet il componente Load Balancer . Il Cloud Load Balancer di Google ci porta numerosi vantaggi. Può fornire un bilanciamento del carico semplice e scalabile per oltre un milione di query al secondo. Può anche scaricare l’overhead SSL dalle VM, instradare le query nella migliore regione per gli utenti in base sia alla posizione che alla disponibilità e supportare protocolli moderni come HTTP / 2 e QUIC.
Per questa esercitazione, si sfrutta un’altra caratteristica chiave: il proxy globale della connessione IP. Questa funzione fornisce un unico indirizzo IP usato dai client i quali possono quindi connettersi alle risorse ospitate su indirizzi IP privati ovunque in Google Cloud. Questa configurazione aiuta a proteggere le istanze dagli attacchi DDoS e dagli attacchi diretti. Inoltre, consente funzionalità come Google Cloud Armor per una sicurezza ancora maggiore.

Gli step che dobbiamo seguire sono:

  1. Creare una regola firewall per consentire l’accesso alla nostra VM da parte del load balancer
  2. Allocare un indirizzo IPv4 statico e globale per il load balancer
  3. Creazione di un instance group che raccoglierà’  le tue istanze.

 

firewall

Dal menu firewall andiamo a creare la regola allow-lb-and-healthcheck per consentire il traffico dal load balancer alla VM.

In breve abbiamo aperto per i CIDR del load balancer la porta 8080 a tutte le VM che usano il tag network allow-lb-and-healthcheck. Quindi dopo aver creato questa regola del Firewall occorre aggiornare la VM e applicare sulla istanza demo-vm il tag allow-lb-and-healthcheck.

creazione istance group

I servizi di load balancing di Google Cloud richiedono che i gruppi di istanze fungano da backend per il traffico. In questo tutorial useremo i gruppi gestiti manualmente ma e’ anche possibile utilizzare istance group gestiti in maniera automatica per sfruttare funzionalità quali il ridimensionamento automatico, la correzione automatica, la distribuzione regionale (multi-zona) e l’aggiornamento automatico. Ecco la nostra configurazione dell Istance Group

In breve abbiamo configurato :

  • un gruppo dal nome hello-vm-group composto da una singola VM: la nostra demo-vm. Se un domani avessimo bisogno di scalare potremmo inserire nel gruppo altre VM per bilanciare il carico.
  • una port name mapping: endpoint-port la quale rappresenta la porta 8080 sulla quale il load balancing dovra’ inoltrare il traffico

 

load balancing: configurazione backend e health check

Andiamo quindi a creare il servizio backend del nostro load balancer che riferirà’ al gruppo di VM identificato dall istance group appena creato.

In breve abbiamo configurato

  • Named Port che il load balancing utilizza per indirizzare il traffico verso il gruppo
  • health check, che esegue il polling delle istanze per vedere se sono integre. Il load balancing del carico invia il traffico solo a istanze integre. Per semplicità’ abbiamo usato di nuovo l api /hello. Per completezza occorre usare l endpoint esposto da Spring Actuator per monitorare lo stato di salute dell’applicazione.
  • Servizio di backend collegato all istance group creato nello step precedente

 

load balancing: host e regole di path

Nella configurazione del servizio di Load Balancing ci e’ permesso di definire le regole che sulla base delle URL delle richieste verranno utilizzate  per dirottare le richieste all istance group di riferimento. In questo esercizio, poiché non si utilizza l’inoltro basato sul contenuto, la mappa URL contiene solo la mappatura predefinita.

load balancing: configurazione frontend

Il frontend del Google Load Balancing sara’ l interfaccia esposta su  internet che i vostri client interrogheranno per accedere alle vostre API.

Fate attenzione sulla selezione della tipologia dell IP; se selezionate l opzione Ephemeral significa che l IP potrebbe cambiare con il tempo. Nel mio esempio ho riservato un IP statico. Nello screen abbiamo configurato il frontend in attesa sulla porta 80.

riepilogo configurazione

Abbiamo quindi configurato il load balancer per esporre ai client l interfaccia all IP 34.102.186.80 e porta 80. Tutte le richieste verranno redirette al backend hello-backend-service che e’ collegato al gruppo di istanze VM hello-vm-group che in questo momento riferisce ad una sola VM: hello vm. A questo punto possiamo testare  dal nostro browser accedendo all URL http://34.102.186.80/hello il quale mostrerà’ la risposta attesa: Ciao Mondo.

 

A proposito di me

Dario Frongillo

Uno degli admin di Italiancoders e dell iniziativa devtalks.
Dario Frongillo è un software engineer e architect, specializzato in Web API, Middleware e Backend in ambito cloud native. Attualmente lavora presso NTT DATA, realtà di consulenza internazionale.
E' membro e contributor in diverse community italiane per developers; Nel 2017 fonda italiancoders.it, una community di blogger italiani che divulga articoli, video e contenuti per developers.

Gli articoli più letti

Articoli recenti

Commenti recenti