Tutoriel : Comment installer un Ingress Controller ? #Traefik

Publié le

Ce tutoriel a pour but de montrer comment installer Traefik en tant qu'Ingress Controller dans un cluster Kubernetes.

Aperçu de Traefik

Traefik est un reverse proxy qui propose entre autre des fonctionnalités de load balancing, une mise à l'echelle facilitée, la possibilité de mettre en place des endpoints HTTPS, des demandes de certificats TLS via Let's Encrypt ou tout autre provider conforme au protocole ACME, etc.. Par contre, pour que cette dernière fonctionnalité soit opérationnelle en environnement distribué, il faudra soit opter pour Traefik Entreprise, soit installer un outil comme cert-manager.

En terme d'observabilité, Traefik est un très bon produit, puisqu'il est possible d'externaliser ses logs. De plus, il implémente de base un exporter Prometheus, ce qui permet d'avoir des metrics. Pour compléter cet ensemble, les problèmes de configuration sont très faciles à repérer grâce au dashboard intégré.

Enfin, Traefik s'intègre très bien avec Kubernetes, sous la forme d'un Ingress Controller. On a alors le choix d'utiliser des objets de type Ingress, ou alors d'utiliser les CRD (Custom Resource Definition) de Traefik : IngressRoute, Middleware, etc. Les options de configuration sont assez poussées grâce aux CRDs.

Prérequis

Il nous faut un cluster Kubernetes opérationnel, et Helm 3 de disponible. Helm permet de faciliter l'installation d'applications dans le cluster, un peu comme un gestionnaire de paquets d'une distribution Linux.

Mon labo Kubernetes permet de disposer de ce type d'environnement rapidement : il suffit de créer le cluster avec la commande make start. L'accès aux commandes helm et kubectl se fait après s'être connecté à l'API server, grâce à la commande vagrant ssh control-plane, puis sudo su -.

Ajout du dépôt Helm

La première étape est d'ajouter le dépôt de Traefik à Helm :

helm repo add traefik https://helm.traefik.io/traefik
helm repo update

Installation de Traefik

Nous pouvons maintenant installer Traefik à partir de sa chart Helm.

Un grand nombre de paramètres de déploiements sont personnalisables, mais un des choix les plus importants est de définir si l'on veut déployer sous la forme d'un Deployment ou d'un DaemonSet.

L'installation de Traefik sous la forme d'un Deployment est une méthode très intéressante, car elle permet une mise à l'echelle (scalabilité) plus forte qu'une installation sous la forme d'un DaemonSet. En effet, dans cette configuration, des Pods supplémentaires peuvent être réservés en modifiant le nombre de replicas du deploiement. On peut même mettre en place un HorizontalPodAutoscaler pour le faire automatiquement en fonction des ressources consommées.

Avec un DaemonSet, le nombre de Pods est limité à un seul par nœud du cluster, ce qui peut potentiellement causer des soucis de mise à l'échelle sur des grosses installations.

Dans tous les cas, nous commençons par créer un namespace dédié aux add-ons du cluster :

kubectl create ns kube-platform

Installation sous forme de Deployment

L'installation avec les paramètres par défaut se fait sous la forme d'un Deployment, et le point d'entrée de l'Ingress Controller est un service de type LoadBalancer. Nous choisissons d'activer les logs d'accès (accesslog) et les metrics, ce qui facilitera la mise en place d'outils dédiés à l'observabilité par la suite.

L'installation se fait avec la commande suivante :

helm upgrade -i --namespace=kube-platform traefik traefik/traefik \
    --set=additionalArguments="{--accesslog=true,--metrics=true,--metrics.prometheus=true}"

Ce paramétrage fonctionne avec la plupart des fournisseurs de Cloud (ceux qui supportent les services de type LoadBalancer).

Cette option d'installation présente par contre un petit défaut : les logs d'accès ne contiendront pas l'adresse IP des clients, car les Services LoadBalancer et NodePort reposent sur la translation d'adresses snat. En d'autres termes, l'adresse IP d'un client est substituée par l'adresse IP du nœud qui accepte la connexion. Le déploiement "voit" donc les connexions comme venant de l'adresse IP de ce nœud.

