Déployer une application Micronaut conteneurisée avec Jib sur Google Kubernetes Engine

1. Présentation

À propos de Micronaut

Micronaut est un framework full stack moderne basé sur des JVM qui permet de créer des applications sans serveur et des microservices modulaires et faciles à tester. L'objectif de Micronaut est d'offrir un démarrage rapide et un débit rapide, avec un encombrement minimal de la mémoire. Les développeurs peuvent développer avec Micronaut en Java, Groovy ou Kotlin.

Avantages de Micronaut:

  • Démarrage rapide Faible consommation de mémoire : les frameworks IoC basés sur la réflexion chargent et mettent en cache les données de réflexion pour chaque champ, méthode et constructeur de votre code. Avec Micronaut, le temps de démarrage de votre application et la consommation de mémoire ne sont pas liés à la taille de votre codebase.
  • Client HTTP déclaratif, réactif et au moment de la compilation : créez des clients HTTP réactifs de manière déclarative, qui sont implémentés au moment de la compilation, ce qui réduit la consommation de mémoire.
  • Serveur HTTP non bloquant basé sur Netty : avec une courbe d'apprentissage fluide, le serveur HTTP de Micronaut permet d'exposer aussi facilement que possible les API pouvant être utilisées par les clients HTTP.
  • Tests simples et rapides : lancez facilement des serveurs et des clients dans vos tests unitaires, et exécutez-les instantanément.
  • Injection de dépendances et AOP efficaces au moment de la compilation : Micronaut fournit une API de programmation simple basée sur les aspects qui n'utilise pas la réflexion au moment de la compilation.
  • Créer des applications entièrement réactives et non bloquantes : Micronaut est compatible avec tous les frameworks qui implémentent des flux réactifs, y compris RxJava et Reactor.

Pour en savoir plus, consultez le site Web de Micronaut.

À propos de Kubernetes

Kubernetes est un projet Open Source qui peut s'exécuter dans de nombreux environnements différents : des ordinateurs portables aux clusters multinœuds à haute disponibilité, des clouds publics aux déploiements sur site, des machines virtuelles aux machines dédiées.

Dans cet atelier, vous allez déployer un microservice Micronaut simple basé sur Groovy dans Kubernetes, exécuté sur Kubernetes Engine.

L'objectif de cet atelier de programmation est de vous permettre d'exécuter votre microservice en tant que service répliqué exécuté sur Kubernetes. Vous allez convertir le code que vous avez développé sur votre machine en une image de conteneur Docker, puis exécuter cette image sur Kubernetes Engine.

Voici un schéma des différentes parties de cet atelier de programmation pour vous aider à comprendre comment les éléments s'assemblent. Utilisez-le comme référence tout au long de l'atelier de programmation. Tout devrait avoir du sens à la fin (mais n'hésitez pas à ignorer cela pour l'instant).

Schéma de l'atelier de programmation Kubernetes 1 (2).png

Pour les besoins de cet atelier de programmation, l'utilisation d'un environnement géré tel que Kubernetes Engine (une version de Kubernetes hébergée par Google et exécutée sur Compute Engine) vous permet de vous concentrer davantage sur l'utilisation de Kubernetes plutôt que sur la configuration de l'infrastructure sous-jacente.

Si vous souhaitez exécuter Kubernetes sur votre appareil local, par exemple votre ordinateur portable de développement, n'hésitez pas à utiliser Minikube. Il permet de configurer facilement un cluster Kubernetes à nœud unique à des fins de développement et de test. Si vous le souhaitez, vous pouvez utiliser Minikube pour suivre cet atelier de programmation.

À propos de Jib

Jib est un outil Open Source qui vous permet de créer des images Docker et OCI pour vos applications Java. Il est disponible en tant que plug-in pour Maven et Gradle, et en tant que bibliothèque Java.

Jib vise à:

  • Rapide : déployez vos modifications rapidement. Jib divise votre application en plusieurs couches, en séparant les dépendances des classes. Vous n'avez plus besoin d'attendre que Docker recompile l'intégralité de votre application Java. Il vous suffit de déployer les couches qui ont été modifiées.
  • Reproductible : la reconstruction d'une image de conteneur avec le même contenu génère toujours la même image. Ne déclenchez plus jamais de mises à jour inutiles.
  • Daemonless : réduisez vos dépendances de CLI. Créez votre image Docker à partir de Maven ou de Gradle, puis transférez-la vers le registre de votre choix. Vous n'avez plus besoin d'écrire des fichiers Dockerfile ni d'appeler docker build/push.

