Docker, Kubernetes et Istio

Docker, K8s (j’abrège, hein, parce que bon) sont souvent présentés pour les microservices, mais ça marche aussi avec les applications un peu plus grosses. C’est ce que David va montrer avec le petstore version A. Goncalvez.

Dockeriser

Pou ça, David construit son image Docker avec un multi-stage build (toujours impressionant pour le dockeriste débutant comme moi). Et paf, l’application est conteneurisée.

Lancer dans un cluster K8s

Vous connaissez Kubernetes ? ? non ? bon, David a une surprise pour vous

Avec K8s, on peut prendre un cluster de machines et travailler dessus sans trop s’en soucier. Pour lancer notre application, on crée deux descripteurs yaml (ouch, j’aime aussi peu que David).
  1. Un déploiement (qui décrit l’application à déployer)
  2. Un service (qui route le port 80 vers notre application – à la traefik/https://nginx.org/[nginx]/https://getkong.org/[kong]/https://www.sozu.io/[sozu]/…​.)

Et paf, on déploie. L’explication sur le mode de fonctionnement de K8s est un peu louche (à base de boucles de contrôle qui réconcilient des états souhaités/actuels).

Organisation

La CLI de K8s permet d’avoir des informations sur l’état du cluster, et nous montre par exemple que l’application tourne dans un pod. Si ce pod est détruit, K8s en relance un nouveau, et y redéploie l’application. C’est très très cool. On peut aussi facilement déployer l’application dans plusieurs pods, pour faire de la redondance dans ce que ça a de plus vrai : arrêter ou perdre un pod n’a aucun impact sur l’autre.

Améliorer l’appllication de l’extérieur

David ajoute maintenant un proxy nginx pour gzipper le flux, ajouter une page 404 et réécrire les urls. Pour ça, il suffit d’ajouter le proxy dans le pod de l’application. Ca veut dire un déploiement et un service décrivant nginx, un dockerfile et enfin fichier de configuration pour nginx. La particularité, c’est que nginx reroute vers localhost (ce qui n’est pas le cas quand on joue classiquement avec des conteneurs). Parce que nginx et petstore seront forcément déployées sur la même machine. Enfin, en ajoutant un ingress, il est possible de créer un nom de domaine spécifique devant le nginx. C’est vachement pratique, parce que pendant ce temps-là, petstore n’a pas changé.

Istio

Istio reprend précisément ce principe en ajoutant des facades envoy (un proxy C++) devant toutes les applications. Le proxy est configurable.

Premier apport : Istio transforme tous les flux en HTTPS. C’est dingue. C’est à la fois génial et affreux : comment débugger le traffic ?

Grâce à envoy, Istio fournit de monitoring de tous les services avec les temps de réponse,

David passe à une démo où les deux versions de l’application sont déployées côte à côte avec des urls différentes. Et grâce au smart routing d’Istio, on peut faire du blue-green deployment. Alors qu’avec K8s, c’est impossible. Bon, apparement, il y a d’autres solutions (de mémoire, OpenShift le fait aussi comme l’avait montré Clément Escoffier précédement). Pour vérifier qu’on a bien du blue-green, David affiche un dashboard grafana (installé par Istio) en ouvrant un tunnel de sa machine vers le composant Grafana (assez spectaculaire). Et ça marche ! On a bien 20% d’utilisateurs en v2 et 80% en v1.

Routage

Et maintenant, il est temps de tout réécrire. David va donc séparer l’application en plusieurs services, qui utiliseront toujours les routes de l’application initiale. Pour ça, le smart routing d’Istio est pratique …​ mis à part le fait qu’il y a de plus en plus de contenu YAML. Donc on a deux composants, qui se parlent à travers le réseau. Et forcément, avec le réseau, les problèmes arrivent. Heureusement, Istio va nous aider pour survivre à ça. D’abord grâce à un graphe des services (auquel on se connecte comme Grafana grâce à un tunnel temporaire). Et là, trop bien …​ mais trop moche …​ le graphe est généré par Grafviz (mais la version plus récente utilise D3.js).

Gestion du réseau

Encore une fois, grâce au proxy envoy, on peut configurer finement chaque composant pour, par exemple, simuler des timeouts. Ou de mirrorer le trafic de prod vers une application non utilisée en prod, mais qui en recevra la charge. Ou encore d’industrialiser les circuit breakers en les plaçant au niveau d’envoy. Ou encore de gérer la sécurité sans passer par les notions classiques et pénibles de zones de sécurité réseau, mais en utilisant une gestion de la sécurité par rôle. C’est vraiment chouette parce que ça permet d’optimiser le nombre de serveurs. Ca permet également, grâce à la télémétrie, de voir quel composant appelle quel autre service. Pour ceux qui connaissent, ça ressemble vachement à Dynatrace dans l’idée.

Rate limiting

En particulier, il est possible de limiter les appels à un service pour qu’il ne soit pas noyé sous la charge. Malheureusement, encore une fois, il faut des paquets de YAML.

Conclusion

J’ai loupé la séance de questions, parce que je devais aller chercher les bières, mais c’est pas grave, lançons-nous. Docker est un outil un peu chiant, mais très pratique pour les petits ops. Docker est aussi issu d’idées (conteneurs et c-groups) sur lesquels Google bosse depuis …​. des années. Donc forcément, leur outil de gestion de flotte intègre un niveau de complexité supérieur (l’abstraction des pods semble par exemple pratique, mais délicate à aborder). Et évidement, c’est difficile à comprendre pour un non averti comme moi. En revanche, cette complexité permet le déploiement d’outils comme istio, qnui est la killer feature de K8s. Rien que pour donner un exemple, il semble possible pour une entreprise de se débarasser de Dynatrace (dont les licences tournent autour de 100000€/serveur/an). Sans compter toutes les possibilités de debug qui sont, dans le monde des conteneurs, aussi indispensables qu’introuvables. Autrement dit, K8s me tente peu, mais Istio le rend supportable.

Publicités

Comment est-ce que je gère mes services avec Rancher et Consul ?

Mais pourquoi je veux faire ça ?

Admettons que je veuille me mettre aux microservices … ou plutôt aux services packagés dans des conteneurs docker (quelquesoit la taille des dits services).

Je commence par les packager dans des conteneurs Docker et c’est « cool ». Parce que comme ça, je n’ai pas besoin de demander à l’admin sys de déployer du Java partout, mais du Docker.

Donc, j’ai mes services et mon admin a entendu parler (sans doute sur ce blog) d’un chouette truc qui s’appelle Rancher. Et très vite, il veut ajouter une base de données de configuration (parce que mettre les fichiers de config dans les conteneurs, c’est pas terrible … lisez donc 12 factors apps à ce sujet). Donc il me dit d’utiliser Consul. Et Consul, c’est bien pour la config, mais ça fait aussi service registry. C’est-à-dire que ça permet à un service d’en trouver un autre dynamiquement. Un peu comme du JNDI pour les Javaistes … ou du LDAP pour les ancêtres.

Le problème, c’est que Consul fait service registry, et pas service discovery. C’est-à-dire qu’il peut stocker les services, mais pas découvrir quand ils démarrent ou s’arrêtent (enfin pour l’arrêt, si, mais bon, par symétrie, on va considérer ici que ça n’est pas son boulot).

Et comment je fais pour enregistrer mes services ?

Donc, il faut ajouter un composant d’enregistrement, un « registrator ». Coup de bol, il y en a deux pour Rancher :

  1. Gliderlabs registrator
  2. Rancher Registrator

Pourquoi y en a-t-il deux ? C’est assez bien expliqué dans cette chouette question : Do you kill registrator ? Notez que l’auteur de la question est également l’auteur du second registrator … ceci expliquant cela.

Et ça marche comment ?

D’abord, je vous montre le docker-compose.yml, et ensuite on en discute, ok ?

Dans ce fichier, il y a quelques trucs à noter

Attention à la version !

registrator ne supporte l’option useIpFromLabel que dans la branche master. En ancien développeur Java appréciateur des beaux numéros de version, ça me fait mal, mais bon, on me dit que ça marche comme ça dans le monde de Docker …

internal ?

Ca permet à registrator d’utiliser les ports effectivement exposés par les images, au lieu d’utiliser les ports visiobles hors de Rancher, donc ne l’oubliez pas

cleanup, deregister et resync

La doc de registrator est assez claire, mais ça vaut le coup de bien préciser que ces options sont là pour garantir qu’il n’y a pas de services n’existant que dans Consul (ce qui est un peu bête)

useIpFromLabel

A partir de Rancher 1.2, Rancher utilise un système nommé CNI, ce qui fait que l’ip et le port ne sont plus accessibles via le conteneur Docker mais via le label (ajouté dynamiquement par Rancher) io.rancher.container.ip. Du coup, il faut bien signaler au registrator qu’il faut utiliser ce label pour lire l’adresse du conteneur.

Attention aux labels !

Parce que ce registrator est déployé dans Rancher. Il faut donc qu’il soit présent sur tous les hosts (puisqu’il lit la liste des conteneurs depuius le démon Docker local) (d’où le io.rancher.scheduler.global). Il faut également qu’il ait accès au DNS (d’où le io.rancher.container.dns). Les autres options sont moins indispensables.

Et paf !

Une fois que ces opérations sont effectuées, vos conteneurs seront automatiquement enregistrés dans Consul au démarrage, et supprimés de Consul lorsqu’ils s’arrêtent).

