BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles Les Nouveautés De Jakarta NoSQL, Partie 2 : Qu'est-Ce Que Le Cloud-Native ?

Les Nouveautés De Jakarta NoSQL, Partie 2 : Qu'est-Ce Que Le Cloud-Native ?

Points Clés

  • Qu’est ce que le Cloud Native ?
  • Les bonnes pratiques pour le Cloud Native
  • Jakarta dans le Cloud Native
  • Jakarta, NoSQL et Cloud Native

Le passage au Cloud Native

Le cloud computing a apporté de nombreuses méthodologies et techniques qui ont révolutionné à la fois le monde des affaires et le monde technique. Parmi les termes qui sont apparus, il y a celui de "Cloud Native". Pour répondre à ces attentes dans l'univers Java, Jakarta EE a vu le jour. Le but de cet article est de parler du concept de "Cloud Native" et d’exécuter une application avec ce concept en utilisant la dernière version de Jakarta EE NoSQL.

Qu'est-ce que le Cloud Native ?

Comme tout nouveau concept, il existe plusieurs concepts portant le même nom ; si vous lisez des livres ou des articles sur le Cloud Native, vous ne trouverez peut-être pas de consensus à ce sujet. Par exemple :

> Le "Cloud Native" est une approche de création et d’exécution d'applications qui exploite les avantages du modèle de l'informatique cloud.
Pivotal

> Développer d'abord pour le Cloud est une manière différente de penser les systèmes logiciels. Cela comprend les concepts suivants : comprendre que les applications sont déployées sur des infrastructures jetables, composées de modules aux fonctionnalités bien délimitées, dont la capacité de passer à l'échelle est globale et dont l'architecture elle-même est jetable.
Architecting Cloud Native Applications: Design high-performing and cost-effective applications for the cloud

> Dans l'usage général, le "Cloud Native" est une approche de création et d'exécution d'applications qui exploite les avantages du modèle de prestation de services de cloud computing. Le "Cloud Native" concerne la manière dont les applications sont créées et déployées, et non pas le lieu où elles le sont.
InfoWorld

Dans un consensus mutuel autour des définitions de plusieurs articles, on peut dire que "Cloud Native" est un terme utilisé pour décrire les environnements basés sur des conteneurs. Le terme "Cloud Native" n'est donc pas lié à des langages de programmation ou à des frameworks spécifiques, ni même à une entreprise fournisseur de services cloud, mais à des conteneurs.

Quelles sont les bonnes pratiques en matière de cloud ?

Lorsque nous commençons à apprendre un nouveau concept, nous courons généralement pour lire les meilleures pratiques afin d'éviter les erreurs et le code smell. Avec la programmation orientée objet (POO), nous avons les modèles de conception de la bande des quatre, en Java nous avons le livre Java efficace, et quand on parle d'architecture, nous avons à la fois le Clean code et la Clean architecture. La question est donc la suivante : quelles sont les meilleures pratiques pour le Cloud Native ?

À notre connaissance, il n'existe pas de bonnes pratiques concernant spécifiquement le Cloud Native. Mais comme le cloud est proche de la méthodologie Agile, il existe plusieurs pratiques dont nous pouvons tirer parti pour avoir une application saine et sans douleur :

  1. Manifeste pour le développement logiciel agile
  2. Intégration continue
  3. Déploiement continu
  4. Conception axée sur les domaines

Les pratiques les plus connues liées à toute application utilisant le cloud computing sont inspirées des ouvrages de Martin Fowler intitulés Patterns of Enterprise Application ArchitectureetRefactoring.

L'application à douze facteurs

  1. Codebase

Une base de code suivie avec un système de  contrôle de versions, plusieurs déploiements

  1. Dépendances

Déclarer explicitement et isoler les dépendances

  1. Configuration

Stocker la configuration dans l'environnement

  1. Services de backup

Considérer les services de backup comme des ressources liées

  1. Construire, livrer, exécuter