Vous trouverez plus d'informations sur Jib sur la page du projet GitHub.

À propos de ce tutoriel

Ce tutoriel utilise l'exemple de code de l'outil Jib afin de créer des conteneurs pour les applications Java.

L'exemple est un service hello world simple, utilisant le framework Micronaut et le langage de programmation Apache Groovy.

Points abordés

  • Empaqueter une application Java simple en tant que conteneur Docker à l'aide de Jib
  • Créer un cluster Kubernetes sur Kubernetes Engine
  • Déployer votre service Micronaut dans Kubernetes sur Kubernetes Engine
  • Effectuer un scaling à la hausse et déployer une mise à niveau de votre service
  • Accéder au tableau de bord graphique de Kubernetes

Prérequis

  • Un projet Google Cloud Platform
  • Un navigateur tel que Chrome ou Firefox
  • Bonne connaissance des éditeurs de texte Linux standards tels que Vim, EMACs ou Nano

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 en matière de création d'applications Web HTML/CSS ?

Débutant Intermédiaire Expert

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

<ph type="x-smartling-placeholder"></ph> Débutant Intermédiaire Expert
.

2. Préparation

Configuration de l'environnement d'auto-formation

  1. Connectez-vous à Cloud Console, puis créez un projet ou réutilisez un projet existant. (Si vous n'avez pas encore de compte Gmail ou G Suite, vous devez en créer un.)

dMbN6g9RawQj_VXCSYpdYncY-DbaRzr2GbnwoV7jFf1u3avxJtmGPmKpMYgiaMH-qu80a_NJ9p2IIXFppYk8x3wyymZXavjglNLJJhuXieCem56H30hwXtd8PvXGpXJO9gEUDu3cZw

ci9Oe6PgnbNuSYlMyvbXF1JdQyiHoEgnhl4PlV_MFagm2ppzhueRkqX4eLjJllZco_2zCp0V0bpTupUSKji9KkQyWqj11pqit1K1faS1V6aFxLGQdkuzGp4rsQTan7F01iePL5DtqQ

8-tA_Lheyo8SscAVKrGii2coplQp2_D1Iosb2ViABY0UUO1A8cimXUu6Wf1R9zJIRExL5OB2j946aIiFtyKTzxDcNnuznmR45vZ2HMoK3o67jxuoUJCAnqvEX6NgPGFjCVNgASc-lg

Mémorisez l'ID du projet. Il s'agit d'un nom unique permettant de différencier chaque projet Google Cloud (le nom ci-dessus est déjà pris ; vous devez en trouver un autre). Il sera désigné par le nom PROJECT_ID tout au long de cet atelier de programmation.

  1. Vous devez ensuite activer la facturation dans Cloud Console pour pouvoir utiliser les ressources Google Cloud.

L'exécution de cet atelier de programmation est très peu coûteuse, voire gratuite. Veillez à suivre les instructions de la section "Nettoyer" qui indique comment désactiver les ressources afin d'éviter les frais une fois ce tutoriel terminé. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai sans frais pour bénéficier d'un crédit de 300 $.

3. Obtenir l'exemple de code source pour Micronaut

Une fois Cloud Shell lancé, vous pouvez utiliser la ligne de commande pour cloner l'exemple de code source dans le répertoire d'accueil, puis utiliser la commande cd pour accéder au répertoire contenant notre exemple de service:

$ git clone https://github.com/GoogleContainerTools/jib.git
$ cd jib/examples/micronaut/

4. Aperçu du code

Notre service simple Micronaut est constitué d'un contrôleur qui affiche le tristement célèbre message Hello World:

@Controller("/hello")
class HelloController {
    @Get("/")
    String index() {
        "Hello World"
    }
}

Le contrôleur HelloController répond aux requêtes sous le chemin /hello, et la méthode index() accepte les requêtes HTTP GET.

Une classe de test Spock est également disponible pour vérifier que le message qui s'affiche en sortie est correct.

class HelloControllerSpec extends Specification {
    @Shared
    @AutoCleanup
    EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer)

    @Shared
    @AutoCleanup
    RxHttpClient client = embeddedServer.applicationContext.createBean(RxHttpClient, embeddedServer.getURL()) 

    void "test hello world response"() {
        when:
        HttpRequest request = HttpRequest.GET('/hello')
        String rsp  = client.toBlocking().retrieve(request)

        then:
        rsp == "Hello World"
    }
}

