20 juin 2016

DockerCon : quand docker-swarm laisse la place à docker swarm

tl:dr; 
docker 1.12 = docker 1.11 + swarmKit + server-side docker-compose 


Dans ma dernière vidéo je vous parlais du changement d'architecture de Docker 1.11 et du fait que le démon docker ne fait "plus grand chose" - à part l'authentification et la gestion des images, quelques bricoles quoi.

Il faut croire que, comme la nature, l'équipe Docker a horreur du vide, puisqu'elle s'est empressée de remplacer ce déficit de fonctionnalités dans la version 1.12 (Release Candidate 2) annoncée ce matin en keynote de la DockerCon - et oui, j'étais au courant avant, nananèreu

Dcoker-swarm est mort, vive docker swarm


Vous aviez sans doute vu passer l'annonce de swarmKit, un projet issu de l'architecture de docker-swarm mais plus générale (on parle ici de "tâches", pas forcément de conteneurs docker). En fait ce projet est reparti de la page blanche, en reprenant ce qui a bien marché dans docker-swarm et en choisissant d'autres pistes pour ce qui marchait moins bien.

Typiquement, oubliez votre etcd / consul et le zookeeper qui va bien pour gérer un cluster swarm. Jusqu'ici, swarm avait besoin d'un service externe "clé/valeur" pour stocker la configuration du cluster. En plus de compliquer le setup pour assurer de la haute disponibilité, cela introduisait pas mal de délais dans le traitement asynchrone de la transmission de ces infos. 

SwarmKit utilise Raft, protocole d'élection d'un noeud maître, et son implémentation par etcd. Plus besoin de service externe, un cluster swarm se suffit à lui même out-of-the-box pour distribuer ses métadonnées et élire son noeud "leader". 

Mais l'annonce de SwarmKit n'était que la partie visible de l'Iceberg, qui d'ailleurs à trompé pas mal de monde, car comme toujours les évolutions de Docker sont visibles sur le projet open-source pour qui sait lire entre les lignes des Pull-Requests.

Docker 1.12 annonce donc l'intégration native de swarmKit, pour former un cluster swarm sans quoi que ce soit d'autre que le démon Docker. Cette nouvelle feature n'est pas active par défaut (la compatibilité restant la première priorité). Il vous faudra explicitement passer en "mode swarm":  docker swarm init

Docker 1.12 introduit aussi le concept de services, et permet de déployer N instances d'un conteneur sur le cluster (voir, sur tous les noeuds du cluster - parfait pour l'exploitation), de gérer leur re-schedule automatique en cas de défaillance, le load-balancing de ces N instances, les mises à jour en rolling-upgrade, etc. Bref, ce que vous faisiez jusqu'ici avec docker-swarm ou avec votre orchestrateur docker préféré (sic), vous pourrez le faire en natif avec le docker engine de base, dans le cadre d'un cluster swarm - le nom reste, je reconnais que ça peut être source de confusion, mais bon en même temps au final c'est le même concept.

Le load balancing c'est une nouveauté importante qu'il va falloir que je teste plus en profondeur. S'il est toujours possible d'utiliser le DNS avec la liste des IP associées à un service, ce qui suppose que votre code client gère ça correctement (sic), la nouvelle approche consiste à faire du load balancing en se basant sur IPVS (i.e passer par le noyau Linux). Les interactions exactes entre un service déployé de cette façon, les conteneurs qui lui permettent de tourner, et les réseaux / ports associés sont encore assez flous pour ce qui me concerne, cela nécessitera quelques tests plus appuyés.

De son côté, le projet docker-swarm, s'il va vivre encore un moment (support client oblige) va rapidement être dépassé par ce support natif dans docker-engine.

Compose se fait tailler un short

Seconde annonce majeure : l'ajout du concept de "service“ à l'API docker, avec des réplicas et un load balancing natif sur le cluster swarm.

