1. Panoramica
Questo lab illustra caratteristiche e funzionalità progettate per semplificare il flusso di lavoro di sviluppo per i tecnici del software incaricati di sviluppare applicazioni Java in un ambiente containerizzato. Lo sviluppo tipico dei container richiede che l'utente comprenda i dettagli dei container e del processo di compilazione dei container. Inoltre, gli sviluppatori in genere devono interrompere il flusso, uscendo dal loro IDE per testare ed eseguire il debug delle loro applicazioni in ambienti remoti. Con gli strumenti e le tecnologie menzionati in questo tutorial, gli sviluppatori possono lavorare in modo efficace con le applicazioni containerizzate senza uscire dall'IDE.
Cosa imparerai a fare
In questo lab imparerai i metodi per lo sviluppo con container in Google Cloud, tra cui:
- Sviluppo di InnerLoop con Cloud Workstations
- Creazione di una nuova applicazione iniziale Java
- Panoramica del processo di sviluppo
- Sviluppo di un servizio REST CRUD semplice
- Debug dell'applicazione su cluster GKE
- Connessione dell'applicazione al database Cloud SQL
2. Configurazione e requisiti
Configurazione dell'ambiente autogestito
- Accedi alla console Google Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai ancora un account Gmail o Google Workspace, devi crearne uno.
- Il Nome progetto è il nome visualizzato dei partecipanti del progetto. Si tratta di una stringa di caratteri non utilizzata dalle API di Google. Puoi aggiornarla in qualsiasi momento.
- L'ID progetto è univoco in tutti i progetti Google Cloud ed è immutabile (non può essere modificato dopo essere stato impostato). La console Cloud genera automaticamente una stringa univoca. di solito non ti importa cosa sia. Nella maggior parte dei codelab, dovrai fare riferimento all'ID progetto (in genere è identificato come
PROJECT_ID
). Se l'ID generato non ti soddisfa, puoi generarne un altro casuale. In alternativa, puoi provarne una personalizzata per verificare se è disponibile. Non può essere modificato dopo questo passaggio e rimarrà per tutta la durata del progetto. - Per informazione, c'è un terzo valore, un numero di progetto, utilizzato da alcune API. Scopri di più su tutti e tre questi valori nella documentazione.
- Successivamente, dovrai abilitare la fatturazione nella console Cloud per utilizzare risorse/API Cloud. Eseguire questo codelab non dovrebbe costare molto. Per arrestare le risorse in modo da non incorrere in fatturazione oltre questo tutorial, puoi eliminare le risorse che hai creato o eliminare l'intero progetto. I nuovi utenti di Google Cloud sono idonei al programma prova senza costi di 300$.
Avvia editor Cloudshell
Questo lab è stato progettato e testato per l'utilizzo con l'editor di Google Cloud Shell. Per accedere all'editor,
- accedi al tuo progetto Google all'indirizzo https://console.cloud.google.com.
- Nell'angolo in alto a destra, fai clic sull'icona dell'editor di Cloud Shell
- Si aprirà un nuovo riquadro nella parte inferiore della finestra
- Fai clic sul pulsante Apri editor
- L'editor si apre con un Explorer a destra e l'editor nell'area centrale
- Nella parte inferiore dello schermo dovrebbe essere disponibile anche un riquadro del terminale
- Se il terminale NON è aperto, utilizza la combinazione di tasti "Ctrl+" per aprire una nuova finestra del terminale
Configura gcloud
In Cloud Shell, imposta l'ID progetto e la regione in cui vuoi eseguire il deployment dell'applicazione. Salvale come variabili PROJECT_ID
e REGION
.
export REGION=us-central1
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
clona il codice sorgente
Il codice sorgente di questo lab si trova nel container-developer-workshop in GoogleCloudPlatform su GitHub. Clonalo con il comando seguente, quindi passa alla directory.
git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git
cd container-developer-workshop/labs/spring-boot
Esegui il provisioning dell'infrastruttura utilizzata in questo lab
In questo lab eseguirai il deployment del codice su GKE e accedi ai dati archiviati in un database Cloud SQL. Lo script di configurazione riportato di seguito prepara l'infrastruttura per te. Il processo di provisioning richiederà più di 25 minuti. Attendi il completamento dello script prima di passare alla sezione successiva.
./setup_with_cw.sh &
Cluster Cloud Workstations
Apri Cloud Workstations nella console Cloud. Attendi che il cluster si trovi nello stato READY
.
Crea configurazione workstation
Se la sessione di Cloud Shell è stata disconnessa, fai clic su "Riconnetti" quindi esegui il comando gcloud cli per impostare l'ID progetto. Sostituisci l'ID progetto di esempio riportato di seguito con il tuo ID progetto qwiklabs prima di eseguire il comando.
gcloud config set project qwiklabs-gcp-project-id
Esegui lo script seguente nel terminale per creare la configurazione di Cloud Workstations.
cd ~/container-developer-workshop/labs/spring-boot
./workstation_config_setup.sh
Verifica i risultati nella sezione Configurazioni. Sono necessari 2 minuti per passare allo stato PRONTO.
Apri Cloud Workstations nella console e crea una nuova istanza.
Cambia il nome in my-workstation
e seleziona la configurazione esistente: codeoss-java
.
Verifica i risultati nella sezione Workstations.
Avvia workstation
Avvia e avvia la workstation.
Consenti i cookie di terze parti facendo clic sull'icona nella barra degli indirizzi.
Fai clic su "Sito non funzionante?".
Fai clic su "Accetta i cookie".
Una volta avviata la workstation, verrà visualizzato l'IDE Code OSS. Fai clic su "Segna come completato". nella pagina Getting Started (Per iniziare) l'IDE
3. Creazione di una nuova applicazione iniziale Java
In questa sezione creerai da zero una nuova applicazione Java Spring Boot utilizzando un'applicazione di esempio fornita da spring.io. Apri un nuovo terminale.
clona l'applicazione di esempio
- Crea un'applicazione iniziale
curl https://start.spring.io/starter.zip -d dependencies=web -d type=maven-project -d javaVersion=17 -d packageName=com.example.springboot -o sample-app.zip
Fai clic sul pulsante Consenti se viene visualizzato questo messaggio per copiare e incollare i dati nella workstation.
- Decomprimi l'applicazione
unzip sample-app.zip -d sample-app
- Apri "sample-app" cartella
cd sample-app && code-oss-cloud-workstations -r --folder-uri="$PWD"
Aggiungi spring-boot-devtools e Fiocco
Per abilitare i DevTools Spring Boot, individua e apri il file pom.xml dall'Explorer nel tuo editor. Incolla il seguente codice dopo la riga descrittiva <description>Demo project for Spring Boot</description>
- Aggiungi spring-boot-devtools in pom.xml
Apri pom.xml
nella directory principale del progetto. Aggiungi la seguente configurazione dopo la voce Description
.
pom.xml
<!-- Spring profiles-->
<profiles>
<profile>
<id>sync</id>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
- Attiva jib-maven-plugin in pom.xml
Jib è uno strumento di containerizzazione Java open source di Google che consente agli sviluppatori Java di creare container utilizzando gli strumenti Java che conoscono. Jib è uno strumento per la creazione di immagini container semplice e veloce che gestisce tutti i passaggi per pacchettizzare la tua applicazione in un'immagine container. Non richiede la scrittura di un Dockerfile o l'installazione di un Dockerfile ed è integrato direttamente in Maven e Gradle.
Scorri verso il basso nel file pom.xml
e aggiorna la sezione Build
per includere il plug-in Jib. Una volta completata, la sezione relativa alla build dovrebbe corrispondere alla seguente.
pom.xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Jib Plugin-->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<!-- Maven Resources Plugin-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
Genera manifest
Skaffold fornisce strumenti integrati per semplificare lo sviluppo dei container. In questo passaggio inizializzarai Skaffold, che creerà automaticamente i file YAML Kubernetes di base. Il processo tenta di identificare le directory con definizioni di immagini container, come un Dockerfile, quindi crea un manifest di deployment e di servizio per ciascuna.
Esegui il comando seguente nel terminale per iniziare il processo.
- Esegui questo comando nel terminale
skaffold init --generate-manifests
- Quando richiesto:
- Utilizza le frecce per spostare il cursore su
Jib Maven Plugin
- Premi la barra spaziatrice per selezionare l'opzione.
- Premi Invio per continuare
- Inserisci 8080 per la porta.
- Inserisci y per salvare la configurazione
Due file vengono aggiunti allo spazio di lavoro skaffold.yaml
e deployment.yaml
Output Skaffold:
Aggiorna il nome dell'app
I valori predefiniti inclusi nella configurazione al momento non corrispondono al nome dell'applicazione. Aggiorna i file in modo che facciano riferimento al nome dell'applicazione anziché ai valori predefiniti.
- Modifica le voci nella configurazione Skaffold
- Apri
skaffold.yaml
- Seleziona il nome dell'immagine attualmente impostato su
pom-xml-image
- Fai clic con il tasto destro del mouse e scegli Modifica tutte le occorrenze
- Digita il nuovo nome come
demo-app
.
- Modifica le voci nella configurazione di Kubernetes
- Apri file
deployment.yaml
- Seleziona il nome dell'immagine attualmente impostato su
pom-xml-image
- Fai clic con il tasto destro del mouse e scegli Modifica tutte le occorrenze
- Digita il nuovo nome come
demo-app
.
Attiva modalità di sincronizzazione automatica
Per facilitare un'esperienza di ricarica rapida ottimizzata, utilizzerai la funzionalità di sincronizzazione fornita da Jib. In questo passaggio configurerai Skaffold in modo che utilizzi questa funzionalità nel processo di creazione.
Tieni presente che la casella di controllo il profilo che stai configurando nella configurazione Skaffold utilizza la "sincronizzazione" Spring Profilo che hai configurato nel passaggio precedente, in cui hai abilitato il supporto per spring-dev-tools.
- Aggiorna configurazione Skaffold
Nel file skaffold.yaml
, sostituisci l'intera sezione di compilazione del file con la seguente specifica. Non alterare altre sezioni del file.
skaffold.yaml
build:
artifacts:
- image: demo-app
jib:
project: com.example:demo
type: maven
args:
- --no-transfer-progress
- -Psync
fromImage: gcr.io/distroless/java17-debian11:debug
sync:
auto: true
Aggiungi una route predefinita
Crea un file denominato HelloController.java
in /src/main/java/com/example/springboot/
cartella.
Incolla i contenuti seguenti nel file per creare una route http predefinita.
HelloController.java
package com.example.springboot;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Value;
@RestController
public class HelloController {
@Value("${target:local}")
String target;
@GetMapping("/")
public String hello()
{
return String.format("Hello from your %s environment!", target);
}
}
4. Panoramica del processo di sviluppo
In questa sezione analizzerai alcuni passaggi utilizzando il plug-in Cloud Code per apprendere i processi di base e convalidare la configurazione della tua applicazione iniziale.
Cloud Code si integra con Skaffold per semplificare il processo di sviluppo. Quando esegui il deployment su GKE nei passaggi seguenti, Cloud Code e Skaffold creano automaticamente l'immagine container, ne eseguono il push a un Container Registry e quindi il deployment dell'applicazione su GKE. Ciò avviene dietro le quinte, astraendo i dettagli dal flusso degli sviluppatori. Cloud Code migliora inoltre il processo di sviluppo fornendo funzionalità tradizionali di debug e sincronizzazione a caldo allo sviluppo basato su container.
Accedi a Google Cloud
Fai clic sull'icona di Cloud Code e seleziona "Accedi a Google Cloud":
Fai clic su "Procedi per accedere".
Controlla l'output nel terminale e apri il link:
Accedi con le tue credenziali Qwiklabs per studenti.
Seleziona "Consenti":
Copia il codice di verifica e torna alla scheda Workstation.
Incolla il codice di verifica e premi Invio.
Aggiungi cluster Kubernetes
- Aggiungi un cluster
- Seleziona Google Kubernetes Engine:
- Seleziona progetto.
- Seleziona "quote-cluster" creato nella configurazione iniziale.
Imposta l'ID progetto corrente utilizzando l'interfaccia a riga di comando gcloud
Copia l'ID progetto per questo lab dalla pagina qwiklabs.
Esegui il comando gcloud cli per impostare l'ID progetto. Sostituisci l'ID progetto di esempio prima di eseguire il comando.
gcloud config set project qwiklabs-gcp-project-id
Esempio di output:
Debug su Kubernetes
- Nel riquadro a sinistra in basso, seleziona Cloud Code.
- Nel riquadro visualizzato in SESSIONI DI SVILUPPO, seleziona Debug su Kubernetes.
Scorri verso il basso se l'opzione non è visibile.
- Seleziona "Sì". per utilizzare il contesto corrente.
- Seleziona "quote-cluster" creato durante la configurazione iniziale.
- Seleziona Container Repository.
- Seleziona la scheda Output nel riquadro inferiore per visualizzare l'avanzamento e le notifiche
- Seleziona "Kubernetes: Esegui/Debug - Dettagliato" nel menu a discesa del canale a destra per visualizzare ulteriori dettagli e i log trasmessi in live streaming dai container
Attendi che venga eseguito il deployment dell'applicazione.
- Esamina l'applicazione di cui è stato eseguito il deployment su GKE nella console Cloud.
- Torna alla visualizzazione semplificata selezionando "Kubernetes: Run/Debug" dal menu a discesa della scheda OUTPUT.
- Una volta completati la build e i test, la scheda Output riporta il seguente messaggio:
Resource deployment/demo-app status completed successfully
e un URL: "Forwarded URL from service demo-app: http://localhost:8080" - Nel terminale Cloud Code, passa il mouse sopra l'URL nell'output (http://localhost:8080), quindi nella descrizione comando visualizzata seleziona Segui link.
La nuova scheda verrà aperta e vedrai l'output di seguito:
Utilizza i punti di interruzione
- Apri l'applicazione
HelloController.java
all'indirizzo/src/main/java/com/example/springboot/HelloController.java
- Individua l'istruzione di ritorno per il percorso principale che indica
return String.format("Hello from your %s environment!", target);
. - Aggiungi un punto di interruzione alla riga facendo clic sullo spazio vuoto a sinistra del numero di riga. Viene visualizzato un indicatore rosso per indicare che il punto di interruzione è impostato
- Ricarica il browser e nota che il debugger interrompe il processo in corrispondenza del punto di interruzione e ti consente di esaminare le variabili e lo stato dell'applicazione in esecuzione da remoto in GKE
- Fai clic nella sezione Variabili fino a trovare la colonna "Target" .
- Osserva il valore attuale come "local"
- Fai doppio clic sul nome della variabile "target" e, nel popup,
Cambia il valore in "Cloud Workstations".
- Fai clic sul pulsante Continua nel pannello di controllo del debug
- Esamina la risposta nel browser, che ora mostra il valore aggiornato che hai appena inserito.
- Per rimuovere il punto di interruzione, fai clic sull'indicatore rosso a sinistra del numero di riga. In questo modo, l'esecuzione del codice in questa riga non verrà interrotta man mano che procedi nel lab.
Ricarica a caldo
- Modifica l'istruzione in modo che restituisca un valore diverso, ad esempio "Hello from %s Code"
- Il file viene salvato e sincronizzato automaticamente nei container remoti in GKE
- Aggiorna il browser per visualizzare i risultati aggiornati.
- Interrompi la sessione di debug facendo clic sul quadrato rosso nella barra degli strumenti di debug
Seleziona "Sì, esegui la pulizia dopo ogni esecuzione".
5. Sviluppo di un servizio REST CRUD semplice
A questo punto la tua applicazione è completamente configurata per lo sviluppo containerizzato e hai seguito il flusso di lavoro di sviluppo di base con Cloud Code. Nelle sezioni seguenti, metterai in pratica ciò che hai imparato aggiungendo endpoint di servizio REST che si connettono a un database gestito in Google Cloud.
Configura le dipendenze
Il codice dell'applicazione utilizza un database per rendere persistenti i dati del servizio rimanenti. Assicurati che le dipendenze siano disponibili aggiungendo quanto segue nel file pom.xl
- Apri il file
pom.xml
e aggiungi quanto segue nella sezione delle dipendenze della configurazione
pom.xml
<!-- Database dependencies-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
Servizio REST del codice
Quote.java
Crea un file denominato Quote.java
in /src/main/java/com/example/springboot/
e copia il codice riportato di seguito. Definisce il modello di entità per l'oggetto Quote utilizzato nell'applicazione.
package com.example.springboot;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.Objects;
@Entity
@Table(name = "quotes")
public class Quote
{
@Id
@Column(name = "id")
private Integer id;
@Column(name="quote")
private String quote;
@Column(name="author")
private String author;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getQuote() {
return quote;
}
public void setQuote(String quote) {
this.quote = quote;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Quote quote1 = (Quote) o;
return Objects.equals(id, quote1.id) &&
Objects.equals(quote, quote1.quote) &&
Objects.equals(author, quote1.author);
}
@Override
public int hashCode() {
return Objects.hash(id, quote, author);
}
}
QuoteRepository.java
Crea un file denominato QuoteRepository.java
all'indirizzo src/main/java/com/example/springboot
e copialo nel seguente codice
package com.example.springboot;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface QuoteRepository extends JpaRepository<Quote,Integer> {
@Query( nativeQuery = true, value =
"SELECT id,quote,author FROM quotes ORDER BY RANDOM() LIMIT 1")
Quote findRandomQuote();
}
Questo codice utilizza JPA per rendere persistenti i dati. La classe estende l'interfaccia Spring JPARepository
e consente la creazione di codice personalizzato. Nel codice hai aggiunto un metodo personalizzato findRandomQuote
.
QuoteController.java
Per esporre l'endpoint per il servizio, una classe QuoteController
fornirà questa funzionalità.
Crea un file denominato QuoteController.java
all'indirizzo src/main/java/com/example/springboot
e copialo nel seguente contenuto
package com.example.springboot;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class QuoteController {
private final QuoteRepository quoteRepository;
public QuoteController(QuoteRepository quoteRepository) {
this.quoteRepository = quoteRepository;
}
@GetMapping("/random-quote")
public Quote randomQuote()
{
return quoteRepository.findRandomQuote();
}
@GetMapping("/quotes")
public ResponseEntity<List<Quote>> allQuotes()
{
try {
List<Quote> quotes = new ArrayList<Quote>();
quoteRepository.findAll().forEach(quotes::add);
if (quotes.size()==0 || quotes.isEmpty())
return new ResponseEntity<List<Quote>>(HttpStatus.NO_CONTENT);
return new ResponseEntity<List<Quote>>(quotes, HttpStatus.OK);
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity<List<Quote>>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PostMapping("/quotes")
public ResponseEntity<Quote> createQuote(@RequestBody Quote quote) {
try {
Quote saved = quoteRepository.save(quote);
return new ResponseEntity<Quote>(saved, HttpStatus.CREATED);
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity<Quote>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PutMapping("/quotes/{id}")
public ResponseEntity<Quote> updateQuote(@PathVariable("id") Integer id, @RequestBody Quote quote) {
try {
Optional<Quote> existingQuote = quoteRepository.findById(id);
if(existingQuote.isPresent()){
Quote updatedQuote = existingQuote.get();
updatedQuote.setAuthor(quote.getAuthor());
updatedQuote.setQuote(quote.getQuote());
return new ResponseEntity<Quote>(updatedQuote, HttpStatus.OK);
} else {
return new ResponseEntity<Quote>(HttpStatus.NOT_FOUND);
}
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity<Quote>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@DeleteMapping("/quotes/{id}")
public ResponseEntity<HttpStatus> deleteQuote(@PathVariable("id") Integer id) {
Optional<Quote> quote = quoteRepository.findById(id);
if (quote.isPresent()) {
quoteRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Aggiungi configurazioni di database
application.yaml
Aggiungi la configurazione per il database di backend a cui accede il servizio. Modifica (o crea se non presente) il file application.yaml
in src/main/resources
e aggiungi una configurazione Spring con parametri per il backend.
target: local
spring:
config:
activate:
on-profile: cloud-dev
datasource:
url: 'jdbc:postgresql://${DB_HOST:127.0.0.1}/${DB_NAME:quote_db}'
username: '${DB_USER:user}'
password: '${DB_PASS:password}'
jpa:
properties:
hibernate:
jdbc:
lob:
non_contextual_creation: true
dialect: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto: update
Aggiungi migrazione di database
Crea le cartelle db/migration
in src/main/resources
Crea un file SQL: V1__create_quotes_table.sql
Incolla i contenuti seguenti nel file
V1__create_quotes_table.sql
CREATE TABLE quotes(
id INTEGER PRIMARY KEY,
quote VARCHAR(1024),
author VARCHAR(256)
);
INSERT INTO quotes (id,quote,author) VALUES (1,'Never, never, never give up','Winston Churchill');
INSERT INTO quotes (id,quote,author) VALUES (2,'While there''s life, there''s hope','Marcus Tullius Cicero');
INSERT INTO quotes (id,quote,author) VALUES (3,'Failure is success in progress','Anonymous');
INSERT INTO quotes (id,quote,author) VALUES (4,'Success demands singleness of purpose','Vincent Lombardi');
INSERT INTO quotes (id,quote,author) VALUES (5,'The shortest answer is doing','Lord Herbert');
Configurazione di Kubernetes
Le seguenti aggiunte al file deployment.yaml
consentono all'applicazione di connettersi alle istanze Cloud SQL.
- TARGET: configura la variabile per indicare l'ambiente in cui viene eseguita l'app
- SPRING_PROFILES_ACTIVE: mostra il profilo Spring attivo, che verrà configurato su
cloud-dev
- DB_HOST: l'IP privato per il database, annotato al momento della creazione dell'istanza del database o facendo clic su
SQL
nel menu di navigazione della console Google Cloud. Modifica il valore. - DB_USER e DB_PASS: come impostato nella configurazione dell'istanza Cloud SQL, archiviati come secret in Google Cloud
Aggiorna il file deployment.yaml con il contenuto seguente.
deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: demo-app
labels:
app: demo-app
spec:
ports:
- port: 8080
protocol: TCP
clusterIP: None
selector:
app: demo-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
labels:
app: demo-app
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: demo-app
image: demo-app
env:
- name: PORT
value: "8080"
- name: TARGET
value: "Local Dev - CloudSQL Database - K8s Cluster"
- name: SPRING_PROFILES_ACTIVE
value: cloud-dev
- name: DB_HOST
value: ${DB_INSTANCE_IP}
- name: DB_PORT
value: "5432"
- name: DB_USER
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: password
- name: DB_NAME
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: database
Sostituisci il valore DB_HOST con l'indirizzo del tuo database eseguendo i comandi seguenti nel terminale:
export DB_INSTANCE_IP=$(gcloud sql instances describe quote-db-instance \
--format=json | jq \
--raw-output ".ipAddresses[].ipAddress")
envsubst < deployment.yaml > deployment.new && mv deployment.new deployment.yaml
Apri deployment.yaml e verifica che il valore DB_HOST sia stato aggiornato con l'IP dell'istanza.
Esegui il deployment e convalida l'applicazione
- Nel riquadro nella parte inferiore dell'editor di Cloud Shell, seleziona Cloud Code, quindi Debug su Kubernetes nella parte superiore dello schermo.
- Una volta completati la build e i test, nella scheda Output appare il seguente messaggio:
Resource deployment/demo-app status completed successfully
, mentre viene visualizzato un URL con il seguente URL: "Forwarded URL from service demo-app: http://localhost:8080". Tieni presente che a volte la porta potrebbe essere diversa, ad esempio 8081. In questo caso, imposta il valore appropriato. Imposta il valore dell'URL nel terminale
export URL=localhost:8080
- Visualizza citazioni casuali
Dal terminale, esegui più volte il comando riportato di seguito sull'endpoint con virgolette casuali. Osservare una chiamata ripetuta con citazioni diverse
curl $URL/random-quote | jq
- Aggiungi un preventivo
Crea una nuova citazione con id=6 utilizzando il comando elencato di seguito e osserva la richiesta ripetuta
curl -H 'Content-Type: application/json' -d '{"id":"6","author":"Henry David Thoreau","quote":"Go confidently in the direction of your dreams! Live the life you have imagined"}' -X POST $URL/quotes
- Eliminare un preventivo
Ora elimina la citazione che hai appena aggiunto con il metodo delete e osserva un codice di risposta HTTP/1.1 204
.
curl -v -X DELETE $URL/quotes/6
- Errore del server
Si verifica uno stato di errore eseguendo di nuovo l'ultima richiesta dopo che la voce è già stata eliminata
curl -v -X DELETE $URL/quotes/6
Nota che la risposta restituisce un HTTP:500 Internal Server Error
.
Esegui il debug dell'applicazione
Nella sezione precedente hai rilevato uno stato di errore nell'applicazione quando hai tentato di eliminare una voce che non era presente nel database. In questa sezione imposterai un punto di interruzione per individuare il problema. L'errore si è verificato nell'operazione DELETE, quindi utilizzerai la classe QuoteController.
- Apri
src/main/java/com/example/springboot/QuoteController.java
- Trova il metodo
deleteQuote()
- Trova la linea:
Optional<Quote> quote = quoteRepository.findById(id);
- Imposta un punto di interruzione sulla riga in questione facendo clic sullo spazio vuoto a sinistra del numero di riga.
- Viene visualizzato un indicatore rosso che indica che il punto di interruzione è impostato
- Esegui di nuovo il comando
delete
curl -v -X DELETE $URL/quotes/6
- Torna alla visualizzazione di debug facendo clic sull'icona nella colonna a sinistra
- Osserva la riga di debug interrotta nella classe QuoteController.
- Nel debugger, fai clic sull'icona
step over
.
- Un codice restituisce al client un errore interno del server HTTP 500, che non è l'ideale.
Trying 127.0.0.1:8080... * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) > DELETE /quotes/6 HTTP/1.1 > Host: 127.0.0.1:8080 > User-Agent: curl/7.74.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 500 < Content-Length: 0 < Date: < * Connection #0 to host 127.0.0.1 left intact
Aggiorna il codice
Il codice non è corretto e il blocco else
deve essere sottoposto a refactoring per inviare un codice di stato HTTP 404 Non trovato.
Correggi l'errore.
- Con la sessione di debug ancora in esecuzione, completa la richiesta premendo il pulsante "Continua" nel pannello di controllo del debug.
- Poi modifica il blocco
else
con il codice:
else {
return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
}
Il metodo dovrebbe essere simile al seguente
@DeleteMapping("/quotes/{id}") public ResponseEntity<HttpStatus> deleteQuote(@PathVariable("id") Integer id) { Optional<Quote> quote = quoteRepository.findById(id); if (quote.isPresent()) { quoteRepository.deleteById(id); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } else { return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND); } }
- Esegui di nuovo il comando di eliminazione
curl -v -X DELETE $URL/quotes/6
- Esegui il debugger e osserva il messaggio HTTP 404 Non trovato restituito al chiamante.
Trying 127.0.0.1:8080... * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) > DELETE /quotes/6 HTTP/1.1 > Host: 127.0.0.1:8080 > User-Agent: curl/7.74.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 404 < Content-Length: 0 < Date: < * Connection #0 to host 127.0.0.1 left intact
- Interrompi la sessione di debug facendo clic sul quadrato rosso nella barra degli strumenti di debug
6. Complimenti
Complimenti In questo lab hai creato da zero una nuova applicazione Java e l'hai configurata per funzionare in modo efficace con i container. Hai quindi eseguito il deployment dell'applicazione ed eseguito il debug in un cluster GKE remoto seguendo lo stesso flusso di sviluppatori che si trova negli stack di applicazioni tradizionali.
Che cosa hai imparato
- Sviluppo di InnerLoop con Cloud Workstations
- Creazione di una nuova applicazione iniziale Java
- Panoramica del processo di sviluppo
- Sviluppo di un servizio REST CRUD semplice
- Debug dell'applicazione su cluster GKE
- Connessione dell'applicazione al database Cloud SQL