Déploiement WordPress et MySQL sur un Cluster Kubernetes via Openstack

  • Adrien 

Dans le cadre du partenariat entre INGENIANCE et City Network, un projet a été lancé par le Lab DevOps. Ce projet consiste en un déploiement d’une application containérisée (WordPress + MySQL) sur un cluster Kubernetes via un cloud Openstack.

Pourquoi Kubernetes ?

Dans le cadre d’applications containérisées, il est nécessaire de pouvoir déployer et gérer ces applications facilement. Pour ce faire, un orchestrateur est l’outil indispensable.

Actuellement, Kubernetes est l’un des orchestrateurs les plus populaires. C’est le géant Google qui était à l’initiative de ce projet. Maintenant c’est un projet open-source grandissant qui tend à se présenter comme le leader du marché de l’orchestration de containeurs. Cela est dû à la maturité de la solution par rapport à ses concurrents directs (Mesos, Docker Swarm).

Kubernetes et Openstack

Ce projet déploie notre application sur le cloud de City Network qui utilise Openstack.

Openstack est un ensemble de logiciels open-sources permettant de déployer et de manager les ressources du cloud. Openstack possède un programme d’orchestration, l’objectif étant de créer un service « human- and machine- accessible » pour gérer l’ensemble du cycle de vie des ressources d’un cloud Openstack.

On a d’un côté Heat, le projet principal dans ce programme. Il implémente un moteur d’orchestration pour déployer des ressources sur le cloud en se basant sur des templates.

De l’autre côté, on a Magnum qui permet de faire évoluer les orchestrateurs, comme Kubernetes ou Docker Swarm, en ressources de première main. Magnum utilise une image qui contient Docker et Kubernetes et lance cette image sur une machine virtuelle.

Le projet

Comme précisé plus tôt, on souhaite déployer automatiquement une application sur un Cluster Kubernetes. C’est WordPress qui a été choisie comme application avec une base de données MySQL.Pour ce projet, nous nous basons sur la documentation de Kubernetes qui présente un exemple de déploiement manuel de cette application (Retrouvez ce tutoriel ici ).

Présentons rapidement le setup initial du projet. Toutes les tâches sont exécutées depuis un serveur Ubuntu hébergé par le cloud de City Network.

Concernant l’arborescence du projet :

  • Le dossier Ansible/ qui contient tout les rôles et playbook Ansible utilisés pour automatiser la création du cluster Kubernetes et de déploiement de l’application
  • Le dossier Openstack/ contient tous les fichiers de configuration requis pour pouvoir créer toutes les ressources nécessaires au déploiement de WordPress

C’est grâce à un pipeline du CI/CD de Gitlab que seront exécutées toutes les tâches nécessaires. La configuration de ce pipeline est contenue dans le fichier .gitlab-ci.yml( Plus d’informations sur l’intégration continue de Gitlab ici ). Le pipeline exécute les tâches Ansible contenues dans le dossier du même nom.

Notre pipeline comprend deux étapes :

  • La première appelée infra s’occupe de créer l’ensemble des ressources composant un cluster Kubernetes avec la CLI du projet Magnum
  • La deuxième appelée deploy s’occupe quant à elle de déployer les ressources Kubernetes nécessaires pour le fonctionnement de l’application.

Le pipeline est exécuté par des runners qui sont créés sur le serveur mentionné plus haut.

Passons en revue les tâches exécutées pendant ces deux étapes. Tout d’abord la première partie, l’étape de création d’infrastructure :

  • Premièrement, on commence par générer deux fichiers openrc et clouds.yaml. Ces deux fichiers contiennent les paramètres nécessaires pour s’authentifier sur le cloud.
  • Ensuite on crée une keypair qui sera associée au cluster lors de sa création. Cette clé est par exemple nécessaire si l’on souhaite accéder au nœud du cluster via SSH.
  • Puis vient la création du cluster Kubernetes. C’est lors de cette tâche que l’on utilise la CLI de Magnum. La CLI a besoin de certains paramètres comme le nombre de nœuds minions que l’on souhaite, ou même la taille du cluster.
  • Ce projet déploie de plus un dashboard Horizon. Horizon est l’un des projets de Openstack qui fournit une interface graphique pour ce type de cloud. Ce dashboard permet donc d’avoir un retour graphique sur l’état des ressources mais aussi de les manipuler.

La création du cluster prend en moyenne une dizaine de minutes. Lorsque que cela est fait la deuxième étape du pipeline commence automatiquement.

Avant de passer à la deuxième partie, attardons-nous un instant à quelques paramètres passés à la commande Magnum pour créer ce cluster Kubernetes :