Ca parait abstrait comme ça ? En pratique, vous allez déployer non plus un conteneur (même si vous pouvez encore) mais un "service" utilisant une image : 
docker service create --name foo --network bar ma_super_appli:1

Sur TOUS les noeuds de votre cluster swarm, et sur l'overlay network bar indiqué, vous pourrez discuter avec ce conteneur. Et si vous augmentez le nombre d'instances :
docker service update foo --replicas 5
.. docker se chargera de faire du round-robin sur ces conteneurs pour distribuer la charge. Evidemment il y a toutes les possibilités de contraintes / affinités / labels de swarm pour jongler finement lorsque c'est nécessaire. 

Pour faire simple, jusqu'ici vous utilisiez docker-compose pour lancer une grappe de conteneurs. Rassurez-vous, vous allez sans doute continuer à faire ça en développement, et le format docker-compose.yml n'est pas remis en question. Par contre, sur un cluster swarm docker-compose est exposé à une limite :

Docker-compose utilise l'API docker pour faire de l'orchestration, mais un déploiement compose n'est pas atomique. Comprenez que si vos deux premiers conteneurs trouvent leur place sur un noeud, et que le troisième ne rentre pas faut de resources disponibles, et bien votre déploiement échoue, point barre. En gros, docker-compose est un orchestrateur côté client, en mode optimistic transaction.

Docker 1.12 introduit le concept de "bundle", dont le format est encore très récent et sujet à évolutions (i.e ne vous attardez pas dessus pour le moment), qui définit un groupe de containers et comment les lier ensembles.



Oui, c'est tout pareil que docker-compose. D'ailleurs, docker-compose bundle vous permettra de générer une spécification de bundle à partir de votre fichier docker-compose.yml, il ne s'agit donc pas de remplacer compose, mais plutôt de le booster en lui fournissant une API à la hauteur de ses ambitions. 

Ce bundle (un fichier JSON à ce stade, mais ça peut encore bouger), vous le passerez à votre démon docker via la commande docker deploy. La différence avec compose, c'est que le déploiement se fait alors "côté serveur", avec la sélection des noeuds en connaissance de cause.

Contrairement à docker-swarm, docker-compose va par contre subsister puisque son mode de fonctionnement continue à être pertinent en mode "classic" (non-swarm) - typiquement sur le poste de développement - et assurer la liaison avec le format de bundle.

BREF

docker-swarm vient de se prendre un balle, et docker-compose s'est fait couper les jambes par l'annonce de Docker 1.12. Ce qui est intéressant ici, c'est de voir que ces deux outils, conçus sur la base de l'API docker, avec ses contraintes et limites, voient au final leur fonctionnalité coeur intégrée dans docker-engine. Et vont donc pouvoir renaître en inventant de nouveaux usages et patterns, lesquels seront peut être un jour intégrés à leur tour... 

Ce cycle peut paraître surprenant quand on investi sur un outillage qui peut devenir obsolète au détour des annonces d''une keynote, mais il montre la dynamique raisonnée de l'écosystème Docker : si une fonctionnalité démontrer son intérêt, elle finit par être prise en charge nativement dans l'engine, vidant l'outil de sa raison d'être première, mais au final montrant que l'approche était bonne, et ouvrant la voie pour le cycle suivant.




A ce stade 1.12 n'est qu'une Release Candidate, et l'effet d'annonce pour la DockerCon a limité la période de test par la communauté (très occupée à s'accaparer SwarmKit). La version 1.12, bien qu'activement testée par de nombreux partenaires, va mettre donc encore quelque semaines à murir, sous les assauts d'une communauté qui ne va pas se priver de la secouer dans tous les sens pour vérifier que
  1. ça continue de marcher comme avant 
  2. le nouvelles fonctionnalités tournent dans la vraie vie comme indiqué dans la doc
Dans tous les cas, Docker 1.12 va changer pas mal de choses dans votre façon de déployer Docker, en intégrant les concepts de clustering et de déploiements composites au coeur de docker-engine.