Migrer de l'application Java Google App Engine vers Cloud Run avec Docker

1. Présentation

Cette série d'ateliers de programmation (tutoriels pratiques et d'auto-formation) vise à aider les développeurs Java sur Google App Engine (standard) à moderniser leurs applications en les guidant lors d'une série de migrations. En suivant ces étapes, vous pouvez rendre votre application plus portable et décider de la conteneuriser pour Cloud Run, le service d'hébergement de conteneurs de Google Cloud étroitement lié à App Engine, ainsi que pour d'autres services d'hébergement de conteneurs.

Ce tutoriel explique comment conteneuriser une application App Engine afin de la déployer sur le service entièrement géré Cloud Run à l'aide d'un fichier Dockerfile. Les fichiers Docker sont la méthode de déploiement la plus pratique pour cette migration, mais ils offrent également le plus d'options pour personnaliser votre processus de compilation.

En plus de vous expliquer les étapes requises pour passer d'App Engine à Cloud Run, vous découvrirez comment mettre à niveau une application App Engine Java 8 vers Java 17.

Si l'application que vous souhaitez migrer utilise de manière intensive les anciens services groupés App Engine ou d'autres fonctionnalités spécifiques à App Engine, le guide Accéder aux services groupés App Engine pour Java 11/17 constitue peut-être un meilleur point de départ que cet atelier de programmation.

Vous apprendrez à

  • Utiliser Cloud Shell
  • Activez les API Cloud Run, Artifact Registry et Cloud Build.
  • Conteneuriser votre application à l'aide de Docker, Docker et Cloud Build
  • Déployer vos images de conteneur dans Cloud Run

Prérequis

Enquête

Comment allez-vous utiliser ce tutoriel ?

Je vais le lire uniquement Je vais le lire et effectuer les exercices

Comment évalueriez-vous votre expérience avec Java ?

Débutant Intermédiaire Expert

Quel est votre niveau d'expérience avec les services Google Cloud ?

Débutant Intermédiaire Expert

2. Contexte

Les systèmes PaaS tels qu'App Engine et Cloud Functions offrent de nombreux avantages pour vos équipes et vos applications, par exemple en permettant aux administrateurs système et aux développeurs DevOps de se concentrer sur la création de solutions. Avec les plates-formes sans serveur, votre application peut évoluer automatiquement à la hausse si nécessaire, effectuer un scaling à la baisse jusqu'à zéro avec la facturation à l'utilisation pour vous aider à maîtriser les coûts, et utiliser divers langages de développement courants.

La flexibilité des conteneurs est un autre atout majeur. Avec la possibilité de choisir n'importe quel langage, n'importe quelle bibliothèque et n'importe quel binaire, les conteneurs vous offrent le meilleur des deux mondes: la commodité du sans serveur et la flexibilité des conteneurs. C'est l'objectif de Google Cloud Run.

Apprendre à utiliser Cloud Run dépasse le cadre du présent atelier de programmation. Pour cela, consultez la documentation de Cloud Run. L'objectif est de vous familiariser avec la conteneurisation de votre application App Engine pour Cloud Run (ou d'autres services hébergés par des conteneurs). Avant de continuer, vous devez prendre connaissance de quelques informations : votre expérience utilisateur sera légèrement différente.

Dans cet atelier de programmation, vous allez apprendre à créer et à déployer des conteneurs. Vous allez apprendre à conteneuriser votre application avec un Dockerfile, à effectuer une migration hors de la configuration App Engine et (éventuellement) à définir des étapes de compilation pour Cloud Build. Vous devrez donc abandonner certaines fonctionnalités spécifiques à App Engine. Si vous préférez ne pas suivre cette voie, vous pouvez toujours passer à un environnement d'exécution Java 11/17 tout en conservant vos applications sur App Engine.

3. Configuration/Préparation

1. Configurer le projet

Pour ce tutoriel, vous allez utiliser un exemple d'application du dépôt appengine-java-migration-samples sur un tout nouveau projet. Assurez-vous que le projet dispose d'un compte de facturation actif.

Si vous prévoyez de migrer une application App Engine existante vers Cloud Run, vous pouvez utiliser cette application pour suivre ce tutoriel.

Exécutez la commande suivante pour activer les API nécessaires à votre projet:

gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com

2. Obtenir un exemple d'application de référence

Clonez l'exemple d'application sur votre propre machine ou dans Cloud Shell, puis accédez au dossier baseline.

L'exemple est une application Datastore Java 8 basée sur un servlet destinée à être déployée sur App Engine. Suivez les instructions du fichier README pour préparer cette application au déploiement sur App Engine.

3. (Facultatif) Déployer l'application de référence

Les étapes suivantes ne sont nécessaires que si vous souhaitez vérifier que l'application fonctionne sur App Engine avant de migrer vers Cloud Run.