Des étapes de construction et d'exploitation strictement séparées

  1. Processus

Exécuter l'application comme un ou plusieurs processus stateless

  1. Association de ports

Exposer les services via des associations de ports

  1. Concurrence

Scalabilité via le modèle de processus

  1. Disponibilité

Maximiser la robustesse avec un démarrage rapide et un arrêt propre

  1. Parité dév/prod

Faire en sorte que les environnements de développement, de staging et de production soient aussi similaires que possible

  1. Logs

Traiter les logs comme des flux d'événements

  1. Procédures d’administration

Effectuer des tâches d'administration/gestion comme des processus uniques

En résumé, il n'existe pas encore de meilleures pratiques spécifiques pour le "Cloud Native", mais il est utile de suivre les modèles Agiles, de micro-services et de l'application à douze facteurs.

Revenons au code

Dans l'introduction, nous avons expliqué en détail ce que signifie "Cloud Native". Revenons maintenant à notre application et convertissons la en application Cloud Native. Dans le premier article, nous avons expliqué le modèle, l'entité et le fonctionnement de Jakarta NoSQL. Nous allons donc reprendre le tout et utiliser la méthode la plus simple pour traiter les requêtes avec NoSQL et MongoDB avec un repository.

import jakarta.nosql.mapping.Column;
import jakarta.nosql.mapping.Entity;
import jakarta.nosql.mapping.Id;

import javax.json.bind.annotation.JsonbVisibility;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;

@Entity
@JsonbVisibility(FieldPropertyVisibilityStrategy.class)
public class Hero implements Serializable {

	@Id
	private String name;

	@Column
	private Integer age;

	@Column
	private Set<String> powers;

}

 

import jakarta.nosql.mapping.Page;
import jakarta.nosql.mapping.Pagination;
import jakarta.nosql.mapping.Repository;

import java.util.stream.Stream;

public interface HeroRepository extends Repository<Hero, String> {

	Stream<Hero> findAll();

	Page<Hero> findAll(Pagination pagination);

	Stream<Hero> findByPowersIn(String powers);

	Stream<Hero> findByAgeGreaterThan(Integer age);

	Stream<Hero> findByAgeLessThan(Integer age);
}

Pour rendre ces services disponibles, nous allons créer dans l’application une classe de ressources avec JAX-RS.

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.function.Supplier;

import static java.util.stream.Collectors.toList;

@ApplicationScoped
@Path("heroes")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class HeroResource {

	private static final Supplier<WebApplicationException> NOT_FOUND =
        	() -> new WebApplicationException(Response.Status.NOT_FOUND);

	@Inject
	private HeroRepository repository;

	@GET
	public List<Hero> findAll() {
    	return repository.findAll()
            	.collect(toList());
	}

	@GET
	@Path("/{id}")
	public Hero findById(@PathParam("id") String id) {
    	return repository.findById(id).orElseThrow(NOT_FOUND);
	}

	@GET
	@Path("seniors/{age}")
	public List<Hero> findByOlder(@PathParam("age") Integer age) {
    	return repository.findByAgeGreaterThan(age)
            	.collect(toList());
	}

	@GET
	@Path("youngs/{age}")
	public List<Hero> findByYounger(@PathParam("age") Integer age) {
    	return repository.findByAgeLessThan(age)
            	.collect(toList());
	}

	@POST
	public void save(Hero hero) {
    	repository.save(hero);
	}

	@PUT
	@Path("/{id}")
	public void update(@PathParam("id") String id, Hero hero) {
    	repository.save(hero);
	}

	@Path("/{id}")
	@DELETE
	public void delete(@PathParam("id") String name) {
    	repository.deleteById(name);
	}
}

