======Sujet de TP : Mise en oeuvre de Docker Swarm ====== ====Remarque==== Ce TP est noté de la même façon que les autres. Un script sera passé ce soir après 10h (demain 12h pour les tiers temps). Une première ébauche du script est {{ :cloud:2018:testswarm.zip |ici}}. Cette ébauche teste la présence des services demandés, des machines créées par docker-machine qui doivent être présentes dans le cluster. Nous ajouterons le test du service final demandé et du contenu du //registry//. Pour passer le test, il nous faut : - un nom pour votre équipe dans la case nomEquipeSwarm (les 2 membres du binôme doivent entrer la même valeur pour qu'on puisse s'y retrouver) - l'IP de votre manager dans la case IPTpSwarm ====Introduction ==== L'objectif de ce TP est de se familiariser avec la solution de clusterisation proposée par Docker et nommée //Swarm//. Comme vu en cours, il existe des solutions alternatives que nous n'explorerons pas dans le cadre de ce TP (ex: //Kubernetes//). Nous nous appuierons sur l'infrastructure OpenStack de Lyon 1 [[https://cloud-info.univ-lyon1.fr/horizon]]. Pour obtenir des informations sur comment se connecter : https://documentation.univ-lyon1.fr/ . Dans le projet **TIW** ou **SRIV-SCV** nous déploierons au préalable 3 petites machines virtuelles (''m1.xsmall'' est suffisant). L'une sera utilisée comme //Manager//, et les deux autres comme //Worker//. Attention : Pour ce TP nous avons préparé une image avec un //docker// pré-installé et pré-configuré qui fonctionne à l'université. Vous devez créer vos instance à partir d'un //snapshot// nommé ''snap-docker-ready''. Si vous utilisez des machines en dehors de l'université, installé bien une version de docker récente (>=1.12) et le paquet ''docker-engine'' dont l'installation est [[https://docs.docker.com/engine/installation/|décrite ici]]. Le paquet ''docker.io'' présent par exemple sur //Ubuntu// est justement une version de //docker// sans //Swarm//. **//NB//**: Une fois le cluster installé, la commande ci-dessous vous permettra d'avoir un visualiseur de votre infrastructure déployée (http://IP:8080): docker service create --name=viz --publish=8080:8080/tcp --constraint=node.role==manager \ --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \ dockersamples/visualizer =====Partie I : Installation de Docker Swarm===== L'installation de base se fait à présent de manière très simple. Tout d'abord sur la VM qui hébegera le manager : docker swarm init --advertise-addr 192.168.XXX.YYY * **Que fait cette commande ? Expliquez/Décrivez succinctement.** Puis sur chacun des //workers// # docker swarm join --token letokenrenvoyeparleswarminit 192.168.XXX.YYY:2377 * **Que fait cette commande ? Expliquez/Décrivez succinctement.** **Remarque** : Pour chacune des questions vous trouverez des éléments de réponse dans la documentation officiel de Docker Swarm. - [[https://docs.docker.com/engine/reference/commandline/swarm_init/]] - [[https://docs.docker.com/engine/reference/commandline/swarm_join/]] * **Quelle commande peut on utiliser pour lister et vérifier la liste des //workers// à disposition ?** * **Imaginons que vous souhaitiez ajouter un nouveau nœud //worker// et que vous avez égaré le token de votre cluster swarm. Quelle commande vous permet de le récupérer ?** * **Est il possible d'avoir plusieurs machines qui tiennent le rôle de manager (au même titre que plusieurs machines sont des //workers//). Comment fonctionnent t-ils ?** * **Sortez un //worker// du cluster puis remettez le. Quelles commandes saisissez-vous ?** ===== Partie II : Usage d'un cluster swarm===== Exécutons trois instances de //nginx// dans notre //cluster swarm//. (manager)# docker service create --name Web --publish 80:80 --replicas=3 nginx:latest * **Quelle commande utilise-t-on pour lister tous les services créés ?** * **Quelle commande utilise-t-on pour lister toutes les instances du service ?** * **Quelle commande utilise-t-on pour obtenir des informations détaillées sur un service ? (inspect)** == Comment étendre un service ?== Afin d'avoir à présent cinq instances de notre service (manager)# docker service scale Web=5 On peut également réduire le nombre de services (scale down) (manager)# docker service scale Web=1 Supprimons à présent notre service (manager)# docker service rm Web ==Maintient automatique du service== Si nous avons défini un service avec un nombre donné de //replicas//, le Swarm manager est en charge de s'assurer de maintenir cet état. Pour vous en assurer : * instanciez trois réplicas d'un service (voir commande précédente); * Connectez vous sur l'une des machines de travail hébergeant l'un de ces réplicas et détruisez brutalement le docker (''docker kill ...''). * **Que se passe t-il au bout de quelques secondes ?** * **À présent stoppez directement la machine de travail. Que se passe t-il ?** ===== Partie III : Gestion des nœuds composant le cluster ===== * On souhaite éteindre un nœud physique (de type worker) pour effectuer une opération de maintenance sur ce dernier. **Quelle procédure aller vous suivre (ou Quelles commandes allez vous saisir) pour faire cela proprement ?** * Expliquez brièvement la notion de promotion d'un nœud worker (promote/demote). =====Partie IV : Réseau overlay ===== Supprimez tous les services utilisés précédemment, vous allez en relancer un seul avec un unique réplicas : docker service create --name nginx -p 80:80 --replicas 1 nginx Ensuite, retrouvez sur quel nœud de calcul se trouve le docker. Le nom du docker est un peu différent du nom du service, Grâce à la commande docker logs -f nginx.x.yyyyyyyyyyy afficher les logs du docker nginx. Puis avec votre navigateur tentez de contacter le serveur web sur vos 3 machines. * **Que constatez-vous ?** * **Quel réseau utilise le docker ? (utilisez la commande ''docker inspect ...'')** * **Afficher la liste des réseau, quel est le //driver// de ce réseau ?** === Créez votre réseau overlay=== * Créer un réseau ''172.21.21.0/24'' avec le driver //overlay// ayant pour nom //reseau// (sans accent). Ajoutez lors de sa création l'option ''attachable''. Cette option vous permettra de créer des docker utilisant le réseau sans être géré par swarm. * Déployer sur le réseau nouvellement créer 3 réplicas du service nginx. Observez l'adressage IP. ===== Partie V : Création d'un registry privé ===== Vous avez vu lors du TP précédant que le cluster swarm pouvait facilement lancer des dockers basés sur des images publiques. Mais pour le moment vous ne pouvez pas le faire avec des images construites via un //dockerfile//. Pour éviter cette limite, il faut installer un dépôt docker privé dans lequel vous placerez et téléchargerez les images que vous avez généré. Vous trouverez la [[https://docs.docker.com/registry/|documentation ici]] Attention, les //registry// que vous pouvez facilement utiliser sont des //registry// locaux c'est à dire que leur adresse est ''localhost''. En effet, pour autoriser un //registry// distant, il faut gérer des certificats d'authentification SSL ce qui est hors du cadre de ce cours. Vous allez donc créer un unique docker registry qui répondra à l'adresse ''localhost:5000'' sur plusieurs machines virtuelle. Cela n'est possible que grâce au cluster swarm qui va s'occuper pour vous de la redirection des paquets. * Dans le cluster //swarm//, créer un **service** ''registry'' qui partage le port 5000 avec toutes les machines du cluster. * Sur quel nœud ce dernier est-il instancié ? * Testez sa réponse à l'adresse localhost en vous connectant sur la machine virtuelle qui ne fait pas tourner le service *registry*. * Pour tester le registry, vous pouvez télécharger (*pull*) une image officiel et la *tagger* avec le nom ''localhost:5000/NOMIMAGE''. Ensuite vous l'envoyez (*push*) sur le registry localhost et supprimez les deux images (celle récupéré via le pull et celle taggée). Enfin, faite de nouveau un pull sur localhost de l'image taggée qui devrait re téléchargée de nouveau. === Exploration du registry === Le //registry// semble un peu abstrait car il ne permet pas facilement d'explorer son contenu. Mais il y a des service spécialisé dans cette exploration que vous pouvez bien sur installer sous forme de conteneurs. * Installez un service d'exploration du //registry// comme celui-ci [[https://store.docker.com/r/konradkleine/docker-registry-frontend]] via la commande docker service create -d --network reseau -e ENV_DOCKER_REGISTRY_HOST=registry \ -e ENV_DOCKER_REGISTRY_PORT=5000 -p 8443:80 --name regbrowser \ konradkleine/docker-registry-frontend:v2 Consultez la page [[http://IP_DE_VOTRE_VM:8443]] et explorez le contenu du registry. {{glyphicon>alert?48}} Attention ce TP est noté, voir [[cloud:2018:tp_swarm#remarque|ici]] ===== Partie VI : préparation de la suite du TP ===== Pour la suite du TP nous allons recréer les 2 worker, il va donc falloir les supprimer //proprement//. * supprimez tous les services en ne conservant que les service ''regbrowser'', ''viz'' et ''registry'' (a priori il faut supprimer les service nginx). * Modifiez les 2 //workers// pour les vider de leur dockers. * Supprimez les 2 VM workers **Attention de bien conserver le manager** Vous constatez que les services sont déplacés sur le manager (qui est le seul noeud encore utilisable du cluster). * Si le //registry// a été déplacé, regardez une nouvelle fois son contenu. Il est vide ! Expliquez pourquoi. * Retirez les //workers// du cluster Pensez à écrire sur tomuss : - un nom pour votre équipe dans la case ''nomEquipeSwarm'' (les 2 membres du binôme doivent entrer la même valeur pour qu'on puisse s'y retrouver) - l'IP de votre manager dans la case ''IPTpSwarm'' =====Partie VII: Docker Machine ===== [[https://docs.docker.com/machine/overview/|Docker machine]] est un script qui permet de générer des machines virtuelles et d'installer docker automatiquement. Il est capable d'utiliser plusieurs hyperviseurs comme //virtutalbox// ou //openstack// mais aussi les fournisseurs de cloud publiques : AWS, Azure ... Vous avez une documentation plus spécifique sur [[https://docs.docker.com/machine/drivers/openstack/|openstack ici]]. Normalement, toutes les machines utilisées sont générées par //docker-machine//. Mais certaines requêtes de //docker machine// utilisent un port inhabituel qui est filtré sur le réseau wifi ce qui perturberait le TP. Il faut donc l'utiliser depuis une machine qui se trouve dans le même réseau. Pour ce TP, il est donc plus simple de l'utiliser depuis le //manager// pour créer les 2 //workers//. * Supprimez les //workers// du début du TP mais conservez le manager. Notez l'adresse du manager dans la case ''IPManager'' de [[http://tomuss.univ-lyon1.fr|tomuss]]. * Sur le manager, vérifiez que docker-machine est installé avec l'utilitaire de complétion. La commande docker-machine est assez simple car elle signale la plupart des options qui lui manque. La commande de création est [[https://docs.docker.com/machine/reference/create/|documentée ici]], les [[https://docs.docker.com/machine/drivers/openstack/|options relatives à openstack là]]. CE qu'il faut comprendre est que la commande va contacter les API openstack et s'occuper de l'installation des machines à votre place. Il faut donc lui fournir toutes les informations qui vous serait nécessaire pour faire la même chose. Vous pouvez aussi bien sur suivre la progression de son travail en consultant le site [[https://cloud-info.univ-lyon1.fr]]. Vous devez savoir que : - le driver est ''openstack'' - l'url d'authentification est ''https://cloud-info.univ-lyon1.fr:5000/v3/'' - le nom d'utilisateur et le mot de passe sont ceux qui vous permettent de vous connecter (voir la remarque plus loin). - le //tenant// est le projet //openstack// où créer les machines Il faut donner son identifiant avec l'option ''openstack-tenant-id'' et lui donner la valeur ''9b0d64f0d1d241d8b8afbd60caac615a'' ((Cette information se trouve dans le fichier généré par le menu ''fichier openstack rcv3'' en haut à droite de l'interface horizon)). - le nom de l'image à utiliser est celui d'un snapshot spécialement préparé ''snap-docker-machine''((Il est possible de lui faire utiliser une image standard à condition de lui donner toutes les options qui permettent d'adapter docker à notre environnement, mais cela est fastidieux et il serait impossible à vos enseignants de faire les corrections)). **Quelques conseils :** il faut bien spécifier les options nécessaires au fonctionnement à l'université. Le proxy via l'option //engine-env// qui permet de spécifier une variable d'environnement((donnez une valeur pour ''HTTP_PROXY'' et ''HTTPS_PROXY'')). Cela permettra de configurer le docker installé pour l'utilisation du proxy de l'université et s'utilise de cette manière : docker-machine ... --engine-env HTTP_PROXY=http://proxy.univ-lyon1.fr:3128 \ --engine-env HTTPS_PROXY=http://proxy.univ-lyon1.fr:3128 \ --engine-env NO_PROXY=.univ-lyon1.fr \ --engine-opt "dns 10.10.10.10" \ --engine-opt "log-level debug" \ ... NOMDELAMACHINE Lorsque docker-machine a commencé à créer une machine, il en garde une trace et interdit de réutiliser le même nom. Vous pouvez effacer ces traces en utilisant la commande ''docker-machine rm -f NOMMACHINE''. Protection de votre mot de passe: Attention, vous vous connectez au serveur openstack avec votre //login// et mot de passe de l'université. Pour éviter de laisser votre mot de passe en clair dans la ligne de commande, n'utilisez pas l'option ''openstack-password''. Vous devez stocker votre mot de passe dans la variable d'environnement ''OS_PASSWORD''. Pour cela copier/coller la commande : export OS_PASSWORD=$(python3 -c "import getpass; pa=getpass.getpass('Mot de passe : '); print (pa)") Ensuite, vous pourrez utiliser la variables d'environement ''$OS_PASSWORD'' Erreur: Si vous obtenez l'erreur suivante faite un ''export NO_PROXY=.univ-lyon1.fr'' Error creating machine: Error in driver during machine creation: Post https://cloud-info.univ-lyon1.fr:5000/v3/auth/tokens: Forbidden * En utilisant docker-machine, créez 2 machines qui serviront de nœuds de travail pour //Swarm//. Appelez-les VOTRELOGIN-work1, VOTRELOGIN-work2. Vous pouvez ensuite voir les nœuds gérés par docker-machine via la commande ''docker-machine ls'', en supprimer une par ''docker-machine rm'' ... ''docker-machine'' stocke ses informations dans le répertoire ''.docker/machine/...''. * Où sont les clefs ssh des machines que vous avez créées ? Pour exécuter des commandes docker sur ces machines il y a 3 méthodes : - Vous pouvez utiliser les variables d'environnement docker fixées par la commande ''docker-machine env NOMMACHINE''. - Vous pouvez vous connecter sur les machines via la commande ''docker-machine ssh NOMMACHINE'' - Vous pouvez exécuter les commande à distance via la commande ''docker-machine ssh NOMMACHINE COMMANDE''. Par exemple docker-machine ssh NOMMACHINE sudo docker ps * Ajouter à votre cluster //swarm// les 2 nœud de travail créés par docker machine. ===== Partie VII : Utilisation d'une image configurée===== Vous allez construire une image personnelle, mais cette dernière est basée sur une autre qui se trouve dans un registry privé et nécessite une authentification. L'image que vous allez construire devra être déposé dans le registry local ''localhost:5000'' où elle sera disponible à tous les noeud du cluster ce qui permettra de l'utiliser dans un service. ===Authentification auprès d'un registry=== * via la commande ''docker pull forge.univ-lyon1.fr:4567/romain.chanu/cloudcomputing/udl-php:v1'' vérifiez que cette image n'est pas publique. * En utilisant la commande ''docker login'' ([[https://docs.docker.com/engine/reference/commandline/login/#usage|infos ici]]), authentifiez-vous auprès de la forge de l'université sur le port **4567**. Ensuite, re-testez le téléchargement de l'image qui devrait fonctionner. * Dans le répertoire ''.docker'', retrouvez le jeton d'authentification. ===Construction d'une image=== Vous pouvez construire une image personnelle, à partir de cette image. Pour cela créez un dockerfile avec les caractéristiques suivantes: - hérite de forge.univ-lyon1.fr:4567/romain.chanu/cloudcomputing/udl-php:v1 - définit une variable d'environnement du nom de **CC_LOGIN** avec le nom d'utilisateur de votre choix * Il faut maintenant //construire// son image normalement * La "tagguer" correctement afin de la déposer dans le //registry// local ''localhost:5000''. Rappel, la documentation est ici [[https://docs.docker.com/registry/#basic-commands|ici]] (le nom du tag doit commencer par celui du registry c'est à dire ''localhost:5000/'') * Une fois les étapes précédentes réalisées il faut l'envoyer dans le //registry// Vous pouvez alors voir l'image dans l'explorateur du //registry//. Maintenant que tous les noeud du cluster peuvent avoir accès à cette image, elle peut être utilisée dans un service. * lancer un service //swarm// - basé sur cette image; - avec 3 réplicas; - redirigeant le port ''80'' des VM sur le port 80 des dockers; - utilisant le réseau ''reseau''; - dont le nom est ''myphp''. * vérifiez qu'il est bien instancié sur plusieurs machines différentes; * vérifiez qu'il répond avec une répartition de charge. ===== Partie VIII : Création d'un fichier de déploiement ===== Pour automatiser vos déploiements, il est plus pratique d'utiliser un fichier //yaml// pour décrire votre application comme pour le premier TP avec docker-compose. Vous allez effctivement créer ce fichier, mais la commande de lancement utilisée sera maintenant ''docker stack''. La version du fichier est maintenant une version supérieur à 3, par exemple ''3.1''. * Vous devez supprimer votre précédent service avec ''docker service rm myphp''. * Maintenant que tout est prêt, vous pouvez écrire votre fichier yaml : ''stack/stack.yml'' pour : - lancer un service de nom ''php'' - basé sur votre image ''localhost:5000/TAG''; - avec une réplication à 2; - qui expose le port 80 sur les nœuds; * Une fois qu'il est écrit, vous pouvez lancer votre stack avec l'aide de la commande ''docker stack deploy'' en lui donnant le nom ''stackphp''. ===Gestion des secrets=== Le service mis en place est un petit site proposant un login. Le login est celui que vous avez mis dans le ''Dockerfile'', le mot de passe et un //token// de sécurité sont aussi nécessaires et peuvent être fournis par le fichier de description ''stack.yaml''. Mais il est préférable que ces dernier n'apparaissent pas directement dans le fichier. C'est le rôle des //secrets//. En effet, lors de la mise en place d'applications, il y a de nombreuses données sensibles comme les certificats ou les mots de passe. Pour ne pas les mettre en clair dans vos fichiers, docker propose la possibilité de créer des //secrets//. Cela tombe bien... Car l'application que vous avez construit est spécialement prévue pour utiliser les //secrets// pour le mot de passe et le token de soumission. La première chose à faire est de retrouver le token dans les logs de la stack déployée. En effet, lors du lancement de l'application, la première ligne affichée dans les journaux est la valeur de **votre token** de soumission. * utiliser ''docker service logs ...'' pour afficher les logs des dockers lancé et obtenir le token. Avec la commande ''docker secret'' vous allez créer 2 secrets: * Le premier contenant le mot de passe de votre choix (**Cela ne doit pas être le mot de Lyon1**). Ce secret doit s’appeler **password_login** où login est la valeur de la variable d'environnement que vous avez mis dans le Dockerfile de la partie précédente. * Le second doit se nommer token et vous pouvez trouver la valeur à la première ligne du journal de l'application (que vous avez du lancer au moins une fois) Une fois que les secrets sont créés, vous devez modifier votre fichier yaml pour ajouter la prise en charge de ces 2 secrets et préciser que votre service puisse y accéder. Si vous avez utilisé une fonction de type //echo// pour la création votre secret, il sera de type //external//. Si vous avez tout configuré correctement, vous pouvez normalement vous connecter sur le petit formulaire. Si vous y arrivez, un blond (pas celui à qui vous pensez) vous félicitera et le script de Fabien vous donnera un bonus.