Alternative : installation avec un service de type NodePort

Si votre fournisseur de Cloud ne supporte pas les services de type LoadBalancer, ou si nous voulons implémenter nous-même le load balancer (avec HAProxy par exemple), il sera alors utile d'activer proxy protocol : ça permet de préserver l'adresse IP du client dans les logs d'accès. Certains fournisseurs de cloud comme Scaleway proposent des load balancers qui supportent directement proxy protocol.

Si l'on choisit d'utiliser proxy protocol, il faut indiquer à Traefik, depuis quels réseaux vont venir les requêtes depuis le load balancer. Ça se fait avec l'argument --entryPoints.web.proxyProtocol.trustedIPs=<liste des réseaux autorisés>.

La commande d'installation devient alors :

helm upgrade -i --namespace=kube-platform traefik traefik/traefik \
    --set=additionalArguments="{--entryPoints.web.proxyProtocol.trustedIPs=127.0.0.1/32\,10.0.0.0/8,--accesslog=true,--metrics=true,--metrics.prometheus=true}" \
    --set=ports.web.nodePort=32080 \
    --set=ports.websecure.nodePort=32443 \
    --set=service.type=NodePort

Il faut bien sûr adapter le réseau autorisé à votre propre configuration.

Installation sous forme de DaemonSet

Avec un déploiement sous la forme d'un DaemonSet, Traefik écoute directement sur les ports 80 (HTTP) et 443 (HTTPS) des nœuds. Il suffit alors de placer un load balancer devant ces nœuds pour répartir le trafic entrant efficacement dans le cluster.

Avec un fournisseur comme Exoscale, il suffit de partager une adresse IP "elastic" entre les nœuds, et le tour est joué : c'est très facile et peu coûteux 👍🏻. Pour une utilisation en production, on peut automatiser le fail-over avec un déploiement de leur outil exoip lui aussi sous la forme d'un DaemonSet.

Pour que Traefik écoute sur les ports 80 et 443, il est nécessaire d'accorder les droits root au container (nécessaire quand un processus écoute sur des ports inférieurs à 1024). On en profite pour placer les containers sur le réseau hôte du nœud (hostNetwork), ce qui améliore grandement les performances du réseau, en plus de conserver l'adresse IP des clients qui se connectent. Il n'y a plus besoin d'un service NodePort.

Il faut reconnaitre que du point de vue de la sécurité, ce n'est pas le setup idéal (container "root" et utilisation du réseau hôte), mais on a des performances qui seront au top dans la plupart des cas.

La commande pour faire l'installation est la suivante :

helm upgrade -i --namespace=kube-platform traefik traefik/traefik \
    --set=deployment.kind=DaemonSet \
    --set=additionalArguments="{--accesslog=true,--metrics=true,--metrics.prometheus=true}" \
    --set=hostNetwork=true \
    --set=ports.traefik.port=9000 \
    --set=ports.web.port=80 \
    --set=ports.websecure.port=443 \
    --set=service.enabled=false \
    --set=securityContext=null

Accès au Dashboard

Par défaut, le dashboard est disponible depuis le port 9000 des pods de Traefik. Pour y accéder, la solution la plus simple est de créer un Ingress vers ceux-ci. Cette solution n'est pas terrible d'un point de vue de la sécurité, on préfèrera plutôt y accéder ponctuellement. Dans ce cas, on utilisera la fonction de port forwarding de kubectl.

Note : avec l'installation sous forme de DaemonSet, l'accès au dashboard de Traefik peut se faire directement depuis l'adresse IP d'un des nœuds, sur le port 9000. Dans mon labo Kubernetes avec Vagrant, une possibilité est d'y accéder depuis le premier nœud. Le dashboard doit toujours être accessible uniquement par un moyen sécurisé, car il expose des informations potentiellement critiques.