L'application est prête ; la dernière étape que nous allons créer est la classe de configuration qui permet la connexion avec MongoDB. C'est simple, nous utiliserons Eclipse MicroProfile Configuration qui a des capacités d'intégration étroites avec Eclipse JNoSQL, l'implémentation de référence de Jakarta NoSQL. Eclipse MicroProfile Configuration est une solution pour externaliser la configuration des applications Java et rend le troisième facteur facile à suivre.

import jakarta.nosql.document.DocumentCollectionManager;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;

@ApplicationScoped
class DocumentManagerProducer {

	@Inject
	@ConfigProperty(name = "document")
	private DocumentCollectionManager manager;

	@Produces
	public DocumentCollectionManager getManager() {
    	return manager;
	}

	public void destroy(@Disposes DocumentCollectionManager manager) {
    	manager.close();
	}
}

La configuration actuelle d'une application est accessible via ConfigProvider#getConfig().

Une Config est constituée des informations recueillies auprès des org.eclipse.microprofile.config.spi.ConfigSources enregistrés. Ces ConfigSources sont triées selon leur ordre. De cette façon, nous pouvons écraser la configuration de moindre importance depuis l'extérieur.

Par défaut, il y a 3 ConfigSources :

  1. System.getProperties() (ordinal=400)
  2. System.getenv() (ordinal=300)
  3. Tous les fichiers META-INF/microprofile-config.properties présents dans le ClassPath. (default ordinal=100, configurable séparément via une propriété config_ordinal à l'intérieur de chaque fichier)

Par conséquent, les valeurs par défaut peuvent être spécifiées dans les fichiers ci-dessus fournis avec l'application et la valeur peut être écrasée ultérieurement pour chaque déploiement. Un nombre ordinal supérieur est prioritaire sur un nombre inférieur.

Cela implique que nous pouvons avoir la configuration pour l'environnement local sous forme de fichier, une pour tester également sous forme de fichier, et enfin nous pouvons passer outre toutes ces informations lorsque nous les déplaçons vers le cloud.

document=document
document.database=conferences
document.settings.jakarta.nosql.host=localhost:27017
document.provider=org.eclipse.jnosql.diana.mongodb.document.MongoDBDocumentConfiguration

Nous avons maintenant une configuration locale, donc déplaçons notre application avec Jakarta EE basée sur l'approche "Cloud Native". Pour faciliter les choses, nous utiliserons une plateforme en tant que service (PaaS) car vous pouvez déplacer votre application en mode conteneur dans le cloud par le biais d'une infrastructure as code (IaC).

L'infrastructure as code, ou infrastructure programmable, signifie l'écriture de code, qui peut être faite en utilisant un langage de haut niveau ou tout langage descriptif pour gérer les configurations et automatiser l'approvisionnement de l'infrastructure en plus des déploiements.

Platform.sh

L'application Java est prête à fonctionner ! L'étape suivante consiste à définir les fichiers Platform.sh nécessaires à la gestion et au déploiement de l'application. Dans notre article sur Java avec Platforme.sh, nous avons détaillé chacun de ces trois fichiers en détail :

  1. Un pour le routage (.platform/routes.yaml). Platform.sh vous permet de définir les routes.
  2. Zéro ou plusieurs pour les conteneurs de service (.platform/services.yaml). Platform.sh vous permet de définir et de configurer entièrement la topologie et les services que vous souhaitez utiliser dans votre projet.
  3. Un ou plusieurs pour les conteneurs d'application (.platform.app.yaml). Vous contrôlez votre application et la façon dont elle sera construite et déployée sur Platform.sh via un seul fichier de configuration.

Le fichier qui va changer dans cet article est le fichier de services, qui permet de définir une base de données, un moteur de recherche, un cache, etc. Pour ce projet, nous allons définir MongoDB au lieu de MySQL.

mongodb:
	type: mongodb:3.6
	disk: 1024

Pour lire la configuration de l'environnement, Platform.sh propose un lecteur de configuration qui permet une intégration facile. Platform.sh fonctionne également avec un ensemble de frameworks et de langages, dont Java. Dans cet article, nous allons remplacer la configuration MongoDB par les propriétés Java qui ajouteront de la transparence à l'application, grâce à Eclipse MicroProfile Configuration. Avec ces fichiers prêts et déployés vers le master, Platform.sh créera un ensemble de conteneurs au sein d'un cluster.

# This file describes an application. You can have multiple applications
# in the same project.
#
# See https://docs.platform.sh/user_guide/reference/platform-app-yaml.html

# The name of this app. Must be unique within a project.
name: app

# The runtime the application uses.
type: "java:8"

disk: 800

# The hooks executed at various points in the lifecycle of the application.
hooks:
  build: |
	wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
	mv jq-linux64 jq
	chmod +x jq
	mvn -U -DskipTests clean package payara-micro:bundle

# The relationships of the application with services or other applications.
#
# The left-hand side is the name of the relationship as it will be exposed
# to the application in the PLATFORM_RELATIONSHIPS variable. The right-hand
# side is in the form `<service name>:<endpoint name>`.
relationships:
  mongodb: 'mongodb:mongodb'

# The configuration of app when it is exposed to the web.
web:
  commands:
	start: |
  	export MONGO_PORT=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|./jq -r ".mongodb[0].port"`
  	export MONGO_HOST=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|./jq -r ".mongodb[0].host"`
  	export MONGO_ADDRESS="${MONGO_HOST}:${MONGO_PORT}"
  	export MONGO_PASSWORD=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|./jq -r ".mongodb[0].password"`
  	export MONGO_USER=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|./jq -r ".mongodb[0].username"`
  	export MONGO_DATABASE=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|./jq -r ".mongodb[0].path"`
  	java -jar -Xmx1024m -Ddocument.settings.jakarta.nosql.host=$MONGO_ADDRESS \
  	-Ddocument.database=$MONGO_DATABASE -Ddocument.settings.jakarta.nosql.user=$MONGO_USER \
  	-Ddocument.settings.jakarta.nosql.password=$MONGO_PASSWORD \
  	-Ddocument.settings.mongodb.authentication.source=$MONGO_DATABASE \
  	target/heroes-microbundle.jar --port $PORT

L'application est maintenant prête, il est donc temps de la déplacer vers le cloud avec Platform.sh en suivant les étapes suivantes :

  1. Créez un nouveau compte d'essai gratuit.
  2. Inscrivez-vous avec un nouveau nom d'utilisateur et un nouveau mot de passe, ou connectez-vous en utilisant un compte GitHub, Bitbucket ou Google existant. Si vous utilisez un identifiant tiers, vous pourrez définir un mot de passe pour votre compte Platform.sh ultérieurement.
  3. Sélectionnez la région du monde où vous souhaitez que votre site vive.
  4. Sélectionnez une template vierge.

 

Après cet assistant, Platform.sh vous fournira toute l'infrastructure, et il offrira à votre projet un repository Git à distance. L'infrastructure Platform.sh pilotée par Git signifie qu'elle gérera automatiquement tout ce dont votre application a besoin pour la déployer vers le repository master à distance. Après avoir configuré vos clés SSH, il vous suffit d'écrire votre code - y compris quelques fichiers YAML qui spécifieront l'infrastructure souhaitée - puis de faire une commit Git, et de le déployer.

git remote add platform <platform.sh@gitrepository>
git commit -m "Initial project"
git push -u platform master

Dans cet article, nous avons parlé des principes et des meilleures pratiques concernant le "Cloud Native", qui est encore un domaine qui doit être amélioré puisqu'il s'agit d'une nouvelle technique de développement de logiciels. Le cloud facilite le développement de logiciels, et nous pouvons voir une application fonctionnant tout simplement grâce à Platform.sh et intégrée à Jakarta EE. Tout cela pour dire que c'est le moment idéal (bonne année !) pour transférer votre projet vers un PaaS cloud mature comme Platform.sh.

 

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT