ous avons participé au Devoxx France 2018 qui s’est déroulé du 18 au 20 avril 2018. Dans cet article, nous allons vous présenter quelques conférences intéressantes que nous avons pu suivre. Ces retours sont basés sur notre compréhension personnelle, chacun est accompagné de la présentation YouTube. Libre à vous de les regarder pour vous forger votre propre opinion !
Cloud Native Spring, chapitre deux
Josh Long
Josh nous a donné un très bon aperçu des possibilités offertes par Spring Cloud. Il a commencé par évoquer le fait qu’il existe deux problèmes principaux lorsqu’on veut s’attaquer aux microservices. Le premier est le temps; il existe beaucoup d’outils différents il faut donc prendre le temps de bien les choisir, ce que nous n’avons pas forcément. Le deuxième est la communication entre les microservices.
Josh nous a ensuite réalisé une démonstration de deux microservices complètement réactifs communicants entre eux. Il nous a monté les streams réactifs, le driver réactif pour MongoDB et Spring Actuator pour les métriques.
Il évoque également les possibilités qui s’offrent à nous avec Spring Cloud, à savoir l’utilisation de service registry avec Netflix Eureka, de rate limiter avec Redis, de circuit breaker avec Hystrix, de messaging avec Kafka. Spring peut également fournir un serveur de configuration qui centralise toutes les propriétés de nos applications et permet notamment l’utilisation de feature flags.
Reactive Spring
Juergen Hoeller et Josh Long
Cette présentation était pour ainsi dire un résumé de la précédente, “Cloud Native Spring, Chapitre deux”. La différence était que sa durée était de seulement 45 minutes, contre 3 heures pour l’autre. Vous pouvez regarder une des deux vidéos en fonction de votre temps disponible, celle de 3 heures étant évidemment plus poussée dans les explications.
Migrer à Spring Boot 2 lorsque l’on a une “vraie” application
Julien Dubois
Julien nous a présenté les problématiques rencontrées par JHipster lorsqu’ils ont migré de Spring Boot 1 vers la version 2.
- Il a fallu dans un premier temps migrer les librairies tierces afin quelles soient compatibles avec la dernière version de Spring.
- Une migration des fichiers properties a également été nécessaire, car certaines propriétés ont été renommées.
- Le format JSON de retour de Spring Actuator a été modifié, il a donc fallu adapter les outils qui l’utilisait.
- Spring Data a subi quelques changements d’API et utilise maintenant les Optionals.
En plus de ces modifications plus ou moins coûteuses en refactoring, de nouveaux outils sont apparus et ont été pris en compte dans leur migration. Il s’agit de Spring Webflux qui permet une programmation réactive, Spring Security supportant également la programmation réactive ainsi qu’OAuth 2. Micrometer, pour de la gestion de monitoring, a aussi été mis à disposition.
Spring Cloud quant à lui n’a pas pour l’instant eu d’impact. Toutefois, sa version supportant Spring Boot 2 n’est pas encore sortie officiellement.
Dans l’ensemble, le coût de refactoring a été assez cher et plus encore il a fallu tester de nouveau toute l’application.
Glowroot, le petit APM qui vous veut du bien
Henri Gomez
Henri nous a présenté l’Application Performance Management (APM) Java Glowroot. Contrairement à la plupart des APM, celui-ci est open source et gratuit. Son overhead est inférieur à 100 µs et sa consommation mémoire minime.
Glowroot a deux modes de fonctionnement. Le mode autonome en spécifiant seulement le chemin du jar au lancement du serveur, ou le mode centralisé qui nécessite une base Cassandra et permet de monitorer une ferme d’applications.
Il comporte l’ensemble des fonctionnalités attendues d’un APM comme l’affichage des slow traces. Il fonctionne avec tout protocole, frameworks et serveurs d’application.
Java dans Docker : Bonnes pratiques
Charles Sabourdin et Jean-Christophe Sirot
Charles et Jean-Christophe nous ont parlé d’un ensemble de bonnes pratiques pour utiliser des applications Java avec Docker. La présentation était axée sur la gestion de la mémoire.
Le paramètre “memory” peut être utilisé au démarrage d’un conteneur Docker afin de spécifier le montant maximum de RAM qu’il peut utiliser. Il est conseillé de l’utiliser, ainsi que le paramètre “memory-swappiness” afin de désactiver le swap qui diminuerait grandement les performances.
Côté Java, la gestion de ressources dans un conteneur a été amélioré en Java 9 et backporté en Java 8u131. Toutefois, il est nécessaire d’utiliser les flags UnlockExperimentalVMOptions et UseCGroupMemoryLimitForHeap. En Java 10, la fonctionnalité est stable et activé par défaut.
Tous ces principes s’appliquent également pour la gestion de ressources CPU.
Container security tips for developers
Justin Cormack
Justin nous a donné un ensemble de conseils de sécurité pour l’utilisation des conteneurs avec Docker.
Docker est plutôt bien sécurisé par défaut, il y a toutefois un ensemble de bonnes pratiques à suivre pour éviter tout désagrément. Il est recommandé de toujours utiliser des images officielles. Il faut privilégier par exemple les images Java officielles plutôt que celles réalisées par une personne lambda. Les images officielles sont régulièrement mises à jour pour patcher des vulnérabilités, donc il faut également veiller à mettre à jour nos images qui se basent dessus.
Il est conseillé de signer nos images afin d’être sûr que le cluster de production récupère bien une image reconnue qui a été buildée par notre serveur d’intégration continue. Il est également possible et utile de scanner régulièrement les images utilisées afin d’y trouver des vulnérabilités connues et pouvoir les corriger.
Enfin, il faut éviter de commiter les secrets de nos applications sur GIT ainsi qu’utiliser les variables d’environnement et privilégier plutôt l’utilisation de Vault ou des systèmes intégrés à Docker et Kubernetes pour gérer identifiants et mots de passe.
Les 12 factors Kubernetes
Etienne Coutaud
Etienne nous a présenté sa version des Twelve-Factor App appliqués à Kubernetes.
Les bonnes pratiques à suivre pour déployer des applications dans un cluster Kubernetes sont les suivantes :
- Il faut garder en tête qu’un Pod signifie un ou plusieurs conteneurs.
- Utiliser les labels à profusion. Cela permettra de gérer plus facilement un cluster qui comporte des dizaines, voire des centaines de pods. Chaque commande Kubernetes peut être exécutée en précisant un namespace ou un label et ainsi cibler son impact.
- Les fichiers de configuration YAML de Kubernetes doivent être traités comme du code et versionnés. De plus, la commande apply pourra être utilisée sur un ensemble de fichier et Kubernetes se chargera d’appliquer uniquement ce qui a été modifié.
- Les services permettent d’exposer des pods et de gérer du load balancing.
- Utiliser les ConfigMaps et Secrets pour gérer les identifiants de nos applications. Ils seront ensuite injectés et accessibles depuis nos pods.
- Utiliser les requests et limits pour gérer les ressources de notre cluster.
- Les pods doivent être déployés via un fichier de Deployment et non pas directement en tant que pod. Dans le cas contraire, aucun ReplicaSet ne sera créé, leur cycle de vie de ne sera pas correctement géré et ils ne pourront pas être redémarrés automatiquement en cas de problème par exemple.
- Utiliser les paramètres LivenessProbe et ReadinessProbe. Le premier permet à Kubernetes de savoir lorsqu’un pod a bien été démarré et le second de savoir lorsqu’il est réellement prêt à être utilisé (après une connexion à une base de données par exemple).
- Ne pas utiliser la version “latest” pour les images. Privilégier plutôt l’id de commit GIT par exemple. Cela permettra de savoir plus facilement quelles fonctionnalités et corrections sont disponibles en production.
- Les pods sont stateless et éphémères. Il faut donc y penser lors du développement de l’application. S’il est nécessaire de garder une session par exemple, il faudra utiliser un pod explicitement déclaré statefull et contenant une base Redis.
- Les volumes doivent être montés sur des stockages distribués. Vu que nos pods sont stateless, toute donnée sera perdue à leur redémarrage. Il faut donc configurer le pod pour qu’il ait accès à des volumes mis à disposition généralement par notre fournisseur Cloud.
- Les microservices déployés doivent suivre les Twelve-Factor App.
Docker, Kubernetes et Istio, c’est utile pour mon monolithe ?
David Gageot
David nous a présenté une transformation de l’application classique “Pet Store” en microservices.
Il a commencé par la création d’une image Docker pour l’application afin de pouvoir la déployer dans un cluster Kubernetes. La configuration pour ce déploiement se présente sur la forme de fichiers YAML.
La première étape de la migration consiste à intégrer un conteneur Nginx et un conteneur contenant l’application dans un même pod Kubernetes. Le conteneur Nginx est embarqué en mode “sidecar” et permet d’intercepter les requêtes du Pet Store afin de les compresser, ainsi que faire de la réécriture d’URL.
La deuxième étape consiste à ajouter un autre sidecar, Envoy. Il s’agit d’un proxy qui va être rajouté automatiquement par le service mesh nommé Istio. Ce dernier ajoute un grand nombre de fonctionnalités à Kubernetes. Il va permettre notamment de chiffrer les communications entre chaque microservice grâce à Istio Auth. Cet ajout de proxy en sidecar de chaque pod va également permettre à Istio Mixer d’agréger des métriques et les envoyer à Prometheus et Grafana afin d’avoir un dashboard d’analyse de notre cluster.
Istio a un grand nombre d’autres fonctions. Il est possible de l’utiliser pour gérer des déploiements en blue/green, timeouts, retries, health checks, mirroring, circuit breaker, rate limits, telemetry, reporting, traces distribuées avec Zipkin, etc.
Avec toutes ces fonctions, il est possible de migrer graduellement une application legacy vers des microservices.
Troubleshooting & Debugging Production Microservices in Kubernetes
Ray Tsang et Baruch Sadogursky
Ray et Baruch nous ont présenté des pistes afin de débugger des microservices en production sous Kubernetes.
Côté best practices pour faciliter l’analyser, il est conseillé de ne pas utiliser la version “latest” pour les images, mais plutôt l’id du commit GIT par exemple. Partant d’une application ne suivant pas ce conseil, ils ont dans un premier temps comparé les hashs des images Dockers avec la version précédente, ainsi que le hash du jar embarqué dans le conteneur afin de pouvoir connaître la version réelle de l’application qui tourne en production.
Les logs des pods sont redirigés sur la sortie standard. Comme il peut avoir un grand nombre de pods répliqués sur plusieurs serveurs, il existe des outils comme stern ou ktail qui permettent d’agréger les logs de tous les pods d’un même ReplicaSet. Dans le meilleur des cas, nous pouvons utiliser par exemple une stack ELK qui va permettre de centraliser tous les logs sur Kibana.
Une fois le pod défaillant ciblé, il est possible de le sortir du cluster afin de l’analyser plus en détails. Il est possible de tracer précisément la requête effectuée avec l’aide de Zipkin.
Enfin, l’utilisation du Google Cloud Engine (GKE), pour gérer notre cluster Kubernetes, permet d’avoir accès à ensemble d’outils facilitant le debugging. Nous pouvons noter par exemple le debugger de GKE qui permet d’ajouter à la volée des logs dans le code s’exécutant en production grâce à de la bytecode instrumentation.
Du mutualisme à l’Open Source
Alexandre Delègue Mathieu Ancelin et François Desmier
Alexandre, Mathieu et François nous ont parlé de la transformation de leur entreprise, la MAIF, ainsi que du développement de certains outils open sources.
La MAIF est une société d’assurance qui s’est rendu compte que sans évoluer, elle était vouée à disparaître. En effet, nous pouvons imaginer que d’ici quelques années le besoin d’assurance sera moins nécessaire, notamment grâce (ou à cause, selon le point de vue) aux voitures autonomes qui vont se démocratiser. Dans tous les cas le modèle actuel va évoluer et l’entreprise se doit également d’évoluer. Une diversification est nécessaire.
Dans cette optique, la MAIF a sorti déjà deux outils open sources : Otoroshi et Izanami.
Otoroshi est un outil permettant de gérer API management, circuit breaker, load balancing, throttling, quotas et métriques. Il dispose également d’une interface d’administration REST et web.
Izanami est un outil permettant de gérer feature flipping, configuration partagée et tests A/B.
D’autres outils sont en préparation et l’ensemble de ce qui a été développé permet une gestion facilitée des architectures microservices.
Using Kubernetes for Continuous Integration and Continuous Delivery
Carlos Sanchez
Carlos nous a présenté un workflow d’intégration continue et déploiement continu via l’utilisation de Jenkins X, qui s’appuie sur Kubernetes. Le workflow peut s’effectuer de la manière suivante : un push puis une pull request sont effectués sur GitHub, un build Jenkins est automatiquement déclenché, s’il passe correctement le merge de la pull request est fait, enfin d’un clic de bouton l’application est déployée dans l’environnement choisi.
Jenkins X se compose également d’un grand ensemble de plugins et permet d’automatiser certaines tâches liées au déploiement d’une nouvelle version comme la génération automatique de changelog.
Maitriser sa gestion de l’identité avec Keycloak
Lilian Benoit Thomas Recloux et Sebastien Blanc
Lilian, Thomas et Sébastien nous ont présenté Keycloak et ses possibilités en profondeur. Il s’agit d’une solution open source permettant de faciliter la gestion de l’authentification et de l’identité de nos applications. Il supporte les protocoles OpenID Connect 1.0, OAuth 2.0 et SAML 2.0.
Le principe d’OAuth 2 est de récupérer un authorization code, puis un access token, puis utiliser ce dernier pour s’authentifier.
OpenID Connect permet d’allier OAuth 2 et JWT. Ce dernier consiste en un header, un payload et une signature. Le payload peut être utilisé pour passer n’importe quel type d’information (non compromettante) utile à notre application. En comparaison avec OAuth 2, OpenID Connect est un protocole d’authentification et d’autorisation complet.
Une bonne pratique dans la gestion des tokens est de faire des access token à durée de vie courte (quelques minutes). Un refresh token, avec durée de vie beaucoup plus longue, permet ensuite de récupérer un nouvel access token valide. Ceci permettra par exemple qu’au bout de quelques minutes, les droits éventuellement mis à jour d’un utilisateur soient pris en compte à la régénération d’un access token.
Le SAML 2.0, beaucoup plus ancien pour sa part, car défini en 2005, permet notamment l’échange d’information d’authentification entre partis. Il permet une gestion du SSO et il n’est pas uniquement utilisable en HTTP, car il s’agit simplement d’un format XML.
Pour ce qui est de Keycloak lui-même, il se compose de Realms et de Clients. Un client sera une application et le realm sera l’entité regroupant nos différentes applications qui ont un certain lien entre elles, comme la nécessité d’utiliser du SSO.
La customisation est très poussée sur tout ce qui touche à l’authentification. A titre d’exemple, les fonctionnalités pouvant être activées sont : rester connecté, mot de passe oublié, enregistrement, captcha, vérification d’email, protection brute force, politique de mot de passe, double authentification, etc.
En plus d’une bonne intégration à Spring Boot et Spring Security, un ensemble d’adaptateurs sont fournis, ainsi qu’un proxy fonctionnant en mode “sidecar”, sur le même principe qu’Istio dans un cluster Kubernetes.
Keycloak est ainsi une solution complète fournissant toutes les fonctionnalités nécessaires pour la gestion de l’authentification et des droits de nos applications.
Chaos Engineering, principes et mise en application
Benjamin Gakic
Benjamin nous a présenté le Chaos Engineering, initié par Netflix, et sa mise en application chez OUI.sncf.
Dans une situation chaotique, habituellement nous agissons d’abord, puis observons et enfin seulement répondons au problème. Le but va être d’éviter de se retrouver dans ce genre de situation en la provoquant nous-même et la résolvant. Le chaos engineering est non déterministe et s’effectue en production. Il s’agit de faire de l’expérimentation sur un système distribué afin de renforcer notre confiance dans la capacité du système à résister à des conditions turbulentes.
D’après de récents sondages, la sécurité devient maintenant moins prioritaire pour les entreprises que le downtime de leur application. Les indisponibilités sont de plus en plus médiatisées et font de la mauvaise publicité. Deux exemples récents sont OVH et GitLab qui ont chacun eu un épisode de downtime important très médiatisé.
Pour faire du Chaos Engineering, plusieurs outils sont à notre disposition, le premier étant Chaos Monkey. Pour simuler des pannes, cet outil va mettre hors service des instances de production de manière aléatoire. Les autres outils disponibles sont notamment Latency Monkey, Fill Disk Monkey, Process Killer Monkey, Properties Monkey, etc. Chacun va tenter de “casser” nos applications d’une manière différente afin de cibler des vulnérabilités dans notre architecture et pouvoir les corriger avant qu’elles ne se produisent réellement.
En plus de mettre ces outils en place, d’abord en pré-production, OUI.sncf met en place des journées “Game day” dont le but est également de trouver des vulnérabilités. Des équipes d’opérateurs se chargent de “casser” l’environnement de différentes façons et des équipes de développeurs doivent ensuite arriver à les détecter, diagnostiquer puis les résoudre le plus rapidement possible.
Lighthouse: mesurer et améliorer votre performance web
Sara Harkousse et Philippe Antoine
Sara et Philippe nous ont présenté Lighthouse. Celui se présente sous la forme d’un module NodeJS, ou bien directement intégré dans les DevTools de Google Chrome.
Lighthouse permet d’analyser une page web et fourni un ensemble d’indicateurs sur celle-ci, avec un score sur 100 pour chacun. Les indicateurs sont les suivants :
- Performances
- Progressive Web App
- Best practices
- Accessibility
- SEO
Pour chaque amélioration possible, une todo list est proposée avec des conseils sur les mesures à mettre en place ou ce qu’il faudrait ajouter/modifier sur notre site.
Parmi les aides proposées, on peut noter par exemple un scan automatique des librairies utilisées (fourni via Snyk). Pour le reste, les DevTools permettent également d’améliorer performances et accessibilité.
Réconciliez vous avec le JS grâce à Flow
Trung Nguyen
Trung nous a fait un tour rapide des fonctionnalités proposées par Flow. Il s’agit d’un vérificateur de type statique, développé et largement utilisé par Facebook.
Une fois le module NPM installé, Flow pourra analyser les fichiers de notre projet annotés avec // @flow. Il nous présentera un ensemble de warnings et d’erreurs permettant de détecter des bugs avant le runtime. Pour cela, Flow fait du type checking en essayant d’inférer les types.
Flow apporte également un ensemble de syntaxes supplémentaires au JavaScript afin de définir nous-même les types utilisés.
Accélerez vos tests end-to-end avec Cypress
Rodolphe Bung
Rodolphe nous a présenté un outil de test end-to-end nommé Cypress. Contrairement à Selenium, il est exécuté directement dans le navigateur et permet par conséquent une meilleure gestion des applications single page.
Cypress est centré sur l’expérience développeur. Son installation et son API sont simples. Il propose en plus des fonctionnalités très utiles telles que le live reload, le mocking, la mise à disposition automatique de vidéos des tests effectués, des tests de régression visuelle et des tests unitaires de composants React et Vue.js. Des plugins sont également disponibles.
Le seul reproche qui pourrait lui être fait actuellement est qu’il ne soit pas multi-navigateur. Il fonctionne uniquement sur Google Chrome, mais le développement sur d’autres navigateurs est en cours.
GraphQL vs Traditional Rest API
Vladimir Dejanovic
Vladimir nous a présenté le langage de requête pour APIs nommé GraphQL. Cette spécification a été décrite par Facebook en 2012 puis publiée en 2015. Comme il s’agit d’une spécification, chaque implémentation peut différer et ne pas forcément implémenter toutes les fonctions possibles.
Une API REST classique est basée sur une architecture client-serveur, est stateless, est cacheable, a une interface uniforme entre le client et le serveur.
Une API GraphQL possède également ces fonctionnalités et aura en plus notamment un schéma disponible. Ce schéma définira toutes les opérations possibles sur l’API; les query (de la lecture de données) et les mutations (de la modification de données). L’avantage d’avoir ce schema est de pouvoir savoir exactement ce qui est disponible et d’ainsi d’avoir une documentation.
Les clients appelant une API GraphQL choisissent quels objets et quels champs récupérer. Contrairement à REST, le client peut donc utiliser l’API comme il le souhaite en fonction de ses besoins, sans avoir forcément à appeler plusieurs endpoints pour récupérer des sous objets. Comme le client a plus de liberté, il existe des mécanismes de protection pour éviter qu’une requête soit beaucoup trop lourde à exécuter, à savoir des timeouts, des niveaux maximum de profondeur pour récupérer des objets enfants, des niveaux maximum de complexité et du throttling.
Certaines implémentations peuvent aussi fournir un système de souscription pour que le client soit alerté lorsqu’une donnée est modifiée.