TP Kubernetes
Prise en main
Installation de snap
Tout d'abord, si ce n'est pas déjà fait, installez snap:
sudo apt-get update
sudo apt-get install snapd
Installation et conf de base
Puis installez MicroK8s via snap et configurer-le pour l'utilisateur de la VM:
sudo snap install microk8s --classic
sudo usermod -a -G microk8s $USER
sudo chown -f -R $USER ~/.kube
su - $USER
Vérifiez que le cluster Kubernetes fonctionne correctement :
microk8s status --wait-ready
Vous pouvez récupérer la liste des noeuds (un seul par défaut) :
microk8s kubectl get nodes
Afin de faciliter la suite et de rester vanilla, ajouter l'alias suivant :
alias kubectl='microk8s kubectl'
echo "alias kubectl='microk8s kubectl'" >> ~/.bashrc
Services de base
MicroK8s est un déploiement minimal de Kubernetes. Vous pouvez lister les pods déployés par défaut :
kubectl get pods -A
Il s'agit uniquement des pods Calico, le plugin CNI (Container Network Interface) qui gère le réseau pour les conteneurs.
Vous allez ajouter deux services importants généralement déployés sur les cluster Kubernetes :
- metrics-server pour l'accès aux métriques de base ;
- CoreDNS pour la resolution DNS interne.
metrics-server
Actuellement, vous n'avez pas accès aux métriques :
kubectl top nodes
kubectl top pods -A
Déloiyez metrics-server et vérifiez que le pod correspondant tourne bien :
microk8s enable metrics-server
kubectl get pods -A
Après quelques dizaine de secondes, les métriques devraient être disponibles :
kubectl top nodes
kubectl top pods -A
CoreDNS
Pour tester le service de DNS (qui est derrière le mécanisme de Service Discovery), lançez un pod nginx et vérifiez qu'il tourne :
kubectl run --image nginx web
kubectl expose pod web --port 80
kubectl get pods -o wide
kubectl get service
Essayez de l'atteindre depuis un autre pod, via son IP, l'IP du service, puis le nom DNS du service :
kubectl run --rm --restart=Never -i -t --image busybox test /bin/sh
wget -O- $ip_du_pod_nginx
wget -O- $ip_du_service
wget -O- web
Déployez CoreDNS, vérifiez qu'il tourne bien et testez à nouveau la résolution DNS :
microk8s enable dns
kubectl get pods -A
kubectl run --rm --restart=Never -i -t --image busybox test /bin/sh
wget -O- web
Nettoyage
kubectl delete service web
kubectl delete pod web
Vapormap
Nous allons lancer trois pods: un pour Mariadb, un pour l'application Django, et un pour notre frontal NGINX. Ces pods seront contrôlés par des Deployments, ce qui permet de les relancer automatiquement en cas de défaillance.
Mariadb
Premier déploiement
Astuce: pour générer les manifestes yaml facilement, vous pouvez utiliser la commande kubectl
avec les options --dry-run -o yaml
:
kubectl create deployment mariadb --image mariadb --dry-run=client -o yaml > mariadb.yml
Lancez le déploiement (1 réplicas) :
kubectl apply -f mariadb.yml
Surveillez l'état du pod :
kubectl get pods -w
Debug
Le pod mariadb-* produit une erreur. Pour la comprendre :
kubectl describe pod mariadb-*
L'erreur est Back-off restarting failed container
, ce qui signifie que le pod redémarre sans cesse. Pour examiner plus précisément l'activité d'un conteneur du pod :
kubectl logs mariadb-*
On voit qu'il manque des options (variables d'environnement) pour le que conteneur mariadb démarre correctement. Définissez les variables MYSQL_ROOT_PASSWORD, MYSQL_USER, MYSQL_PASSWORD et MYSQL_DATABASE dans le fichier mariadb.yml
à l'aide du champ env.
Dans la suite, nous verrons comment éviter les secrets en clair... Si nous avons le temps ;)
Une fois les variables définies, réappliquez les changements et vérifiez que le pod tourne :
kubectl apply -f mariadb.yml
kubectl get pods -w
Tests
Pour tester facilement que le pod mariadb répond correctement, et pour les futurs debug, vous pouvez utiliser la commande kubectl port-forward
:
kubectl port-forward mariadb-* 3306:3306
telnet localhost 3306
Nous avons vu que les pods et leur configuration réseau sont temporaires. Afin de les exposer de manière pérenne, déplyez une service comme dans la première partie. Utilisez la même astuce du dry-run pour générer le fichier :
kubectl expose deployment mariadb --port=3306 --target-port=3306 --dry-run=client -o yaml > mariadb-service.yml
kubectl apply -f mariadb-service.yml
Ainsi, le nom DNS mariadb pointera vers le pod correspondant. Vous pouvez créer un pod temporaire afin de vérifier la résolution DNS, et le bon fonctionnement du serveur mariadb.
kubectl run --rm --restart=Never -i -t --image busybox test /bin/sh
telnet mariadb 3306
Vapormap
Déploiement de vapormap (à vous de jouer)
Sur l'exemple des manifests mariadb, créez un manifest pour déployer les conteneurs vapormap et nginx, avec 2 replicas pour nginx et 3 pour vapormap.
Vous pouvez déclarer plusieurs objets dans le même fichier en les séparant par la ligne ---
Pensez à :
- Spécifier les images correspondantes, Si vous n'avez pas vos propres images, vous pouvez utiliser les suivantes :
registry.plmlab.math.cnrs.fr/resinfo/anf/2019/ada/vapormap/vapormap:master
registry.plmlab.math.cnrs.fr/resinfo/anf/2019/ada/vapormap/nginx:master - Positionner les variables VAPOR_DBNAME, VAPOR_DBUSER, VAPOR_DBPASS, DJANGO_SETTINGS_MODULE et VAPOR_DBHOST pour le conteneur vapormap ;
- Positionner les variables VAPORMAP_URL et VAPORMAP_PORT pour le conteneur nginx ;
- Spécifier les ports pour chaque conteneur ;
- Créer les services correspondants.
Après avoir appliqué le manifeste, vérifez que vous accédez aux conteneurs avec kubectl port-forward
.
Migration de base
L'application ne marchera pas en l'état, puisqu'il faut lancer les migrations de base avant de lancer l'application Django. Ajoutez un initContainer au déploiement varpomap, dont le rôle sera d'éxecuter la commande python manage.py makemigrations && python manage.py migrate
Verifiez le bon fonctionnement de l'application à l'aide de :
kubectl port-forward svc/nginx 8000:8000
Ingress
Maintenant, nous allons exposer l'application au monde extérieur grâce à l'objet Ingress :
cat <<EOF > ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vapormap
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 8000
EOF
kubectl apply -f ingress.yml
Pour l'instant l'objet Ingress est bien inutile car aucun Ingress Controler n'est déployé dans le cluster. Ajoutons Traefik, un Ingress Controler léger et rapide :
microk8s.enable traefik
kubectl get pods --all-namespaces
Par défaut, Traefik écoute sur port 8080. Vous n'avez désormais plus besoin de port-forward (qui est un mécanisme prévu pr le debug) pour accéder à votre application :
firefox http://localhost:8080
3. Aller plus loin
Ressources
Afin de limiter l'usage des ressources par les pod, et de faciliter le travail du scheduler, il est fortement conseillé de spécifier des Resources. Vous pouvez par exemple configurer le pod nginx avec 2Mo/10Mo, et le pod vapormap avec 40Mo/80Mo.
Secrets
Dans le TP, les secrets sont dans le dépôt, ce qui est évidemment un mauvaise pratique. En pratique, l'API Kubernetes comporte un objet (que l'on a utilisé pour configurer la registry docker) qui permet de séparer les secrets des déploiements : l'objet Secret. Ajouter un secret avec les différentes variables d'environnement nécessaire, et modifier les déploiements mariadb et vapormap afin qu'ils utilisent le secret comme variable d'environnement. Par la suite, on peut utiliser sops pour chiffrer les secrets yaml et les ajouter au dépôt en tout confiance...
Volume
Vous aurez remarqué que nous n'abordons pas la problématique de la persistance, par manque de temps. Cet problématique est résolue par Kubernetes grâce aux Volumes. L'API est capable de communiquer avec le cloud sous-jacent (par exemple cinder, dans le cas d'Openstack), mais aussi de tailler des volumes iSCSI, nfs, etc...
NetworkPolicy
Par défaut, la base mariadb est accessible à tous les pods du cluster. Vous pouvez limiter les pods qui y ont accès à l'aide d'une NetworkPolicy. Utilisez le namespaceSelector qui correspond à votre namespace, et le label app: vapormap
.
Helm
Vous trouverez dans le repertoire helm un chart qui permet de déployer Vapormap à l'aide de Helm, un gestionnaire de paquets pour Kubernetes. Le chart se base lui-même sur le chart MariaDB de Bitnami.