Générer mon asciidoc dans docker

Non mais pourquoi je veux faire ça ?

Parce que j’ai des collègues qui n’ont pas installé Graphviz. Personnellement, je ne comprend vraiment pas pourquoi. Mais bon, chacun ses choix.

Donc, comme ils n’ont pas Graphviz, et ne veulent pas l’installer, qu’en bonus ils ne veulent installer ni maven, ni java, et qu’ils semblent considérer que Docker est « la meilleure chose depuis le pain en tranches » (un indice : à mon avis, c’est faux), j’ai créé une image docker « kivabien » :

Donc vous prenez ce dockerfile, là, et comme je n’aime pas trop l’idée de publier ça sur le Hub (faut voir aussi que je suis un peu une quiche en docker), ben vous le lancez … avec docker-compose et cette configuration :

d’un habile coup de docker-compose up. Et si tout se passe bien, vous allez retrouver votre dossier target votre doc correctement générée. Notez que, normalement, votre doc pourra contenir du PlantUML, des liens, toute la richesse d’asciidoc.

Elle est pas belle la vie ? Perso, je suis pas sûr, mais on me dit que c’est ça le progrès. Moi je dis ok.

 

Un chtijug dans le textile

Et paf, un chtijug pas à petit prix chez kiabi ! Le site est plutôt sympa, avec un côté plateforme pour théatre d’improvisation (par contre, les spots du fond qui clignotent, ça va pas être pratique pour les épileptiques). Julien (du chtijug) est bien content qu’on sorte des éternels ISEN/IUT B …​ et moi aussi : aller faire ces conférences dans des entreprises, pour des développeurs professionnels, c’est effectivement mieux.

