Sommaire
Introduction
De nos jours, il est courant et fortement recommandé de mettre en place de la "conteneurisation", souvent au travers de la technologie Docker qui a accéléré la tendance depuis 10 ans :
Dans une équipe de développements applicatifs, sur l'environnement de développement :
- avoir des images prêtes à l'emploi : par exemple une image du serveur d'applications, que toute l'équipe utilise, sur la même base de modules et versions, annuaire LDAP, base de données, etc
- facilité de mise en place d'images, facilement déployables sur chaque station de travail : une image est légère et son exécution sera rapide, pour tester ou effectuer des POC, cela s'avère plus accessible
- une gestion des dépendances (versions des packages, modules, ...) nettement améliorée et contrôlée
Dans un environnements de tests ou de production
Ces images pourront être packagées pour une utilisation sur une plateforme de tests et / ou la plateforme de prod, de façon rapide et efficace : déploiements facilités et mise en production efficiente.
Sur un environnement de production, il y aura régulièrement plusieurs instances d'applications sur plusieurs VM / serveurs, afin d'absorber la charge des accès utilisateurs, il va donc falloir déployer toutes ces images applicatives sous forme de conteneurs légers vers ces différentes instances de machines, et ensuite, s'assurer d'orienter tel flux (https, accès base, etc) vers tels conteneurs : cette façon de faire se nomme de l'orchestration de conteneurs, qui va également gérer le cycle de vie des conteneurs : scaling, création, déploiement / rechargement pour aller vers du Zero downtime deployment, load-balancing, la communcation entre les containers etc
Docker propose un orchestrateur natif à leur technologie, dans le moteur de conteneurs : Docker Swarm, où l'on va retrouver nos habitudes :
- avec le docker CLI
- le docker-compose Yaml, du déclaratif, qui servira aussi à la gestion des conteneurs dans Swarm (stack)
Docker swarm & Portainer
Vocabulaire
Worker = un noeud du cluster Swarm, une VM ou une machine physique
Manager = un noeud spécial du cluster Swarm qui aura pour charge d'orchestrer les services / containers du cluster (flux, déploiements, load balancing et haute disponibilité des services exposés), tel un chef d'orchestre ! Un manager peut aussi jouer le rôle de worker
Stack = un "fichier" docker-compose dans lequel ait décrit les services avec les règles associées : d'images sources à utiliser, de déploiement, de ressources (volumes, networks, ...voire CPU & co)
Service = un élément d'une stack à déployer selon des règles
Task = un container déployé sur un / des noeuds
Registry docker
Dans un écosystème où l'orchestration demande des images pour les transformer en conteneurs ("instances" d'une image), il est nécessaire d'avoir un registry docker qui permettra de stocker ces images à déployer :
- le Docker Hub en est un
ou avoir une machine registry dédiée à cela :
- via une solution légère de type registry développé par Docker et disponible sur le Hub
- via une solution avec une interface Web de type harbor / github
Docker swarm
Docker swarm est inclus dans le moteur docker, c'est un orchestrateur de containers, qui permettra de gérer sur un ensemble de machines / VM, les containers sur chacune de ces instances (flux, déploiement, cycle de vie, répartitions et disponibilité), et, avouons-le, la mise en place reste accessible et rapide, une fois les concepts appréhendés.
Un cluster Swarm a plusieurs nœuds avec au moins 2 nœuds :
- de type manager : aura la mission de diriger les flux entrants vers les nœuds et la gestion de l'orchestration des conteneurs : réplication dans le cluster, déploiement / rechargement des services, load-balancing. Il est conseillé d'avoir un nombre de manager impairs et au moins 3, selon l'algorithme Raft. Un manager peut aussi jouter le rôle de worker
- de type worker, on pourra avoir plusieurs nœuds de ce type, afin de répartir la charge, un noeud à différents état : Active, Drain et Pause. Le mode Drain permettra de dire au manager de ne plus déployer vers les noeuds worker les services et donc d'arrêter les flux vers celui-ci. Le Pause, que j'utilise rarement, permet de suspendre tous les processus dans les containers contenus sur le noeud, en revanche, les flux continuent à être dirigés vers ce dernier.
Schématiquement, un cluster composé de managers et de workers se représentera ainsi :
Source : https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/
Le cluster swarm se gère avec la commande docker (CLI), tout comme on le ferait habituellement avec des images / containers /... en local d'une machine, c'est le gros avantage, on ne perd pas ses habitudes :)
Quelques commande avec le docker CLI
Les commandes ont le plus souvent une aide, il suffit d'utiliser l'option --help
pour avoir la liste des arguments possible.
Le docker CLI permet de gérer un cluster swarm, quelques commandes que j'utilise régulièrement, hormis l'initialisation :
Swarm
- initialisation d'un cluster swarm
$ docker swarm init --advertise-addr IP_MANAGER:2377
- informations sur le cluster
$ docker info
- obtenir un TOKEN worker / node à partir du manager
$ docker swarm join-token worker
docker swarm join --token SWMTKN-1-id1-id2 IP_MANAGER:2377
- faire rejoindre une machine sur le cluster en tant que worker
A partir de la commande donnée précédemment, il suffit de la recopier à partir d'une machine cluster
$ docker swarm join --token SWMTKN-1-id1-id2 IP_MANAGER:2377
- worker / noeud : faire quitter un noeud du cluster, à partir d'un noeud :
* docker swarm leave
Noeud(s)
- liste des noeuds
$ docker node ls
- liste des containers / tâches des noeuds ou d'un noeud
$ docker node ps
$ docker node ps <NODE_NAME>
- modifier l'état d'un noeud
$ docker node <ID_NODE> --availability "drain"
$ docker node <ID_NODE> --availability "active"
Stack(s)
- liste des stacks du cluster contenant, pour chacun, des services
$ docker stack ls
NAME SERVICES ORCHESTRATOR
api-XYZ 7 Swarm
ws 1 Swarm
fluend 3 Swarm
ABC 7 Swarm
loki-grafana 3 Swarm
portainer 2 Swarm
prometheus 8 Swarm
- liste des containers / tâches d'une stack
$ docker stack ps <STACK_NAME>
- liste des services d'une stack (un service correspond à une section du docker compose)
$ docker stack services fluend
Service(s)
- liste des services d'un noeud
$ docker service ls
- informations d'un service
$ docker service inspect --pretty <SERVICE_NAME>
- liste des containers d'un service avec répartition sur les noeuds
$ docker service ps <SERVICE_NAME>
$ # ou enlever le troncage du log de démarrage et la résolution DNS
$ docker service ps <SERVICE_NAME> --no-resolve --no-trunc
- rechargement d'un service
# forcer le redéploiement d'un service
$ docker service update --force <SERVICE_NAME>
- réplication d'un service
# réplication à 2 d'un service
$ docker service scale <SERVICE_NAME>=2
- logs d'un service
$ docker service logs <SERVICE_NAME> -f
- liste des configurations du cluster
$ docker config ls
Config(s)
- lire une config
$ docker config inspect <CONFIG_NAME> --pretty
Portainer
Introduction
Portainer propose une interface Web qui vous aidera à gérer votre cluster, à la place de la ligne de commande qui peut s'avérer rébarbative ou tout simplement pour simplifier la connaissance de toutes les options possible du CLI docker pour gérer le cluster ou tout simplement pour avoir une meilleure "vue" du cluster.
Comme vous avez pu le voir sur le docker CLI, il y a beaucoup d'options ou d'arguments à connaitre pour gérer son cluster, même s'il est bien de les savoir au cas où portainer venait à ne plus fonctionner.
La version présentée est la version 1.2x qui ne prend en compte que Docker ou Docker swarm. La version 2.x a grandement évolué pour gérer en plus un cluster de type Kubernetes, K8s de son petit nom qui est un autre orchestrateur de containers.
Portainer est livré sous forme d'images, soit à utiliser en "local" pour gérer votre écosystème docker, soit à déployer en tant que stack dans le cluster (ie : fichier docker-compose YAML) qui contiendra le service portainer ("serveur") et agent ("client" pour portainer), ce dernier sera déployé sur l'ensemble des workers / noeuds, manager compris.
Avec un fichier compose docker-compose.yml
contenant
version: '3'
services:
agent:
image: portainer/agent:1.3.0
environment:
# REQUIRED: Should be equal to the service name prefixed by "tasks." when
# deployed inside an overlay network
AGENT_CLUSTER_ADDR: tasks.agent
# AGENT_PORT: 9001
LOG_LEVEL: debug
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
networks:
- agent_network
deploy:
mode: global
portainer:
image: portainer/portainer:1.21.0
command: -H tcp://tasks.agent:9001 --tlsskipverify
ports:
- "9000:9000"
volumes:
- portainer_data:/data
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
networks:
- agent_network
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
networks:
agent_network:
driver: overlay
volumes:
portainer_data:
Pour rappel : le mode global déploie le service (ici agent) sur tous les noeuds du cluster, pour le serveur portainer, il ne déploiera le service uniquement sur le manager swarm. Le type / driver docker utilisé est overlay, qui permet d'avoir un réseau "virtuel" entre les machines du cluster docker swarm.
Il suffit, sur notre cluster prêt (un manager / un worker) de déployer portainer avec un deploy, cela va créer la stack portainer en déploiement l'agent et le manager.
$ docker stack deploy -c docker-compose.yml portainer
Les services de la stack portainer ont bien été déployés :
$ docker stack services portainer
ID NAME MODE REPLICAS IMAGE PORTS
65trhtm7ei17 portainer_agent global 1/1 portainer/agent:latest
l4ucvho6ms2m portainer_portainer replicated 1/1 portainer/portainer:latest *:9000->9000/tcp
Vous pouvez alors accéder à l'interface Portainer (certainement sur le port 9000 ou via un reverse proxy devant le cas échéant) pour initialiser le compte admin
Fonctionnalités utiles
Portainer propose un ensemble de fonctionnalités qui va nous soulager dans la gestion de notre cluster swarm, parmi lesquelles :
1 : tableau de bord synthétique des stacks, images, volumes, containers, etc, avec la possibilité d'avoir une vue sur des containers actifs sur chacun des noeuds du cluster
2 : vous accéderez à l'ensemble de vos stacks afin d'en créer, en supprimer ou voir le détail des services déployés (containers / tasks) de la stack : redéployer une stack (pour une mise en production par exemple avec de nouvelles images), modifier le docker-compose associé qui décrit la stack avec, en plus du compose habituel docker, ses règles de déploiements, de loggin, etc
Par exemple, sur la stack prometheus, a 4 services, décrit dans le compose (cf. Editor) : prometheus_alertmanager, prometheus_caddy, prometheus_cadvisor, prometheus_dockerd-exporter, ...
Les noms des services sont nommés selon le motif : nom_de_la_stack_nom_du_service
Nous aurons 2 onglets :
- un général pour recharger / mettre à jour, entrer en mode console dans un container, avoir des logs ou l'information (inspect) d'un container, l'état des containers / tasks, le scaling / réplication opérées, et un onglet
- pour éditer le docker-compose de cette stack.
Sur une stack
1- onglet Stack :
3- : pouvoir filtrer les containers / tasks sur un service
4- : permet d'avoir dans l'ordre des icones : les logs du container (stdout / stderr des process du container, par ex. les logs nginx), les infos (inspect docker) de celui-ci : cela peut être utile pour avoir de l'informations sur d'éventuelles erreurs d'un container qui ne voudrait pas se lancer (en failed / shutdown), des stats (mémoire, CPU, flux réseau et les process lancés dans le container), accéder à la console du container
5- : permet de recharger les services de la stack, en cochant ceux souhaités : soit en recharge simple vers les noeuds (reploiement des services de la stack), soit en forçant le pull des images du compose (cf. Editor) pour redéploiement.
1- onglet "Editor" : permet d'écrire un compose (lors d'une création d'une stack ou sa mise à jour), en Yaml, qui reprend la syntaxe du docker-compose avec en plus des sections propres à Swarm (section deploy qui donnera les règles de déploiement /réplication / contraintes, ressources, section *configs les configurations à monter lorsqu'il y en a besoin)
Le bouton "Update the stack" permet de déployer toute la stack sur le cluster et ses services décrits dans le compose une fois modifié le compose
3 : les services déployés sur les nœuds du cluster et les containers / tasks associés et leur état, des actions seront possible : rechargement, suppression voire création de service (mais on passera plus volontiers par de la gestion de stack via un compose), indications de la répartition des containers (replicas)
4 : liste des containers du cluster swarm avec la possibilité de les filtrer selon leur état ("running", "stopped", "created", "healthy") et d'opération une action dessus : en supprimer (très utile pour effectuer un ménage de temps en temps), en relancer, voire en créer ou d'entrer en mode console dans un container
5 : liste des images du cluster : vous permettra de faire un peu le ménage de temps en temps afin de supprimer les images inutilisées
6 : volumes : les volumes dockers utilisés ou non sur les différents nœuds : cela peut être pratique de repérer les volumes inutilisés à supprimer. On peut aussi en créer mais je passe la plupart par les stacks et un docker-compose. Les volumes sont soient locaux à un noeud (par exemple, le volume portainer de portainer déployé uniquement sur un noeud manager, ou via des partages réseaux de NFS, Longhorn, ... qui permettra un accès de plusieurs noeuds sur ces partages)
7 : les configurations docker qui seront utilisées dans les services, où l'on peut en créer ou en cloner (à la place d'une modification qui n'est pas possible en état). Sur une instance isolée, nous utilisons les volumes pour monter un répertoire, un fichier dans le container. Dans un environnement distribué, un cluster de machines, ces fichiers doivent être centralisé (sur le manager) afin de le distribuer sur chacun des noeuds, ce à quoi servent les configurations sauf à les inclure lors de la création de l'image, mais cela rendra moins souple leur gestion, cela dépend.
Par exemple, la configuration fluen-elasticsearch-conf.v2 aura ce type de contenu
<source>
@type forward
@id input1
@label @mainstream
port 24224
</source>
<filter **>
@type stdout
</filter>
<label @mainstream>
<match api-prod>
@type copy
<store>
@type file
@id output_docker1
path /fluentd/log/api-prod.*.log
symlink_path /fluentd/log/api-prod.log
append true
time_slice_format %Y%m%d
time_slice_wait 1m
time_format %Y%m%dT%H%M%S%z
compress gzip
utc
format json
</store>
</match>
</label>
La config fluent-elasticsearch-conf.v2
pour être utilisée dans une stack comme suit, grâce à la section configs
:
version: "3.6"
configs: # déclaration de la config à prendre
fluent-elasticsearch-conf.v2:
external: true
services:
fluentd:
image: fluend:latest
volumes:
- /home/root/data/logs:/fluentd/log
ports:
- "24224:24224"
- "24224:24224/udp"
networks:
- net
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.labels.type == fluent]
configs: # montage de la config vers la target
- source: fluent-elasticsearch-conf.v2
target: /fluentd/etc/fluent.conf
8 : vue synthétique des nœuds du cluster et de leur état, permettra de changer leur état ("Active" => "Drain" notamment) ou d'ajouter / modifier des labels sur les nœuds, ces labels pourront servir pour les règles de déploiement d'un service , sur ses contraintes (cf. deploy d'un service dans le compose)
Par exemple, le label nginx avec une valeur true
pourra être une contrainte pour un service nginx pour son déploiement : déploie l'image nginx sur 3 noeuds ayant un label nginx avec une valeur à true
9 : gestion des dépôts d'images docker : soit DockerHub, soit le registry de votre écosystème : les images des stacks pourront alors être prise du registry paramétré
Conclusion
Docker swarm peut être mis en place relativement rapidement, bien entendu, charge à vous de construire vos images et les VM qui hébergeront manager et workers.
Pour sa gestion, portainer permet de gérer votre cluster directement en ligne, pour la majeure partie des fonctionnalités de swarm, et...c'est très appréciable.
Katacoda propose d'essayer Portainer directement en ligne, avec les VM provisionnées, un bac à sable pour découvrir ces technologies : https://www.katacoda.com/portainer/scenarios/deploying-to-swarm
Top comments (6)
Super article, très détaillé, bravo! Je peux te demander pourquoi tu as préférer faire cette présentation avec une version plutôt ancienne de Portainer (1.21) ?
La version 2.x n'apporte pas simplement des changements pour supporter Kubernetes mais aussi pas mal de features (en autre la possibilité pour Portainer de déployer une application "synchronisée" directement depuis Git) et de bugfix pour Docker/Swarm.
Top en tout cas :)
Merci, me suis appliqué pour ce billet :)
J'ai axé sur la 1.2x car "je" ne suis pas passé à la 2.x et donc je voulais rester sur ce que je connaissais, proche de la réalité.
C'est prévu de passer à la 2.x, chantier à programmer (upgrade des machines, docker, ....et de portainer), pas mal de choses à faire en amont avant.
Merci de ton retour concernant la version 2, intéressant oui
Cool, hésites pas à m'envoyer un email si tu as des questions!
Oui, et je vois que j'ai à faire à la bonne personne en voyant ton profil LinkedIn :)
Beau produit Portainer ! ça nous facilite grandement la vie
@deviantony je peux te contacter sur quel email ou via LinkedIn ?
J'ai une interrogation sur l'alignement des versions entre le portainer "manager" et ses agents :)
Woops j'ai raté cette notification, tu peux me contacter sur mon LinkedIn et je te partagerai mon email.