Plus qu'un simple test unitaire, ce test exécute en réalité la même pile de serveurs Micronaut (basée sur le framework Netty) que celle exécutée en production. Le comportement de votre code sera donc le même dans le produit et dans les tests.

Pour exécuter les tests, exécutez la commande suivante afin de vérifier que tout fonctionne correctement:

./gradlew test

5. Exécuter l'application en local

Vous pouvez démarrer le service Micronaut normalement à l'aide de la commande Gradle suivante:

$ ./gradlew run

Une fois que l'application a démarré, vous pouvez ouvrir une instance Cloud Shell supplémentaire grâce à la petite icône +, puis vérifier à l'aide de curl que vous obtenez le résultat attendu:

$ curl localhost:8080/hello

Un simple "Hello World" doit s'afficher. s'affiche.

6. Empaqueter l'application en tant que conteneur Docker avec Jib

Préparez ensuite votre application à s'exécuter sur Kubernetes. Pour cela, nous utiliserons Jib pour faire le plus dur, car nous n'aurons pas besoin de toucher un Dockerfile nous-mêmes.

Exécutons cette commande pour créer notre conteneur:

$ ./gradlew jibDockerBuild

Vous devriez obtenir le résultat suivant:

Tagging image with generated image reference micronaut-jib:0.1. If you'd like to specify a different tag, you can set the jib.to.image parameter in your build.gradle, or use the --im
age=<MY IMAGE> commandline flag.

Containerizing application to Docker daemon as micronaut-jib:0.1...
warning: Base image 'gcr.io/distroless/java' does not use a specific image digest - build may not be reproducible
Getting base image gcr.io/distroless/java...
Building dependencies layer...
Building resources layer...
Building classes layer...
Finalizing...

Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, example.micronaut.Application]
Loading to Docker daemon...

Built image to Docker daemon as micronaut-jib:0.1

Maintenant que l'image est créée, vérifions si nous pouvons voir notre message de bienvenue en exécutant notre image Docker dans le premier onglet de Cloud Shell:

$ docker run -it -p 8080:8080 micronaut-jib:0.1
16:57:20.255 [main] INFO  i.m.context.env.DefaultEnvironment - Established active environments: [cloud, gcp]
16:57:23.203 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 2926ms. Server Running: http://97b7d76ccf3f:8080

Notre service est en cours d'exécution. Nous pouvons donc lancer la commande curl dans le deuxième onglet Cloud Shell pour voir si elle fonctionne comme prévu:

$ curl localhost:8080/hello
Hello World

Vous pouvez arrêter le conteneur en appuyant sur Ctrl+C dans Cloud Shell.

7. Transférer notre service conteneurisé vers le registre

Maintenant que l'image fonctionne comme prévu, vous pouvez la transférer vers Google Container Registry, un dépôt privé pour vos images Docker accessible depuis tous les projets Google Cloud (mais également en dehors de Google Cloud Platform).

Avant de pouvoir transférer des données vers le registre, vérifions que Container Registry est activé pour notre projet. Pour ce faire, accédez à Outils > Container Registry. Si la boîte de dialogue suivante n'est pas activée, cliquez sur Activer l'API Container Registry. pour l'activer:

ac812e6260ac7dfb.png

Une fois que le registre est prêt, lancez les commandes suivantes pour y transférer l'image:

$ gcloud auth configure-docker
$ docker tag micronaut-jib:0.1 \
         gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1
$ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1

Les commandes ci-dessus permettent au SDK gcloud de configurer et d'autoriser Docker à transférer des images vers votre instance Container Registry, à ajouter des tags à l'image pour qu'elle pointe vers son emplacement dans le registre, puis à la transférer vers le registre.

Si tout se passe comme prévu, l'image de conteneur doit apparaître dans la console au bout de quelques instants: Outils > Container Registry. Vous disposez maintenant d'une image Docker pour l'ensemble du projet. Comme vous le verrez dans quelques minutes, vous pouvez accéder à cette image et l'orchestrer grâce à Kubernetes.

12224c4e42183b4e.png

8. Créer votre cluster

Vous êtes maintenant prêt à créer votre cluster Kubernetes Engine. Avant cela, accédez à la section "Google Kubernetes Engine" de la console Web et attendez que le système s'initialise (cela ne devrait prendre que quelques secondes).