OpenAPI chez Kiabi

Il y a deux ans, Kiabi a lancé une API web. Je ne vais pas vous reprendre tout l’argumentaire développé par le speaker sur les API, parce que personnellement, je connais déja (oui, je ne suis pas vraiment pédagogue). Cela dit, il explique bien les différents aspects positifs de la définition d’une API (quand les slides seront disponibles, ce sera plus clair). L’un des plus grands bénéfices étant évidement l’accélération des développements : en découplant le développement back-end et le développement front-end, on peut accélerer ce dernier.

OpenAPI, c’est le troisième niveau du développement d’API dans l’échelle suivante :

  1. API interne
  2. API publique, mais uniquement exposée aux partenaires (avec évidement de l’OAuth, et peut-être de l’API management)
  3. API publique, exposée et source de revenus.

Définition

Pour développer l’API, Kiabi a d’abord défini des concepts généraux :

  • API Kiss
    • incluant une API affordance, c’est-à-dire intuitive dans son usage, et suggérant même ses bons usages
    • avec une sémantique claire
    • et en ne fournissant qu’une seule façon de faire une chose
  • Réutiliser des standards et des types d’API existant

Par contre, il faut éviter d’utiliser le jargon fonctionnel interne (ce qui est un point à mon sens super intéressant). Laissez-moi détailler ce point un instant. Dans votre entreprise, vos fonctionnels sont là pour définir le vocabulaire métier. Vous comptez sur leur sérieux. Mais quand vous développez une API publique, vous n’utilisez pas ce vocabulaire … C’est de la schizophrénie ? Non, à mon avis, c’est plutôt que le vocabulaire interne dérive, se jargonifie, et perd son adhérence avec le réel. Du coup, c’est DDD ou pas ? A mon avis, et contrairement à certain homonyme, oui.

