1. Présentation
Cet atelier présente des fonctionnalités conçues pour simplifier le workflow de développement des ingénieurs logiciel chargés de développer des applications Java dans un environnement conteneurisé. En règle générale, le développement de conteneurs nécessite que l'utilisateur comprenne les détails des conteneurs et le processus de création de conteneurs. De plus, les développeurs doivent généralement interrompre leur flux et sortir de leur IDE pour tester et déboguer leurs applications dans des environnements distants. Grâce aux outils et technologies mentionnés dans ce tutoriel, les développeurs peuvent travailler efficacement avec des applications conteneurisées sans quitter leur IDE.
Objectifs de l'atelier
Dans cet atelier, vous allez découvrir des méthodes de développement avec des conteneurs dans GCP, y compris:
- Préparation
- Créer une application de démarrage Java
- Parcourir le processus de développement
- Développer un service REST CRUD simple
- Nettoyage
2. Préparation
Configuration de l'environnement d'auto-formation
- Connectez-vous à la console Google Cloud, puis créez un projet ou réutilisez un projet existant. (Si vous ne possédez pas encore de compte Gmail ou Google Workspace, vous devez en créer un.)
- Le nom du projet est le nom à afficher pour les participants au projet. Il s'agit d'une chaîne de caractères qui n'est pas utilisée par les API Google, et que vous pouvez modifier à tout moment.
- L'ID du projet doit être unique sur l'ensemble des projets Google Cloud et doit être immuable (vous ne pouvez pas le modifier une fois que vous l'avez défini). Cloud Console génère automatiquement une chaîne unique dont la composition importe peu, en général. Dans la plupart des ateliers de programmation, vous devrez référencer l'ID du projet (généralement identifié comme
PROJECT_ID
), donc s'il ne vous convient pas, générez-en un autre au hasard ou définissez le vôtre, puis vérifiez s'il est disponible. Il est ensuite "gelé" une fois le projet créé. - La troisième valeur est le numéro de projet, utilisé par certaines API. Pour en savoir plus sur ces trois valeurs, consultez la documentation.
- Vous devez ensuite activer la facturation dans Cloud Console afin d'utiliser les ressources/API Cloud. L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Pour arrêter les ressources afin d'éviter qu'elles ne vous soient facturées après ce tutoriel, suivez les instructions de nettoyage indiquées à la fin de l'atelier. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai gratuit pour bénéficier d'un crédit de 300 $.
Démarrer l'éditeur Cloudshell
Cet atelier a été conçu et testé pour être utilisé avec l'éditeur Google Cloud Shell. Pour accéder à l'éditeur,
- Accédez à votre projet Google à l'adresse https://console.cloud.google.com.
- En haut à droite, cliquez sur l'icône de l'éditeur Cloud Shell.
- Un nouveau volet s'ouvre au bas de la fenêtre.
- Cliquez sur le bouton "Ouvrir l'éditeur"
- L'éditeur s'ouvre avec un explorateur à droite et un éditeur dans la zone centrale
- Un volet de terminal devrait également être disponible au bas de l'écran.
- Si le terminal n'est PAS ouvert, utilisez la combinaison de touches Ctrl+ pour ouvrir une nouvelle fenêtre de terminal.
Configurer gcloud
Dans Cloud Shell, définissez l'ID de votre projet et la région dans laquelle vous souhaitez déployer votre application. Enregistrez-les en tant que variables PROJECT_ID
et REGION
.
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
Obtenir le code source
Le code source de cet atelier se trouve dans l'atelier "container-developer-workshop" de GoogleCloudPlatform sur GitHub. Clonez-le à l'aide de la commande ci-dessous, puis accédez au répertoire.
git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git
cd container-developer-workshop/labs/spring-boot
Provisionner l'infrastructure utilisée dans cet atelier
Dans cet atelier, vous allez déployer du code sur GKE et accéder aux données stockées dans une base de données Cloud SQL. Le script de configuration ci-dessous prépare cette infrastructure pour vous. Le processus de provisionnement prend plus de 10 minutes. Vous pouvez passer aux étapes suivantes pendant le traitement de la configuration.
./setup.sh
3. Créer une application de démarrage Java
Dans cette section, vous allez créer entièrement une application Java Spring Boot à l'aide d'un exemple d'application fourni par print.io.
Cloner l'exemple d'application
- Créer une application de démarrage
curl https://start.spring.io/starter.zip -d dependencies=web -d type=maven-project -d javaVersion=11 -d packageName=com.example.springboot -o sample-app.zip
- Décompresser l'application
unzip sample-app.zip -d sample-app
- Accédez au répertoire "sample-app" et ouvrez le dossier dans l'espace de travail IDE Cloud Shell
cd sample-app && cloudshell workspace .
Ajoutez des outils de développement Jab
Pour activer les outils de développement Spring Boot, recherchez et ouvrez le fichier pom.xml depuis l'explorateur de votre éditeur. Collez ensuite le code suivant après la ligne de description <description>Demo project for Spring Boot</description>.
- Ajoutez "Spring-boot-devtools" dans le fichier pom.xml.
Ouvrez le fichier pom.xml à la racine du projet. Ajoutez la configuration suivante après l'entrée 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>
- Activer jib-maven-plugin dans pom.xml
Jib est un outil de conteneurisation Java Open Source de Google, qui permet aux développeurs Java de créer des conteneurs à l'aide des outils Java qu'ils connaissent. Jib est un générateur d'images de conteneurs rapide et simple qui gère toutes les étapes du packaging de votre application dans une image de conteneur. Vous n'avez pas besoin d'écrire de fichier Dockerfile ni d'installer Docker. De plus, ce fichier est directement intégré à Maven et Gradle.
Faites défiler le fichier pom.xml vers le bas et mettez à jour la section Build
pour inclure le plug-in Jib. Une fois l'opération terminée, la section de compilation doit correspondre à ce qui suit.
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>
Sélectionnez Always
si vous êtes invité à modifier le fichier de compilation.
Générer des fichiers manifestes
Skaffold fournit des outils intégrés pour simplifier le développement de conteneurs. Au cours de cette étape, vous allez initialiser Skaffold, qui créera automatiquement des fichiers YAML Kubernetes de base. Le processus tente d'identifier les répertoires avec des définitions d'image de conteneur, comme un Dockerfile, puis crée un fichier manifeste de déploiement et de service pour chacun d'eux.
Exécutez la commande ci-dessous pour commencer le processus.
- Exécutez la commande suivante dans le terminal.
skaffold init --generate-manifests
- Lorsque vous y êtes invité :
- Utilisez les flèches pour déplacer le curseur sur
Jib Maven Plugin
. - Appuyez sur la barre d'espace pour sélectionner l'option.
- Appuyez sur Entrée pour continuer
- Saisissez 8080 comme port
- Saisissez y pour enregistrer la configuration
Deux fichiers sont ajoutés à la visualisation de l'espace de travail, skaffold.yaml
et deployment.yaml
.
Mettre à jour le nom de l'application
Actuellement, les valeurs par défaut incluses dans la configuration ne correspondent pas au nom de votre application. Mettez à jour les fichiers pour référencer le nom de votre application plutôt que les valeurs par défaut.
- Modifier les entrées dans la configuration Skaffold
- Ouvrir
skaffold.yaml
- Sélectionnez le nom de l'image actuellement défini sur
pom-xml-image
- Effectuez un clic droit et sélectionnez "Modifier toutes les occurrences"
- Saisissez le nouveau nom
demo-app
.
- Modifier les entrées dans la configuration Kubernetes
- Ouvrir le fichier
deployment.yaml
- Sélectionnez le nom de l'image actuellement défini sur
pom-xml-image
- Effectuez un clic droit et sélectionnez "Modifier toutes les occurrences"
- Saisissez le nouveau nom
demo-app
.
Activer la synchronisation à chaud
Pour optimiser l'expérience de hot reload, vous utiliserez la fonctionnalité de synchronisation fournie par Jib. Au cours de cette étape, vous allez configurer Skaffold pour utiliser cette fonctionnalité dans le processus de compilation.
Notez que l'option "sync" que vous configurez dans la configuration Skaffold utilise la synchronisation Spring Profil que vous avez configuré à l'étape précédente, où vous avez activé la prise en charge de Spring-dev-tools.
- Mettre à jour la configuration Skaffold
Dans le fichier skaffold.yaml, remplacez l'intégralité de la section de compilation du fichier par la spécification suivante. Ne modifiez pas les autres sections du fichier.
skaffold.yaml
build:
artifacts:
- image: demo-app
jib:
project: com.example:demo
type: maven
args:
- --no-transfer-progress
- -Psync
fromImage: gcr.io/distroless/java:debug
sync:
auto: true
Ajouter une route par défaut
Créez un fichier appelé HelloController.java à l'emplacement /src/main/java/com/example/springboot/.
Collez le contenu suivant dans le fichier pour créer une route HTTP par défaut
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. Parcourir le processus de développement
Dans cette section, vous allez apprendre à utiliser le plug-in Cloud Code pour connaître les processus de base et valider la configuration de votre application de démarrage.
Cloud Code s'intègre à Skaffold pour simplifier votre processus de développement. Lors des étapes suivantes, Cloud Code et Skaffold créent automatiquement votre image de conteneur, la transfèrent vers Container Registry, puis déploient votre application sur GKE. Cela se produit en arrière-plan afin d'éliminer les détails du flux de développement. Cloud Code améliore également votre processus de développement en fournissant des fonctionnalités traditionnelles de débogage et de synchronisation à chaud avec le développement basé sur des conteneurs.
Déployer sur Kubernetes
- Dans le volet situé en bas de l'éditeur Cloud Shell, sélectionnez Cloud Code .
- Dans le panneau qui s'affiche en haut, sélectionnez "Debug on Kubernetes" (Déboguer sur Kubernetes). Si vous y êtes invité, sélectionnez "Oui" pour utiliser le contexte Kubernetes actuel.
- La première fois que vous exécutez la commande, une invite s'affiche en haut de l'écran pour vous demander si vous voulez le contexte Kubernetes actuel. Sélectionnez "Oui" accepter et utiliser le contexte actuel.
- Une invite s'affiche ensuite pour vous demander quel registre de conteneurs utiliser. Appuyez sur Entrée pour accepter la valeur par défaut fournie
- Sélectionnez l'onglet "Output" (Sortie) dans le volet inférieur pour afficher la progression et les notifications.
- Sélectionnez "Kubernetes: Run/Debug - Détaillé". dans le menu déroulant du canal à droite pour afficher des informations supplémentaires et les journaux diffusés en direct depuis les conteneurs.
- Revenez à la vue simplifiée en sélectionnant "Kubernetes: Run/Debug" (Kubernetes : Exécuter/Déboguer) dans le menu déroulant
- Une fois la compilation et les tests terminés, l'onglet "Output" (Sortie) indique
Resource deployment/demo-app status completed successfully
, et une URL s'affiche : "Forwarded URL from service demo-app: http://localhost:8080" - Dans le terminal Cloud Code, pointez sur l'URL affichée dans le résultat (http://localhost:8080), puis sélectionnez "Ouvrir l'aperçu sur le Web" dans l'info-bulle qui s'affiche.
La réponse sera:
Hello from your local environment!
Utiliser des points d'arrêt
- Ouvrez l'application HelloController.java située à l'emplacement /src/main/java/com/example/springboot/HelloController.java.
- Recherchez l'instruction de retour pour le chemin d'accès racine qui indique
return String.format("Hello from your %s environment!", target);
- Ajoutez un point d'arrêt à cette ligne en cliquant sur l'espace vide à gauche du numéro de ligne. Un indicateur rouge s'affiche pour indiquer que le point d'arrêt est défini.
- Actualisez votre navigateur et notez que le débogueur arrête le processus au point d'arrêt et vous permet d'examiner la variable d'état (sable) de l'application qui s'exécute à distance dans GKE.
- Cliquez sur la section "Variables" vers le bas jusqu'à la colonne "Cible". .
- Observer la valeur actuelle en tant que "local"
- Double-cliquez sur le nom de variable "target". puis, dans la fenêtre pop-up, remplacez la valeur par "Cloud"
- Cliquez sur le bouton "Continuer" dans le panneau de configuration du débogage.
- Examinez la réponse dans votre navigateur qui affiche à présent la nouvelle valeur que vous venez de saisir.
Actualisation à chaud
- Modifiez l'instruction pour renvoyer une valeur différente, telle que "Hello from %s Code" (Bonjour de %s Code).
- Le fichier est automatiquement enregistré et synchronisé dans les conteneurs distants dans GKE
- Actualisez votre navigateur pour voir les résultats mis à jour.
- Arrêtez la session de débogage en cliquant sur le carré rouge dans la barre d'outils de débogage .
5. Développer un service REST CRUD simple
À ce stade, votre application est entièrement configurée pour le développement conteneurisé, et vous avez suivi le workflow de développement de base avec Cloud Code. Dans les sections suivantes, vous allez mettre en pratique ce que vous avez appris en ajoutant des points de terminaison du service REST se connectant à une base de données gérée dans Google Cloud.
Configurer des dépendances
Le code de l'application utilise une base de données pour conserver les données du service REST. Assurez-vous que les dépendances sont disponibles en ajoutant ce qui suit dans le fichier pom.xl.
- Ouvrez le fichier
pom.xml
et ajoutez le code suivant dans la section des dépendances de la configuration
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>
Coder le service REST
Quote.java
Créez un fichier nommé Citation.java dans /src/main/java/com/example/springboot/ et copiez-y le code ci-dessous. Ce champ définit le modèle d'entité de l'objet Citation utilisé dans l'application.
package com.example.springboot;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.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
Créez un fichier nommé CitationRepository.java dans src/main/java/com/example/springboot et copiez-y le code suivant.
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();
}
Ce code utilise JPA pour la persistance des données. La classe étend l'interface Spring JPARepository
et permet de créer du code personnalisé. Dans le code, vous avez ajouté une méthode personnalisée findRandomQuote
.
QuoteController.java
Pour exposer le point de terminaison au service, une classe QuoteController
fournira cette fonctionnalité.
Créez un fichier nommé CitationController.java dans src/main/java/com/example/springboot et copiez-le dans le contenu suivant.
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) {
try {
quoteRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (RuntimeException e) {
System.out.println(e.getMessage());
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Ajouter des configurations de base de données
application.yaml
Ajoutez une configuration pour la base de données backend à laquelle le service a accès. Modifiez (ou créez-le s'il n'existe pas) le fichier application.yaml
sous src/main/resources
et ajoutez une configuration Spring paramétrée pour le 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
Ajouter une migration de base de données
Créez un dossier à l'emplacement src/main/resources/db/migration/.
Créer un fichier SQL: V1__create_quotes_table.sql
Collez le contenu suivant dans le fichier
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');
Configuration de Kubernetes
Les ajouts suivants au fichier deployment.yaml
permettent à l'application de se connecter aux instances Cloud SQL.
- TARGET : configure la variable pour indiquer l'environnement dans lequel l'application est exécutée.
- SPRING_PROFILES_ACTIVE : affiche le profil Spring actif, qui sera configuré sur
cloud-dev
. - DB_HOST : adresse IP privée de la base de données, qui a été notée lors de la création de l'instance de base de données ou en cliquant sur
SQL
dans le menu de navigation de la console Google Cloud. Veuillez modifier la valeur. - DB_USER et DB_PASS, tels que définis dans la configuration de l'instance Cloud SQL, stockés en tant que Secret dans GCP
Mettez à jour votre fichier deployment.yaml avec le contenu ci-dessous.
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
Remplacez la valeur DB_HOST par l'adresse de votre base de données.
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
Déployer et valider l'application
- Dans le volet situé en bas de l'éditeur Cloud Shell, sélectionnez Cloud Code, puis "Déboguer sur Kubernetes" en haut de l'écran.
- Une fois la compilation et les tests terminés, l'onglet "Output" (Sortie) indique
Resource deployment/demo-app status completed successfully
, et une URL s'affiche : "Forwarded URL from service demo-app: http://localhost:8080" - Afficher les citations aléatoires
Depuis le terminal cloudshell, exécutez plusieurs fois la commande ci-dessous sur le point de terminaison "random-citation". Observer un appel répété renvoyant des guillemets différents
curl -v 127.0.0.1:8080/random-quote
- Ajouter un devis
Créez un autre devis avec id=6 à l'aide de la commande ci-dessous et observez l'écho de la requête.
curl -v -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 127.0.0.1:8080/quotes
- Supprimer une citation
Maintenant, supprimez la citation que vous venez d'ajouter avec la méthode delete et observez un code de réponse HTTP/1.1 204
.
curl -v -X DELETE 127.0.0.1:8080/quotes/6
- Erreur du serveur
Vous rencontrerez un état d'erreur en exécutant à nouveau la dernière requête après la suppression de l'entrée.
curl -v -X DELETE 127.0.0.1:8080/quotes/6
Notez que la réponse renvoie un HTTP:500 Internal Server Error
.
Déboguer l'application
Dans la section précédente, vous avez trouvé un état d'erreur dans l'application lorsque vous avez essayé de supprimer une entrée qui ne figurait pas dans la base de données. Dans cette section, vous allez définir un point d'arrêt pour localiser le problème. L'erreur s'est produite lors de l'opération DELETE. Vous allez donc utiliser la classe CitationController.
- Ouvrez src.main.java.com.example.springboot.CitationController.java
- Rechercher la méthode
deleteQuote()
- Recherchez la ligne permettant de supprimer un élément de la base de données:
quoteRepository.deleteById(id);
- Définissez un point d'arrêt sur cette ligne en cliquant sur l'espace vide à gauche du numéro de ligne.
- Un indicateur rouge s'affiche pour indiquer que le point d'arrêt est défini.
- Exécutez à nouveau la commande
delete
.
curl -v -X DELETE 127.0.0.1:8080/quotes/6
- Pour revenir à la vue de débogage, cliquez sur l'icône dans la colonne de gauche.
- Comme vous pouvez le constater, la ligne de débogage s'est arrêtée dans la classe CitationController.
- Dans le débogueur, cliquez sur l'icône
step over
et observez qu'une exception est générée. - Notez qu'un
RuntimeException was caught.
très générique renvoie au client une erreur de serveur interne HTTP 500, ce qui n'est pas idéal.
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
Mettre à jour le code
Le code est incorrect et le bloc d'exceptions doit être refactorisé pour intercepter l'exception EmptyResultDataAccessException
et renvoyer un code d'état HTTP 404 (introuvable).
Corrigez l'erreur.
- La session de débogage étant toujours en cours d'exécution, terminez la requête en cliquant sur le bouton "Continuer". dans le panneau de configuration du débogage.
- Ajoutez ensuite le bloc suivant au code:
} catch (EmptyResultDataAccessException e){
return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
}
La méthode doit se présenter comme suit :
public ResponseEntity<HttpStatus> deleteQuote(@PathVariable("id") Integer id) { try { quoteRepository.deleteById(id); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } catch(EmptyResultDataAccessException e){ return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND); } catch (RuntimeException e) { System.out.println(e.getMessage()); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } }
- Réexécuter la commande de suppression
curl -v -X DELETE 127.0.0.1:8080/quotes/6
- Parcourez le débogueur et observez que
EmptyResultDataAccessException
est intercepté et qu'un message HTTP 404 Not Found est renvoyé à l'appelant.
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
- Arrêtez la session de débogage en cliquant sur le carré rouge dans la barre d'outils de débogage .
6. Nettoyage
Félicitations ! Dans cet atelier, vous avez entièrement créé une application Java et l'avez configurée pour fonctionner efficacement avec des conteneurs. Vous avez ensuite déployé et débogué votre application sur un cluster GKE distant en suivant le même parcours de développement que dans les piles d'applications traditionnelles.
Pour effectuer un nettoyage une fois l'atelier terminé:
- Supprimer les fichiers utilisés dans l'atelier
cd ~ && rm -rf container-developer-workshop
- Supprimer le projet pour retirer toute l'infrastructure et toutes les ressources associées