Ecran noir

Aller au contenu | Aller au menu | Aller à la recherche

Déploiement de Redis et Sentinel avec Docker swarm mode

Dans ce billet nous verrons comment déployer Redis avec Docker swarm mode de manière hautement disponible grâce à Sentinel. Pour cela nous utiliserons :

  • Une instance master de Redis par laquelle passeront toutes les commandes
  • Une instance slave de Redis permettant de répliquer les données du master
  • 3 instances de Sentinel permettant de basculer sur le slave en cas de crash du master

Infrastructure

Pour déployer ces instances nous disposons de 3 machines (ou VM) qui formeront le swarm :

  • Machine manager - adresse IP 192.168.56.2 : Cette machine fera office de manager du swarm.
  • Machine worker1 - adresse IP 192.168.56.3 : Worker n°1 du swarm.
  • Machine worker2 - adresse IP 192.168.56.4 : Worker n°2 du swarm.

Le problème des adresses IP

Docker swarm mode simplifie grandement le déploiement de services dans un cluster ainsi que la communication entre ces services grâce aux "overlay networks". Cependant, le déploiement de Sentinel pose problème car pour superviser les instances de Redis et communiquer avec les autres instances de Sentinel, il utilise leurs adresses IP qu'il considère comme fixes. Or les services déployés avec Docker swarm ont des adresses IP dynamiques : si un service s'arrête puis redémarre, il n'obtient pas forcément la même adresse IP qu'avant son arrêt. Ce fonctionnement met à mal Sentinel qui ne reconnait plus les instances arrêtées puis redémarrées.

Dans le futur, les évolutions de Docker nous permettrons peut-être d'utiliser un overlay network avec des adresses IP fixes. A l'heure actuelle (version 17.06 de Docker) la seule solution pour obtenir des adresses IP fixes est d'attacher les services sur le réseau de la machine hôte, plutôt que sur un overlay network. Cette solution n'est pas idéale mais c'est la seule qui fonctionne.

Persistance des données

Lorsque Sentinel supervise les instances de Redis, il est susceptible de modifier leur configuration. C'est le cas par exemple lorsqu'un slave devient master suite au crash du master. Pour fonctionner correctement, les instances de Redis et de Sentinel ne doivent pas perdre leur configuration en cas de redémarrage. Il faut donc utiliser des volumes docker pour stocker la configuration.

De plus pour un maximum de sécurité on souhaite stocker sur disque toutes les données de Redis avec l'option appendonly.

J'ai donc créé les 2 images Docker suivantes :

  • ndutertry/redis-ha : Elle permet de lancer un conteneur Redis en master ou slave avec persistance de la configuration et des données.
  • ndutertry/redis-sentinel : Elle permet de lancer un conteneur Sentinel avec persistance de la configuration.

Les sources et les options de configuration de ces images sont disponibles sur GitHub :

Contraintes de déploiement

Les contraintes liées aux adresses IP et à la persistance des données font qu'on ne peut pas laisser à Docker swarm la possibilité de déployer les instances sur n'importe quelle machine. on aura donc :

  • Machine manager : Une instance de Sentinel.
  • Machine worker1 : L'instance Redis master et une instance de Sentinel.
  • Machine worker2 : L'instance Redis slave et une instance de Sentinel.

Création du stack

Il ne reste plus qu'à créer un fichier redis-ha-stack.yml correspondant au schéma suivant :

redis-ha.png

Les services du stack sont décrits ci-dessous.

Service redis-master

  • Il correspond à l'instance master de Redis et il se base sur l'image ndutertry/redis-ha.
  • Il utilise un volume redis-data mappé sur /data pour la persistance des données
  • Il utilise un volume redis-conf mappé sur /etc/redis pour la persistance de la configuration
  • Il est déployé sur worker1
  • Il utilise le réseau de la machine hôte

Dans le stack il sera référencé ainsi :

  redis-master:
    image: ndutertry/redis-ha
    volumes:
      - redis-data:/data
      - redis-conf:/etc/redis
    deploy:
      mode: global
      placement:
        constraints:
          - node.hostname == worker1
    networks:
      - host

Service redis-slave

  • Il correspond à l'instance slave de Redis et il se base sur l'image ndutertry/redis-ha.
  • On positionne la variable d'environnement REDIS_MASTER_HOST utilisée par l'image pour en faire un slave et pointer vers le master.
  • Il utilise un volume redis-data mappé sur /data pour la persistance des données
  • Il utilise un volume redis-conf mappé sur /etc/redis pour la persistance de la configuration
  • Il est déployé sur worker2
  • Il utilise le réseau de la machine hôte

Dans le stack il sera référencé ainsi :

  redis-slave:
    image: ndutertry/redis-ha
    volumes:
      - redis-data:/data
      - redis-conf:/etc/redis
    environment:
      - REDIS_MASTER_HOST=192.168.56.3
    deploy:
      mode: global
      placement:
        constraints:
          - node.hostname == worker2
    networks:
      - host

Service redis-sentinel

  • Il correspond aux 3 instances de Sentinel et il se base sur l'image ndutertry/redis-sentinel.
  • On positionne la variable d'environnement REDIS_MASTER_HOST utilisée par l'image pour pointer vers le master.
  • Il utilise un volume sentinel-conf mappé sur /etc/redis pour la persistance de la configuration
  • Il est déployé en mode global sur tous les noeuds
  • Il utilise le réseau de la machine hôte

Dans le stack il sera référencé ainsi :

  redis-sentinel:
    image: ndutertry/redis-sentinel
    volumes:
      - sentinel-conf:/etc/redis
    deploy:
      mode: global
    environment:
      - REDIS_MASTER_HOST=192.168.56.3
      - SENTINEL_DOWN_AFTER=5000
      - SENTINEL_FAILOVER=15000
    networks:
      - host

Service simple-redis-app

On ajoute également un service simple-redis-app permettant de tester l'accès à Redis en affichant un compteur de visite :

  • On positionne la variable d'environnement SENTINEL_HOST utilisée par l'image pour pointer vers l'une des instances de Sentinel.
  • Il écoute sur le port 3000
  • Il est déployé en 3 instances

Dans le stack il sera référencé ainsi :

  simple-redis-app:
    image: ndutertry/simple-redis-app
    ports:
      - "3000:3000"
    environment:
      - SENTINEL_HOST=192.168.56.2
    deploy:
      replicas: 3

Déploiement

Le fichier redis-ha-stack.yml complet est disponible sur GitHub : https://github.com/nicolas-dutertry...

Dans cette version on a remplacé les adresses IP et les noms des noeuds par des variables d'environnement. Pour déployer le stack avec Docker swarm on peut utiliser le script deploy.sh en passant en paramètre le nom des noeuds manager, worker n°1 et worker n°2 :

$ ./deploy.sh manager worker1 worker2

Test

Pour tester que la solution fonctionne on ouvre tout d'abord dans un navigateur l'url http://192.168.56.2:3000/. On vérifie que le compteur augmente en rafraîchissant la page.

Ensuite on arrête la machine worker1 et après quelques secondes on vérifie que l'application fonctionne toujours. Cela veut dire qu'on a basculé sur le slave, qui est maintenant devenu le master.

On redémarre worker1 et on arrête worker2. L'application fonctionne normalement toujours, puisqu'on a refait la bascule vers le master initial.

Enfin si l'on arrête toutes les machines et que l'on redémarre, on peut vérifier que la valeur du compteur n'a pas été perdue.

Adaptation

L'exemple d'infrastructure présenté ici peut bien entendu être adapté. On pourra par exemple augmenter la robustesse de l'ensemble en ajoutant des machines sur lesquelles se déploieront des instances supplémentaires de Sentinel et de slaves Redis.

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

La discussion continue ailleurs

URL de rétrolien : http://nicolas.dutertry.com/ecran-noir/index.php?trackback/68

Fil des commentaires de ce billet