A partir de ces concepts, Kiabi a défini une refcard qui reprend l’ensemble des concepts et des règles de fonctionnement définies. Chose curieuse, cette refacrd inclut la liste des codes HTTP retournés par les applications Kiabi. Ca me paraît curieux : le W3C a défini ces codes pour des raisons qui peuvent arriver, non ? Alors pourquoi ne pas tous les utiliser ?

Implémentation

Et donc, les implémenteurs implémentent leur API à partir de ces règles, et elle est définie en comité (argh) avec une platrée d’architectes transverses (re-argh). Evidement, ça qualifie le projet comme non-agile, mais en un sens, je comprend le besoin de cohérence du bazar. Et de la même manière, l’implémentation se fait sur une plateforme standard : Tomcat, CXF, JSON, …​

Management

Pour gérer tout ça, Kiabi a mis en place un API Manager (Software AG Webmethods API machintruc) qui ne semble pas fournir tous les services, puisqu’il y a quand même un Apache en frontal (apparemment pour faire de l’URI rewriting). Ils ont également un portail d’API pour développeur, évidement indispensable pour permettre aux développeurs d’utiliser les différentes API proposées. D’une façon amusante, le speaker insiste lourdement sur le fait que ce portail d’API permet aux développeurs d’utiliser facilement les différentes API. Ca trahit à mon sens plus le choc culturel qu’est cette ouverture que le challenge technique de ce portail (ne serait-ce que parce que StackOverflow, Goodreads, le fournissent déja depuis …​ quoi …​ 5 ans ?).

Démo

Pub

Kiabi organise au mois de juin un hackathon. Bon, personnellement, je ne suis pas fan de ce genre d’événements. Mais si ça vous branche …​

traefik

Pourquoi faire un autre reverse proxy (par rapport à, par exemple, nginx ou HAProxy) ? A cause des miccroservices.

Avec les microservices, on gagne un tas de nouveaux outils :

  • Des conteneurs (Docker, rkt)
  • Des orchestrateurs (Docker Swarm, Kubernetes, Mesos, Rancher)
  • Des outils de service discovery (etcd, Consul, Zookeeper)
  • Et des reverse proxy

A quoi ça sert ? A connecter le réseau privé au web en respectant l’état des microservices. Souvenez-vous, Christophe Furmaniak en avait déja parlé lors d’une session sur Rancher.

Les reverse-proxyes open-source (HAProxy et nginx) ont une configuration statique. Du coup, quand les microservices sont déployés, il faut

  1. Arrêter le proxy
  2. Changer la configuration
  3. Redémarrer le proxy

Pas très pratique.

traefik, lui, lit sa configuration depuis l’orchestrateur. Du coup, pas besoin de redémarrage. Plutôt cool …​ Et pour être rapide, c’est du go. Et d’un coup, je comprend pourquoi le go progresse : avec le build statique, une image Docker d’un programme go ne contient pas de dépendances, et c’est chouette ! (pour ceux qui aiment ça). Attention, je ne dis pas que c’est bien. Je dis juste que Go est plutôt bien adapté au monde Docker.

Démo

Et d’un coup, je comprend l’affection de Quentin Adam pour les gestionnaires d’abréviation : lancer des conteneurs docker en ligne de commande pendant une démo, ça peut merder facilement …​ Parce qu’Emile a eu quelques soucis liés à la connexion internet … sensible et aux commandes docker un peu longues.