20c0587c0108b8ba.png

Un cluster se compose d'un serveur d'API maître Kubernetes géré par Google et d'un ensemble de nœuds de calcul. Les nœuds de calcul correspondent à des machines virtuelles Compute Engine. Utilisons la CLI gcloud de votre session Cloud Shell pour créer un cluster avec deux nœuds n1-standard-1 (cette opération prend quelques minutes):

$ gcloud container clusters create hello-cluster \
  --num-nodes 2 \
  --machine-type n1-standard-1 \
  --zone us-central1-c

Une fois l'opération terminée, vous devez voir le cluster créé.

Creating cluster hello-cluster in us-central1-c...done.
Created [https://container.googleapis.com/v1/projects/mn-gke-test/zones/us-central1-c/clusters/hello-cluster].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-c/hello-cluster?project=mn-gke-test
kubeconfig entry generated for hello-cluster.
NAME           LOCATION       MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
hello-cluster  us-central1-c  1.9.7-gke.7     35.239.224.115  n1-standard-1  1.9.7-gke.7   2          RUNNING

Vous devriez maintenant disposer d'un cluster Kubernetes entièrement fonctionnel, optimisé par Google Kubernetes Engine:

d9e1e314769753e7.png

Vous pouvez à présent déployer votre application conteneurisée sur le cluster Kubernetes. À partir de maintenant, vous utiliserez la ligne de commande kubectl (déjà configurée dans votre environnement Cloud Shell). Pour le reste de cet atelier de programmation, les versions du client et du serveur Kubernetes doivent être 1.2 ou ultérieures. kubectl version affiche la version actuelle de la commande.

9. Déployer votre application sur Kubernetes

Un déploiement Kubernetes peut créer, gérer et faire évoluer plusieurs instances de votre application à l'aide de l'image de conteneur que vous venez de créer. Créons un déploiement de votre application dans Kubernetes à l'aide de la commande kubectl create deployment:

$ kubectl create deployment hello-micronaut \
  --image=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.1

Pour afficher le déploiement que vous venez de créer, exécutez simplement la commande suivante:

$ kubectl get deployments
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-micronaut   1         1         1            1           5m

Pour afficher les instances d'application créées par le déploiement, exécutez la commande suivante:

$ kubectl get pods
NAME                               READY     STATUS    RESTARTS   AGE
hello-micronaut-5647fb98c5-lh5h7   1/1       Running   0          5m

À ce stade, votre conteneur doit s'exécuter sous le contrôle de Kubernetes, mais vous devez quand même le rendre accessible depuis l'extérieur.

10. Autoriser le trafic externe

Par défaut, le pod n'est accessible que par le biais de son adresse IP interne au sein du cluster. Pour rendre le conteneur hello-micronaut accessible depuis l'extérieur du réseau virtuel Kubernetes, vous devez exposer le pod en tant que service Kubernetes.

Depuis Cloud Shell, vous pouvez exposer le pod à l'Internet public à l'aide de la commande kubectl expose associée à l'option --type=LoadBalancer. Cette option est obligatoire pour créer une adresse IP accessible depuis l'extérieur :

$ kubectl expose deployment hello-micronaut --type=LoadBalancer --port=8080

L'option utilisée dans cette commande spécifie que vous allez utiliser l'équilibreur de charge fourni par l'infrastructure sous-jacente (dans ce cas, l'équilibreur de charge Compute Engine). Remarquez que vous présentez le déploiement, et non le pod directement. Par conséquent, le service obtenu va répartir le trafic sur tous les pods gérés par le déploiement (dans le cas présent, un seul pod, mais vous ajouterez des instances répliquées par la suite).

Le Kubernetes maître crée l'équilibreur de charge et les règles de transfert Compute Engine associées, les pools cibles et les règles de pare-feu afin de rendre le service entièrement accessible en dehors de Google Cloud Platform.

Pour trouver l'adresse IP publiquement accessible du service, demandez simplement à kubectl de répertorier tous les services du cluster:

$ kubectl get services
NAME              TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
hello-micronaut   LoadBalancer   10.39.243.251   aaa.bbb.ccc.ddd 8080:30354/TCP   1m
kubernetes        ClusterIP      10.39.240.1     <none>          443/TCP          31m