keypair: 'magnum_key'
cluster_template: 'F26-large'
node_count: 1
master_count: 1
  • keypair : Le nom de clé qui a été créé avant la création du cluster
  • cluster_template : Indique le template du cluster à utiliser. Ce template contient notamment le type du cluster (Kubernetes dans notre cas), la taille du cluster (RAM, CPU, Stockage). Pour pouvoir utiliser ces templates, ils doivent au préalable avoir été mis à disposition sur le cloud. Pour afficher la liste des templates disponibles magnum cluster-template-list
  • node_count et master_count : Respectivement le nombre de nœuds minions et master pour le cluster

Lorsque le cluster est créé, on peut visualiser l’ensemble de l’infrastructure grâce au dashboard Horizon.

Il faut maintenant déployer l’application WordPress. C’est donc la deuxième étape du pipeline :

  • Le runner étant différent de l’étape précédente, il nous faut de nouveau générer les deux fichiers openrc et clouds.yaml
  • Ensuite nous allons créer toutes les ressources kubernetes nécessaires au déploiement de notre application, dans un ordre bien précis. Pour faire cela, c’est la CLI kubectl (via un module Ansible) qui est utilisée et qui va lire les différents fichiers de configuration décrivant les ressources. Ces fichiers sont écris en .yaml
  • La dernière étape consiste à associer le load balancer, qui a été créé à l’étape précédente, à une floating ip. Cette étape a dû être rajoutée car la version Openstack installée sur le cloud ne permettait pas de le faire automatiquement depuis les fichiers de configuration correspondants.

Après cette étape, et une fois que les ressources ont été créées, l’application est disponible.

Voici l’ensemble des ressources déployées lors du pipeline :