Reportez-vous aux étapes décrites dans le fichier README.md:

  1. Installer/vous familiariser à nouveau avec la CLI gcloud
  2. Initialiser la gcloud CLI pour votre projet avec gcloud init
  3. Créer le projet App Engine avec gcloud app create
  4. Déployer l'exemple d'application sur App Engine
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. Vérifier que l'application s'exécute sans problème sur App Engine

4. Créer un dépôt Artifact Registry

Après avoir conteneurisé votre application, vous devrez trouver un emplacement où transférer et stocker vos images. La méthode recommandée sur Google Cloud est d'utiliser Artifact Registry.

Créez le dépôt nommé migration avec gcloud comme suit:

gcloud artifacts repositories create migration --repository-format=docker \
--description="Docker repository for the migrated app" \
--location="northamerica-northeast1"

Notez que ce dépôt utilise le type de format docker, mais il existe plusieurs types de dépôts disponibles.

À ce stade, vous disposez de votre application App Engine de référence et votre projet Google Cloud est prêt à la migrer vers Cloud Run.

4. Modifier les fichiers de l'application

Si votre application utilise beaucoup les anciens services groupés, la configuration ou d'autres fonctionnalités réservées à App Engine, nous vous recommandons de continuer à accéder à ces services lors de la migration vers le nouvel environnement d'exécution. Cet atelier de programmation présente un chemin de migration pour les applications qui utilisent déjà des services autonomes ou qui peuvent être refactorisées pour le faire.

1. Mettre à niveau vers Java 17

Si votre application fonctionne avec Java 8, envisagez de passer à une version LTS ultérieure (version 11 ou 17, par exemple) pour vous tenir informé des mises à jour de sécurité et accéder aux nouvelles fonctionnalités du langage.

Commencez par mettre à jour les propriétés de votre pom.xml pour inclure les éléments suivants:

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

La version du projet sera alors définie sur 17, le plug-in du compilateur sera informé que vous souhaitez accéder aux fonctionnalités du langage Java 17 et que vous souhaitez que les classes compilées soient compatibles avec la JVM Java 17.

2. y compris un serveur Web ;

Il existe un certain nombre de différences entre App Engine et Cloud Run qui méritent d'être prises en compte lorsque vous passez de l'un à l'autre. Une différence est que, contrairement à Cloud Run, l'environnement d'exécution Java 8 d'App Engine fournissait et gérait un serveur Jetty pour les applications qu'il hébergeait. Nous allons utiliser Spring Boot pour nous fournir un serveur Web et un conteneur de servlets.

Ajoutez les dépendances suivantes :

<dependencies>
<!-- ... -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
       <version>2.6.6</version>
       <exclusions>
           <!-- Exclude the Tomcat dependency -->
           <exclusion>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-tomcat</artifactId>
           </exclusion>
       </exclusions>
   </dependency>
   <!-- Use Jetty instead -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-jetty</artifactId>
       <version>2.6.6</version>
   </dependency>
<!-- ... -->
</dependencies>

Spring Boot intègre un serveur Tomcat par défaut, mais cet exemple exclura cet artefact et utilisera Jetty pour minimiser les différences de comportement par défaut après la migration.

3. Configuration de Spring Boot

Bien que Spring Boot puisse réutiliser vos servlets sans modification, il nécessite une configuration pour s'assurer qu'ils sont détectables.

Créez la classe MigratedServletApplication.java suivante dans le package com.example.appengine:

package com.example.appengine;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
@EnableAutoConfiguration
public class MigratedServletApplication {
    public static void main(String[] args) {
        SpringApplication.run(MigratedServletApplication.class, args);
    }
}

Notez que cela inclut l'annotation @ServletComponentScan, qui recherche (dans le package actuel par défaut) tous les @WebServlets et les rend disponibles comme prévu.

4. Empaqueter l'application en tant que fichier JAR

Bien qu'il soit possible de conteneuriser votre application en partant d'une guerre, il est plus facile de l'empaqueter en tant que fichier JAR exécutable. Cela ne nécessitera pas beaucoup de configuration, en particulier pour les projets utilisant Maven comme outil de compilation, car le packaging JAR est le comportement par défaut.

Supprimez la balise packaging dans le fichier pom.xml:

<packaging>war</packaging>

Ajoutez ensuite spring-boot-maven-plugin:

<plugins>
<!-- ... -->
  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.6.6</version>
  </plugin>
<!-- ... -->
</plugins>

5. Abandon de la configuration, des services et des dépendances App Engine

Comme indiqué au début de l'atelier de programmation, Cloud Run et App Engine sont conçus pour offrir des expériences utilisateur différentes. Certaines fonctionnalités proposées par App Engine prêtes à l'emploi, comme les services Cron et Task Queue, doivent être recréées manuellement. Elles seront abordées plus en détail dans les modules suivants.