Notez que deux adresses IP accessibles par le port 8080 sont répertoriées pour votre service. L'une est l'adresse IP interne visible uniquement au sein de votre réseau virtuel cloud. L'autre correspond à l'adresse IP externe avec équilibrage de charge. Dans cet exemple, l'adresse IP externe est aaa.bbb.ccc.ddd.

Vous devriez à présent pouvoir accéder au service en utilisant l'adresse suivante dans votre navigateur: http://<EXTERNAL_IP>:8080/hello

11. Assurer le scaling de votre service

Le scaling des applications, qui est une puissante fonctionnalité de Kubernetes, est simple à mettre en œuvre. Supposons que vous ayez soudainement besoin de davantage de capacité pour votre application. vous pouvez simplement demander au contrôleur de réplication de gérer un nouveau nombre d'instances répliquées pour vos instances d'application:

$ kubectl scale deployment hello-micronaut --replicas=3
deployment.extensions "hello-micronaut" scaled

$ kubectl get deployment
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-micronaut   3         3         3            3           16m

Notez l'approche déclarative utilisée ici : au lieu de démarrer ou d'arrêter de nouvelles instances, vous déclarez le nombre d'instances devant être en cours d'exécution. Les boucles de rapprochement Kubernetes permettent simplement de s'assurer que la réalité correspond à votre demande et de prendre des mesures si nécessaire.

12. Déployer une mise à niveau sur votre service

À un moment donné, des corrections de bugs ou de nouvelles fonctionnalités seront nécessaires sur l'application que vous avez déployée en production. Kubernetes va vous aider à déployer une nouvelle version en production, sans impact sur vos utilisateurs.

Commençons par modifier l'application. Ouvrez l'éditeur de code à partir de Cloud Shell.

5aee8f3d1e003571.png

Accédez à /jib/examples/micronaut/src/main/groovy/example/micronaut/HelloController.groovy et mettez à jour la valeur de la réponse:

@Controller("/hello")
class HelloController {
    @Get("/")
    String index() {
        "Hello Kubernetes World"
    }
}

Dans /jib/examples/micronaut/build.gradle, nous allons mettre à niveau la version de l'image 0.1 vers la version 0.2 en mettant à jour la ligne suivante:

version '0.2'

Ensuite, recompilez et empaquetez l'application avec les dernières modifications:

$ ./gradlew jibDockerBuild

Ajoutez un tag à l'image et transférez-la dans le registre d'images de conteneurs:

$ docker tag micronaut-jib:0.2 \
         gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2
$ docker push gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2

Vous êtes maintenant prêt à ce que Kubernetes mette à jour votre contrôleur de réplication de manière fluide et installe la nouvelle version de l'application. Pour modifier le libellé de l'image pour votre conteneur en cours d'exécution, vous devez modifier le fichier hello-micronaut deployment existant et remplacer l'image gcr.io/PROJECT_ID/micronaut-jib:0.1 par gcr.io/PROJECT_ID/micronaut-jib:0.2.

Vous pouvez utiliser la commande kubectl set image pour demander à Kubernetes de déployer la nouvelle version de votre application sur l'ensemble du cluster, une instance à la fois, avec une mise à jour progressive:

$ kubectl set image deployment/hello-micronaut \
          micronaut-jib=gcr.io/$GOOGLE_CLOUD_PROJECT/micronaut-jib:0.2

deployment.apps "hello-micronaut" image updated

Vérifiez à nouveau l'adresse http://EXTERNAL_IP:8080 pour vous assurer qu'elle renvoie bien la nouvelle réponse.

13. Rollback

Petit problème... Vous avez commis une erreur avec une nouvelle version de l'application ? La nouvelle version contient peut-être une erreur et vous devez effectuer rapidement un rollback. Avec Kubernetes, vous pouvez facilement revenir à l'état précédent. Effectuons un rollback de l'application en exécutant la commande suivante:

$ kubectl rollout undo deployment/hello-micronaut

Si vous examinez la sortie du service, nous reviendrons à notre premier « Hello World ». .

14. Résumé

Au cours de cette étape, vous avez configuré un service Hello World Micronaut simple basé sur Apache Groovy, puis vous l'avez exécuté directement dans Cloud Shell, l'avez empaqueté en tant que conteneur avec Jib et déployé sur Google Kubernetes Engine.

15. Félicitations !

Vous avez appris à créer et à déployer un nouveau microservice Web Apache Groovy / Micronaut dans Kubernetes sur Google Kubernetes Engine.

En savoir plus

Licence

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