Pour rappel, un service est composé d’un ou plusieurs conteneurs qui sont répliqués sur différents nœuds du cluster.
Chaque service consiste donc en un ensemble de tâches individuelles, chacune traitée dans son propre conteneur sur l’un des nœuds du cluster.
Il existe les services répliqués sur certains nœuds disponibles du cluster (choisis lors du déploiement) et les services globaux qui eux sont sur tous les nœuds disponibles du cluster.
Le service offre également une adresse IP virtuelle qui va nous permettre de se connecter directement au service tandis qu’il se chargera de distribuer à l’aide de « load balancing » les différentes connexions sur les conteneurs qui composent ce service.
Pour créer un service, nous utiliserons la commande :
docker service create "options"
Nous allons procéder un peu comme lorsque nous avions créés des conteneurs avec la commande « docker run ».
En effet, nous allons devoir spécifier un certain nombre d’informations sous forme d’options à passer à la commande lors de la création du service.
Voici la liste en anglais des très nombreuses options :
Options | Résultats |
--config | Specify configurations to expose to the service |
--constraint | Placement constraints |
--container-label | Container labels |
--credential-spec | Credential spec for managed service account (Windows only) |
--detach , -d | Exit immediately instead of waiting for the service to converge |
--dns | Set custom DNS servers |
--dns-option | Set DNS options |
--dns-search | Set custom DNS search domains |
--endpoint-mode | Endpoint mode (vip or dnsrr) |
--entrypoint | Overwrite the default ENTRYPOINT of the image |
--env , -e | Set environment variables |
--env-file | Read in a file of environment variables |
--generic-resource | User defined resources |
--group | Set one or more supplementary user groups for the container |
--health-cmd | Command to run to check health |
--health-interval | Time between running the check (ms|s|m|h) |
--health-retries | Consecutive failures needed to report unhealthy |
--health-start-period | Start period for the container to initialize before counting retries towards unstable (ms|s|m|h) |
--health-timeout | Maximum time to allow one check to run (ms|s|m|h) |
--host | Set one or more custom host-to-IP mappings (host:ip) |
--hostname | Container hostname |
--init | Use an init inside each service container to forward signals and reap processes |
--isolation | Service container isolation mode |
--label , -l | Service labels |
--limit-cpu | Limit CPUs |
--limit-memory | Limit Memory |
--log-driver | Logging driver for service |
--log-opt | Logging driver options |
--mode | Replicated or Service mode (replicated or global) |
--mount | Attach a filesystem mount to the service |
--name | Service name |
--network | Network attachments |
--no-healthcheck | Disable any container-specified HEALTHCHECK |
--no-resolve-image | Do not query the registry to resolve image digest and supported platforms |
--placement-pref | Add a placement preference |
--publish , -p | Publish a port as a node port |
--quiet , -q | Suppress progress output |
--read-only | Mount the container’s root filesystem as read only |
--replicas | Number of tasks |
--replicas-max-per-node | Maximum number of tasks per node (default 0 = unlimited) |
--reserve-cpu | Reserve CPUs |
--reserve-memory | Reserve Memory |
--restart-condition | Restart when condition is met (“none”|”on-failure”|”any”) (default “any”) |
--restart-delay | Delay between restart attempts (ns|us|ms|s|m|h) (default 5s) |
--restart-max-attempts | Maximum number of restarts before giving up |
--restart-window | Window used to evaluate the restart policy (ns|us|ms|s|m|h) |
--rollback-delay | Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s) |
--rollback-failure-action | Action on rollback failure (“pause”|”continue”) (default “pause”) |
--rollback-max-failure-ratio | Failure rate to tolerate during a rollback (default 0) |
--rollback-monitor | Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h) (default 5s) |
--rollback-order | Rollback order (“start-first”|”stop-first”) (default “stop-first”) |
--rollback-parallelism (defaul 1) | Maximum number of tasks rolled back simultaneously (0 to roll back all at once) |
--secret | Specify secrets to expose to the service |
--stop-grace-period | Time to wait before force killing a container (ns|us|ms|s|m|h) (default 10s) |
--stop-signal | Signal to stop the container |
--sysctl | Sysctl options |
--tty , -t | Allocate a pseudo-TTY |
--update-delay | Delay between updates (ns|us|ms|s|m|h) (default 0s) |
--update-failure-action | Action on update failure (“pause”|”continue”|”rollback”) (default “pause”) |
--update-max-failure-ratio | Failure rate to tolerate during an update (default 0) |
--update-monitor | Duration after each task update to monitor for failure (ns|us|ms|s|m|h) (default 5s) |
--update-order | Update order (“start-first”|”stop-first”) (default “stop-first”) |
--update-parallelism (default 1) | Maximum number of tasks updated simultaneously (0 to update all at once) |
--user , -u | Username or UID (format: <name|uid>[:<group|gid>]) |
--with-registry-auth | Send registry authentication details to swarm agents |
--workdir , -w | Working directory inside the container |
Pour commencer nous allons créer un service web assez simple qui aura un seul réplicas
docker service create --publish "8000":"80" --name "web" "nginx"
Ici nous allons créer un service web qui va mapper le port 8000 vers le port 80 dont le nom sera « web » et qui utilisera une image Nginx.
Pour visualiser les services disponibles nous utiliserons la commande :
docker service ls
Actuellement nous pouvons constater qu’il n’y a qu’un seul réplicas de ce service.
Pour savoir sur quel nœud il tourne il suffira de faire la commande
docker service ps "nom_du_service"
Pour créer un service avec plusieurs réplicas il faudra ajouter une options à la commande que nous avons passé.
docker service create --publish "8080":"80" --name "web-v2" --replicas "3" "nginx"
Comme précédemment, pour vérifier les service qui tournent nous allons faire la commande
docker service ls
Cette fois-ci nous pouvons constater que le service est effectivement répliqué en 3 exemplaires, sur les nœuds suivant :
Pour rappel, « scale » signifie une « mise à l’échelle ».
Cela signifie que nous pouvons modifier en augmentant ou diminuant le nombre de nœuds, de conteneurs ou de services, etc. du cluster.
Si nous voulons augmenter le nombre de réplicas d’un service nous utiliserons la commande suivante :
docker service scale "nom_du_service=nombre"
Prenons par exemple le service « web » que nous avons créés précédemment en un exemplaire pour l’augmenter.
Vérifions maintenant le nombre de réplicas de ce service
Nous retrouvons effectivement 6 réplicas de ce service hébergés sur les nœuds « Worker » de notre cluster.
Pour rappel le lab contient 5 nœuds dont deux sont des « Manager » au statut « drain » indiquant qu’ils ne sont pas disponible pour héberger des services, conteneur etc. et qu’ils seront utilisés uniquement pour la gestion du cluster lui-même.
C’est d’ailleurs pour cela que nos 6 réplicas sont répartis en 2 exemplaires sur nos 3 « Workers ».
De la même manière que nous pouvons augmenter le nombre de réplicas d’un service, nous pouvons également les diminuer.
La commande à utiliser est la même que pour l’augmentation.
docker service scale "nom_du_service=nombre"
La seule différence sera le nombre de réplicas que l’on indiquera dans la commande.
Si l’on vérifie, nous n’avons effectivement plus que 3 réplicas du service « web »
Il ne s’agit bien évidemment pas des seules interactions que l’on peut avoir avec un service.
Les différentes options sont visibles à l’aide de la commande « --help »
Comme nous l’avons vu précédemment, pour lister les différents services qui tournent dans notre cluster nous utiliserons la commande :
docker service ls
Nous avons aussi vu que nous pouvions avoir plus d’information en ciblant directement un service :
docker service ps "nom_du_service"
Comme tout élément lié à Docker, nous avons également la possibilité d’inspecter les services.
Par exemple nous pouvons inspecter le service web que nous avons créé.
docker service inspect "nom_du_service"
Attention la capture d’écran ne reflète pas la longueur du rendu.
docker service inspect "nom_du_service" --pretty
Pour supprimer un service nous utiliserons la commande suivante :
docker service rm "nom_du_service"
On peut vérifier la suppression en listant les services disponibles :
Attention : les conteneurs liés à ce service ne seront aussi supprimés.
docker service logs -f "nom_du_service"
Pour l’instant il n’y a rien car nous ne nous sommes pas encore connecté au serveur web. Ouvrons un navigateur web pour le faire et vérifier si les logs apparaissent.
Les logs sont visibles dans le terminal. On y verra d’ailleurs quelle hôte a répondu à la requête http faite par le client.
Attention : si l’on souhaite avoir des logs en dehors du terminal, il faudra refaire la procédure telle que l’on a pu la voir précédemment.
Nous l’avons déjà vu donc je ne referai pas la démonstration.
Un « scale » de service va permettre d’augmenter ou de diminuer le nombre de réplicas du service.
La commande est identique dans les deux cas :
docker service scale "nom_du_service"="nombre"
Les différentes options utilisables lors de l’update d’un service sont identiques aux options que l’on a pu voir dans le tableau de la section création.
Par exemple, notre service web utilise le port 8080 et nous allons le supprimer.
Pour mettre à jour un service nous utiliserons donc cette commande :
docker service update --options "nom_du_service"
Si l’on vérifie maintenant le service nous ne verrons plus le port :
Nous l’avions évoqué, le « rollback » d’un service permet de revenir en arrière en cas de problème suite à une mise à jour.
Nous retrouverons notre service dans l’état initial dans lequel il se trouvait avant la mise à jour.
Pour cet exemple, nous allons faire un « rollback » sur notre service « web » pour lequel nous venons de supprimer le mappage de port.
La commande à effectuer sera la suivante :
docker service update rollback "nom_du_service"
Si l’on vérifie la présence du port, le mappage 8080 vers 80 sera de nouveau présent :