osDeployK8s_list_of_deployments:
    - 'namespace.yml'
    - 'storage-class.yml'
    - 'config-map.yml'
    # Heapster
    - 'heapster/rbac.yml'
    - 'heapster/controller.yml'
    - 'heapster/controller2.yml'
    - 'heapster/controller3.yml'
    # MySQL
    - 'svc/mysql.yml'
    - 'svc/mysql-read.yml'
    - 'statefulset/mysql.yml'
    # WordPress
    - 'svc/wordpress.yml'
    - 'pvc/wordpress.yml'
    - 'deploy/wordpress.yml'
    - 'hpa/wordpress.yml'
  • namespace.yml : le namespace où l’on déploie l’ensemble des ressources, utile pour les retrouver rapidement et les ségréger par projet/département.
  • storage-class.yml : c’est la ressource qui permet de gérer la façon dont les données de l’application seront stockées. On y reviendra de manière plus précise en parlant des persistent storage.
  • config-map.yml : Contient la configuration souhaitée pour chaque noeuds et/ou pods du cluster
  • heapster/*.yml : Heapster permet de récupérer certaines mesures sur le comportement du cluster. Ces quatres ressources sont donc nécessaires même si elles viennent simplement compléter le déploiement de l’application WordPress. C’est uniquement pour la scalabilité que Heapster est utile.

  • Mysql profite de trois ressources :

    • Deux services, l’un d’eux pour la lecture de la base de données uniquement, ce qui permet de répartir efficacement le flux de requête, le second concerne l’écriture.
    • un statefulset qui, comme un deployment, va déployer les images des applications mais va maintenir une identité propre pour chacun des pods créés par ce dernier.
  • WordPress lui a besoin de 4 ressources :
    • Le service WordPress qui est lié à un load balancer, accessible donc par internet.
    • le Persistent Volume Claim qui utilise la Storage Class mentionné pour pour pouvoir créer le type de volume souhaité. On en parlera aussi dans une autre partie.
    • Le Deployement qui s’occupe de déployer l’image WordPress dans les différents pods.
    • Finalement le Horizontal Pod Scaler qui avec les métriques (RAM & CPU) provenant de Heapster pourra créer ou supprimer des pods selon l’utilisation qui est faite de l’application.

Le cluster Kubernetes est créé, l’application y est déployée avec l’ensemble des ressources citées plus haut.

On peut donc y accéder depuis un navigateur avec l’adresse IP du load balancer.

WordPress nécessite d’être installé. Une fois cela fait le blog est disponible, on pourra donc y créer de nouveaux utilisateurs, de nouveaux articles, etc.

Persistent Storage

L’objectif du Persistent Storage est de sécuriser les données de l’application. S’il y a un problème avec une ressource et/ou le cluster, étant donné que les données sont stockées dans des volumes à part, les données sont récupérables. De cette façon les données sont complétement séparées de la partie infrastructure.

Comment cela fonctionne-t-il dans le cas d’un cluster Kubernetes sur un cloud Openstack ? Openstack fournit un service de stockage, Cinder. Dans ce projet, on utilise donc des volumes Cinder pour stocker les données que ce soit du côté de WordPress ou de Mysql.

Il faut maintenant « dire » à Kubernetes d’utiliser Cinder lorsque des volumes doivent être créés. C’est l’objectif d’un Storage Class :

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
    name: cinder-storage
    namespace: wordpress
provisioner: kubernetes.io/cinder
parameters:
    type: volumes_hdd
    availability: nova

La ligne importante ici est provisioner: kubernetes.io/cinder qui signifie à Kubernetes que c’est Cinder que l’on souhaite utiliser. Ce Storage Class pour un Deploy doit être associé à Persistent Volume Claim, ce qui est le cas pour WordPress ici. Pour le Statefulset c’est différent, il faut intégrer directement le contenu du Storage Class dans le Statefulset.

Pour tester cette persistance, il est possible de supprimer certaines ressources puis de les recréer et témoigner que l’application est toujours disponible et la totalité des données encore présentes.

Scalabilité

Ce projet démontre la capacité d’un cluster Kubernetes à scale selon certaines metrics. Scale up en créant de nouveaux pods, pour faire face à une utilisation croissante de l’application déployée mais aussi de scale down lorsque certains des pods créés ne sont plus nécessaires.

Comme cité précédemment, il faut pourvoir mesurer l’utilisation de l’application qui est déployée. Dans notre projet nous utilisons Heapster, qui va collecter et interpréter différents signaux comme l’utilisation des resources, les événements etc.

Il faut tout de même noter que Heapster tend à ne plus être utilisé au profit d’autres services comme metric-server. Mais nous avons tout de même choisi Heapster car il est plus facile à mettre en place, notamment dans le cadre d’un tel projet.

Comment cela fonctionne-t-il ? Tout d’abord il faut choisir sur quoi baser le scaling. Dans notre cas nous avons choisi la mémoire et le CPU mais il est tout à fait possible de le faire sur le nombre de requêtes par exemple.

Voyons le fichier de configuration hpa/wordpress.yml :

apiVersion: autoscaling/v2alpha1
kind: HorizontalPodAutoscaler
metadata:
  name: wordpress
  namespace: wordpress
spec:
  scaleTargetRef:
    apiVersion: extensions/v1beta1
    kind: Deployment
    name: wordpress
  minReplicas: 2
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      targetAverageUtilization: 60
  - type: Resource
    resource:
      name: memory
      targetAverageUtilization: 60

On peut voir que c’est le Deployment WordPress qui est la cible, i.e. la ressource qui doit scale.

On peut aussi constater que nous surveillons deux types de ressources cpu and memory. Le nombre 60 après targetAverageUtilization est un pourcentage, si le pourcentage d’utilisation de la mémoire et/ou du processeur passe au dessus de 60%, de nouveaux pods seront créés.

On peut stresser le site internet en simulant son utilisation (création de post, de commentaires …). Dans notre projet nous utilisons un utilitaire de test, Tsung, qui requête en boucle l’API de notre site WordPress.

Après une phase de stressing, on peut voir ci-dessous une utilisation supérieure à 60% de la mémoire et du processeur. Ce qui implique qu’il y ait actuellement 4 replicas, cela pour faire face à la forte utilisation de l’application.

Tsung fournit un rapport complet sur la simulation. On peut par exemple voir le nombre d’utilisateurs en fonction du temps. On remarquera deux pics: l’un vers 180 secondes, l’autre vers 450 secondes.

Si l’on compare cela à un autre graphique, par exemple le taux des différentes réponses http, on voit que ces deux pics correspondent à une augmentation du nombre d’erreur 500.

Pourquoi a t-on des erreurs 500 quand le nombre d’utilisateurs augmente ? Parce que c’est à ce moment que le cluster crée de nouveaux pods pour faire face à l’augmentation du flux de requêtes. Les erreurs 500 sont dues au fait que les pods créés sont utilisés trop hâtivement alors qu’ils ne sont pas prêts. Il est tout a fait possible de creuser ce problème, dans des environemments de production, afin de le réduire, ou mieux, de l’éliminer.

Conclusion

Que nous apporte un tel projet ? Tout d’abord de l’expertise sur des sujets tels que Kubernetes, Openstack et plus généralement sur des offres de cloud Platform As A Service. Une offre que notre parteniaire City Network souhaite proposer dans un futur proche, surtout avec l’arrivée de la version Rocky de Openstack. Cette version apportera beaucoup de polyvalence dans le déploiement d’ochestrateur sur un cloud Openstack.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.