L'application exemple n'utilise pas les anciens services groupés, mais les utilisateurs dont les applications le font peuvent consulter les guides suivants:

Étant donné que vous allez désormais déployer sur Cloud Run, vous pouvez supprimer appengine-maven-plugin:

<plugin>
 <groupId>com.google.cloud.tools</groupId>
 <artifactId>appengine-maven-plugin</artifactId>
 <version>2.4.1</version>
 <configuration>
   <!-- can be set w/ -DprojectId=myProjectId on command line -->
   <projectId>${app.projectId}</projectId>
   <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
   <version>GCLOUD_CONFIG</version>
 </configuration>
</plugin>

5. Conteneuriser l'application

À ce stade, vous êtes prêt à indiquer à Cloud Build comment créer le conteneur de votre application. Avec cette méthode de conteneurisation, aucun fichier de configuration de compilation distinct (cloudbuild.yaml) n'est requis. Nous pouvons simplement définir un Dockerfile minimal comme point de départ:

FROM eclipse-temurin

ARG JAR_FILE=JAR_FILE_MUST_BE_SPECIFIED_AS_BUILD_ARG

COPIER ${JAR_FILE} app.jar

ENTRYPOINT ["java", "-jar", "/app.jar"]

Ce fichier Dockerfile regroupe la version uber-jar de votre service Spring Boot dans une seule couche. Il s'agit de l'approche la plus simple pour la conteneurisation Dockerfile, mais elle présente un certain nombre d'inconvénients, en particulier lors de comparaisons répétées lorsque les dépendances sont relativement stables. C'est pourquoi cette méthode de conteneurisation est considérée comme plus avancée. En revanche, écrire votre propre fichier Dockerfile vous permet de contrôler entièrement votre image de base et de profiter des avantages en termes de performances de l'écriture d'une image soigneusement stratifiée.

2**. Exécuter le processus de compilation**

Maintenant que vous avez indiqué à Cloud Build les étapes de compilation souhaitées, vous pouvez procéder à un déploiement en un clic.

Exécutez la commande suivante :

gcloud builds submit --tag LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME

Remplacez les valeurs d'espace réservé dans la commande ci-dessus par les éléments suivants :

  • LOCATION: emplacement régional ou multirégional de votre dépôt.
  • PROJECT_ID: ID de votre projet Cloud.
  • REPOSITORY: nom de votre dépôt Artifact Registry.
  • IMAGE_NAME: nom de votre image de conteneur.

Une fois le processus terminé, votre image de conteneur a été créée, stockée dans Artifact Registry et déployée dans Cloud Run.

À la fin de cet atelier de programmation, votre application devrait ressembler à celle du dossier mod4-migrate-to-cloud-run.

Et voilà ! Vous avez réussi à migrer une application App Engine Java 8 vers Java 17 et Cloud Run. Vous avez maintenant une meilleure compréhension du travail impliqué lors du passage et de la sélection des options d'hébergement.

6. Résumé/Nettoyage

Félicitations ! Vous avez mis à niveau, conteneurisé, migré et déployé votre application. Ce tutoriel est maintenant terminé.

L'étape suivante consiste à en savoir plus sur les fonctionnalités de CI/CD et de sécurité de la chaîne d'approvisionnement logicielle que vous pouvez désormais déployer avec Cloud Build:

Facultatif: Nettoyer et/ou désactiver le service

Si vous avez déployé l'application exemple sur App Engine au cours de ce tutoriel, n'oubliez pas de la désactiver pour éviter que des frais ne vous soient facturés. Lorsque vous serez prêt à passer au prochain atelier de programmation, vous pourrez le réactiver. Lorsque les applications App Engine sont désactivées, elles n'enregistrent aucun trafic et ne génèrent pas de frais. Toutefois, l'utilisation de Datastore peut être facturable si elle dépasse son quota sans frais. Vous devez donc supprimer suffisamment de données pour passer sous cette limite.

En revanche, si vous ne souhaitez pas poursuivre vos migrations et que vous souhaitez tout supprimer complètement, vous pouvez supprimer votre service ou arrêter le projet complètement.

7. Ressources supplémentaires

Problèmes/commentaires concernant le module de migration App Engine en atelier de programmation

Si vous rencontrez des problèmes avec cet atelier de programmation, commencez par faire une recherche avant de les signaler. Liens vers la recherche et la création d'un signalement :

Ressources de migration

Ressources en ligne

Vous trouverez ci-dessous des ressources en ligne qui peuvent être utiles pour ce tutoriel:

App Engine

Informations sur d'autres clouds

Vidéos

Licence

Ce document est publié sous une licence Creative Commons Attribution 2.0 Generic.