La solution d'installer Traefik sous la forme d'un DaemonSet nécessite donc de paramétrer correctement un pare-feu pour filtrer les accès au port 9000 depuis le réseau public.

Depuis le Deployment

Avec l'installation sous forme de Deployment, l'accès au dashboard se fait depuis une machine qui a accès au cluster avec la commande kubectl. Dans de nombreux cas, ça sera la machine locale qui se connecte directement à l'API server.

Dans mon labo Kubernetes avec Vagrant, c'est l'utilisateur root du control-plane qui a un tel accès ; il faut donc commencer par ouvrir un tunnel SSH vers le control-plane :

# export de la configuration SSH de vagrant
vagrant ssh-config > ssh-config

# connexion au control-plane du cluster, tout en ouvrant un tunnel sur le port 9000 (pour le dashboard de Traefik)
ssh -L 9000:127.0.0.1:9000 -F ssh-config control-plane

# dans le projet Vagrant, seul l'utilisateur root peut utiliser kubectl
sudo su -

Nous listons les Pods disponibles dans le namespace où nous avons installé Traefik :

kubectl -n kube-platform get pods

La commande nous renvoie ce genre de sortie :

NAME                       READY   STATUS    RESTARTS   AGE
traefik-6bccd9df87-d7xzl   1/1     Running   0          12m

Avec kubectl, nous pouvons ensuite rendre accessible le port 9000 du Pod directement sur le control-plane.

kubectl -n kube-platform port-forward pod/traefik-6bccd9df87-d7xzl 9000:9000

Nous obtenons cette sortie :

Forwarding from 127.0.0.1:9000 -> 9000
Forwarding from [::1]:9000 -> 9000
Handling connection for 9000

Dans le cadre du labo Vagrant, avec le Deployment, le port 9000 est donc forwardé deux fois : une fois depuis le Pod vers le control-plane (avec kubectl), et une autre fois depuis le control-plane vers notre machine de travail (avec ssh -L ...).

Depuis le DaemonSet

Avec le DaemonSet, pour accéder au dashboard dans le cadre d'une installation sécurisée avec un pare-feu, il suffit d'ouvrir un tunnel SSH vers un des nœuds du cluster. Dans mon labo Vagrant, une solution possible est la suivante :

# export de la configuration SSH de vagrant
vagrant ssh-config > ssh-config

# connexion le premier nœud du cluster, tout en ouvrant un tunnel sur le port 9000 (pour le dashboard de Traefik)
ssh -L 9000:127.0.0.1:9000 -F ssh-config worker-1

Accès au travers d'un navigateur

Une fois ces opérations effectuées, que ce soit avec le Deployment ou le DaemonSet, le dashboard est accessible à partir d'un navigateur internet, depuis l'adresse locale sur le port 9000 : http://127.0.0.1:9000/dashboard/.

Il faut bien mettre un "/" à la fin de l'adresse, sinon nous recevons une erreur. Le dashboard ressemble à ceci :

Capture d’écran 2021-02-25 à 22.06.48.png

Conclusion

L'installation de Traefik avec une configuration de base est à la portée de tous. Par contre, nous n'avons pas couvert un grand nombre de paramètres de la chart Helm. Les autres options sont visibles dans le fichier values.yaml par défaut, et sont bien documentées. Ce fichier est disponible dans le dépôt de la chart.

Parmi les autres options intéressantes, si on utilise un Deployment, il est vivement recommandé de mettre en place un PodDisruptionBudget (option podDisruptionBudget) et l'autoscaling (option autoscaling).

Dans tous les cas, mettre en place la limitation des ressources tant en CPU qu'en mémoire (option resources) est une nécessité absolue ! Les valeurs à mettre en place dépendent fortement du trafic entrant dans le cluster et du nombre de règles de routage (Ingress, et IngressRoute) : c'est une métrique à surveiller dans le temps, surtout au début de l'utilisation du cluster avec Traefik.

Autres références

PHILIPPE CHEPY

Administrateur Système et Développeur