Pour bien comprendre les explications qui vont suivre, il est nécessaire d’avoir lu les articles précédents.
Il faut garder en tête l’architecture cible et se rappeler qu’il est proposé d’utiliser un rôle Ansible pour préparer les serveurs et les configurations associées à l’initialisation d’un cluster K8S.
Une fois les machines virtuelles déployées à l’aide de OpenTofu (Terraform), la structure du rôle Ansible a été présentée.
Les articles suivants ont eu pour vocation de traiter les actions Ansible.
Arrivé à ce stade, on dispose donc d’un ensemble de serveurs intégrant tout le minimum nécessaire pour se voir utiliser au sein d’un cluster K8S.
Il manque néanmoins les derniers composants externes qui permettront la communication des applications depuis et vers le cluster.
De base, un cluster Kubernetes tourne en circuit fermé. Si aucune stratégie par défaut n’empêche les communications internes du cluster (un point à retenir pour la sécurité), il n’en ai pas de même pour les échanges avec l’extérieur.
Il existe bien quelques briques de bases comme l’usage de service en mode NodePort et kube-proxy pour exposer une application « Kubernetisé » à l’extérieur d’un cluster.
Pour un usage à grande échelle et en production, il est néanmoins nécessaire d’ajouter des composants additionnels.
Dans l’architecture cible, nous allons donc avoir besoin de deux niveaux de loadbalancing.
Ce fonctionnement à deux niveaux est reproduit deux fois, pour le LAN et pour la DMZ, puisqu’on a décidé d’utiliser un seul et même cluster.
Plutôt que de grands discours voici un schéma qui résume le fonctionnement et la cible.
Cliquez sur l'image pour l'agrandir.
Il est important de noter que la logique retenue n’a rien d’une vérité absolue. Plusieurs méthodologies et choix d’outil sont possibles. De même dans un environnement cloud public, le premier niveau de loadbalancing est souvent proposé en natif, et un objet service peut être déclaré en tant que LoadBalancer pour s’intégrer avec la solution du cloud provider.
Me concernant j’ai choisi ce schéma, car mon objectif est de très peu jouer sur le loadbalancing externe (un passage en HA en VRRP est prévu) pour me focaliser sur les fonctionnalités au niveau loadbalancing interne.
Traefik n’est pas le seul Ingress Controller. Haproxy pourrait lui aussi remplir cette fonction, et on n’aurait à la fois du HAProxy en interne et en externe du cluster.
J’apprécie cependant particulièrement Traefik qui offre une approche moderne et performante.
Un Ingress Controller comme son nom l’indique est en charge de la gestion des objets Kubernetes ingress, soit l’objet en charge de l’exposition des services K8S aux requêtes extérieures. C’est lui qui via l’usage de ces objets va gérer la redirection des flux en interne du cluster.
Il est possible d’utiliser un ou plusieurs Ingress Controller au sein d’un même cluster. On peut exploiter un seul et même logiciel, soit déclarer des logiciels différents. On parlera de Class et les objets Ingress pourront être traités par telle ou telle Class d’Ingress Controller.
Chaque Ingress Controller apporte ses spécificités en plus de son rôle de base. Il pourra ajouter des fonctionnalités de réécriture d’URL, de partage de charge, d’ajout de certificats….
Traefik sera déployé sous forme de pod mais à l’exception de tous les autres pods à venir sur le cluster, ils seront les seuls à proposer des conteneurs avec des ports directement rattachés aux hosts. C’est un un cas d’usage à part, mais on le verra plus tard dans la configuration de Traefik.
Enfin, Traefik sera exécuté sur le LAN par les control plane. C’est un choix ouvert à la critique, car dans les bonnes pratiques on évite d’ajouter des dépendances et des rôles sur les control plane. On n’aurait pu faire le choix, comme pour la DMZ, de faire tourner les instances Traefik sur les nodes classiques.
Cette logique s’explique de mon côté par une volonté de mieux optimiser l’usage de mes ressources virtuelles. Sacrifier trois serveurs uniquement pour les control plane sur une infra qui n’accueillera pas des milliards de pods, c’est un peu gâcher me concernant.
C’est pourquoi, au moins sur le LAN, je me suis permis de proposer cette organisation pour solliciter davantage mes control plane. L’impact de cette installation est d’avoir tous les flux extérieurs à destination d’application dans le LAN qui transiteront vers l’un ou l’autre des control plane.
Les flux pourront ensuite être redirigés en interne du cluster vers un node worker contenant un pod associé à l’application accédée.
Concernant la DMZ, l’idée d’avoir des instances traefik dédiées est bien entendu motivée par des contraintes de sécurité.
Commençons maintenant par détailler le fichier Ansible 06-configure-haproxy.yml et traiter le loadbalancing externe.
---
#installation de HA proxy
- name: Install haproxy
become: yes
tdnf:
update_cache: yes
name: "haproxy"
state: present
when: "'TAG-COOLCORP-ROLE-HAPROXY' in tags"
tags: role_k8s_deploy.haproxy.install
#Configuration HA proxy pour le LAN
- name: "Set haproxy LAN configuration"
become: yes
template:
src: "haproxy_lan.cfg.j2"
dest: "/etc/haproxy/haproxy.cfg"
when: "'TAG-COOLCORP-ROLE-HAPROXY' in tags and 'TAG-COOLCORP-NETWORK-LAN' in tags"
tags: role_k8s_deploy.haproxy.haproxy-lan-config
notify:
- restart haproxy
#Configuration HA proxy pour la DMZ
- name: "Set haproxy DMZ configuration"
become: yes
template:
src: "haproxy_dmz.cfg.j2"
dest: "/etc/haproxy/haproxy.cfg"
when: "'TAG-COOLCORP-ROLE-HAPROXY' in tags and 'TAG-COOLCORP-NETWORK-WEB' in tags"
tags: role_k8s_deploy.haproxy.haproxy-dmz-config
notify:
- restart haproxy
#Demarrer HA proxy
- name: "Start HA proxy"
become: yes
systemd:
name: haproxy
state: started
when: "'TAG-COOLCORP-ROLE-HAPROXY' in tags"
tags: role_k8s_deploy.haproxy.haproxy-service
#S'assurer que HA proxy soit actif au démarrage
- name: "Enable proxy"
become: yes
systemd:
name: haproxy
enabled: true
when: "'TAG-COOLCORP-ROLE-HAPROXY' in tags"
tags: role_k8s_deploy.haproxy.haproxy-service
Le fichier est assez simple. On commence par installer HAproxy sur les VMs disposant du tag TAG-COOLCORP-ROLE-HAPROXY. (voir cet article pour une explication de l’usage des tags vmware avec Ansible).
Ensuite on fixe la configuration pour le HAproxy dans le LAN. Comme pour les articles précédents, la logique est toujours la même. On se base sur un template présent dans le dossier templates de l’arborescence Ansible qui sera copié à la destination (sans l’extension j2).
Lors de la copie, les variables présentes dans le template seront remplacées par les valeurs déclarées dans le fichier main.yml du répertoire defaults.(n’hésitez pas à repasser par ici. pour une meilleure compréhension).
Voici le contenu du template haproxy_lan.cfg.j2:
global
defaults
timeout client 30s
timeout server 30s
timeout connect 30s
frontend k8s_master_node_front
bind {{ var_vip_kub_vip }}:{{ var_kube_api_port }}
default_backend k8s_master_node_back
backend k8s_master_node_back
mode tcp
option tcp-check
server prdk8sctp501 192.168.10.71:{{ var_kube_api_port }} check
server prdk8sctp502 192.168.10.72:{{ var_kube_api_port }} check
server prdk8sctp503 192.168.10.73:{{ var_kube_api_port }} check
frontend k8s_master_traefik_http_front
bind {{ var_vip_kub_vip }}:80
default_backend k8s_master_traefik_http_back
backend k8s_master_traefik_http_back
mode tcp
option tcp-check
server prdk8sctp501 192.168.10.71:80 check
server prdk8sctp502 192.168.10.72:80 check
server prdk8sctp503 192.168.10.73:80 check
frontend k8s_master_traefik_https_front
bind {{ var_vip_kub_vip }}:443
default_backend k8s_master_traefik_https_back
backend k8s_master_traefik_https_back
mode tcp
option tcp-check
server prdk8sctp501 192.168.10.71:443 check
server prdk8sctp502 192.168.10.72:443 check
server prdk8sctp503 192.168.10.73:443 check
Le template pourrait être amélioré en variabilisant le nom et les ips des serveurs. C'est une amélioration à apporter pour rendre le template plus portable.
L’idée n’est pas de rentrer dans le détail de la configuration de HAproxy, mais le fonctionnement est assez simple.
On définit les services de front (port et IP) pour les rattacher au serveur de backend (port et IP) vers lesquels renvoyer les requêtes.
Le HAProxy LAN devant etre utilisé pour loabalancer l'API K8S, on retrouve la variable var_vip_kub_vip et var_kube_api_port. Ce sont des variables déja présentés dans l'article précédent pour, notamment la préparation du fichier de configuration de kubeadm.
C’est une version très basique de la configuration de HAproxy. Bien d’autres options sont possibles, notamment sur les checks de disponibilité pour s’assurer que les serveurs de backend répondent correctement (ce n’est parce qu’une connexion se fait sur un port, que le service est opérationnel).
La configuration de HA proxy en DMZ est pratiquement la même que pour le LAN. Le template haproxy_dmz.cfg.j2 utilisé est le suivant:
global
defaults
timeout client 30s
timeout server 30s
timeout connect 30s
frontend k8s_master_traefik_http_front
bind {{ var_vip_kub_vip_dmz }}:80
default_backend k8s_master_traefik_http_back
backend k8s_master_traefik_http_back
mode tcp
option tcp-check
server prdk8snod511 192.168.5.81:80 check
server prdk8snod512 192.168.5.82:80 check
frontend k8s_master_traefik_https_front
bind {{ var_vip_kub_vip_dmz }}:443
default_backend k8s_master_traefik_https_back
backend k8s_master_traefik_https_back
mode tcp
option tcp-check
server prdk8snod511 192.168.5.81:443 check
server prdk8snod512 192.168.5.82:443 check
À la différence du LAN on ne traite pas le loadbalancing de l’API, car cette dernière n’est pas exposée en DMZ (et c’est bien normal).
En fin des actions Ansible on s’assure de l’activation du service HAproxy sur chacun des serveurs, avec un démarrage automatique en cas de redémarrage de la VM.
Le fichier Ansible 07-configure-traefik.yml en charge des actions autour de Traefik est le suivant:
---
#Création des dossier de reception des configurations
- name: Creates traefik configuration directory for admin user
become: yes
file:
path: "/home/{{ var_admin_user}}/{{ var_vip_kub_endpoint }}/traefik"
state: directory
owner: "{{ var_admin_user}}"
mode: 0770
recurse: yes
when: "'TAG-COOLCORP-ROLE-MASTER' in tags or 'TAG-COOLCORP-NETWORK-WEB' in tags"
tags: role_k8s.configure-traefik.directory
#Création de la configuration traefik pour le LAN
- name: "Set traefik lan configuration"
become: yes
template:
src: "traefik-config-lan.yaml.j2"
dest: "/home/{{ var_admin_user}}/{{ var_vip_kub_endpoint }}/traefik/traefik-config-lan.yaml"
owner: "{{ var_admin_user}}"
mode: 0770
when: "'TAG-COOLCORP-ROLE-MASTER' in tags"
tags: role_k8s.configure-traefik.lanconfig
#Création du compte de service pour Traefik en LAN
- name: "Set traefik service lan account"
become: yes
template:
src: "svc-traefik-lan.yaml.j2"
dest: "/home/{{ var_admin_user}}/{{ var_vip_kub_endpoint }}/traefik/svc-traefik-lan.yaml"
owner: "{{ var_admin_user}}"
mode: 0770
when: "'TAG-COOLCORP-ROLE-MASTER' in tags"
tags: role_k8s.configure-traefik.servicelanaccount
#Création de la configuration pour le dashboard Traefik en LAN
- name: "Set traefik dashboard lan configuration"
become: yes
template:
src: "traefik-lan-dashboard.yaml.j2"
dest: "/home/{{ var_admin_user}}/{{ var_vip_kub_endpoint }}/traefik/traefik-lan-dashboard.yaml"
owner: "{{ var_admin_user}}"
mode: 0770
when: "'TAG-COOLCORP-ROLE-MASTER' in tags"
tags: role_k8s.configure-traefik.lan-dashboard
#Création de la configuration traefik pour la DMZ
- name: "Set traefik dmz configuration"
become: yes
template:
src: "traefik-config-dmz.yaml.j2"
dest: "/home/{{ var_admin_user}}/{{ var_vip_kub_endpoint }}/traefik/traefik-config-dmz.yaml"
owner: "{{ var_admin_user}}"
mode: 0770
when: "'TAG-COOLCORP-ROLE-MASTER' in tags"
tags: role_k8s.configure-traefik.dmzconfig
#Création du compte de service pour Traefik en DMZ
- name: "Set traefik service dmz account"
become: yes
template:
src: "svc-traefik-dmz.yaml.j2"
dest: "/home/{{ var_admin_user}}/{{ var_vip_kub_endpoint }}/traefik/svc-traefik-dmz.yaml"
owner: "{{ var_admin_user}}"
mode: 0770
when: "'TAG-COOLCORP-ROLE-MASTER' in tags"
tags: role_k8s.configure-traefik.dmz.servicelanaccount
#Création de la configuration pour le dashboard Traefik en DMZ
- name: "Set traefik dashboard dmz configuration"
become: yes
template:
src: "traefik-dmz-dashboard.yaml.j2"
dest: "/home/{{ var_admin_user}}/{{ var_vip_kub_endpoint }}/traefik/traefik-dmz-dashboard.yaml"
owner: "{{ var_admin_user}}"
mode: 0770
when: "'TAG-COOLCORP-ROLE-MASTER' in tags"
tags: role_k8s.configure-traefik.dmz-dashboard
Le début consiste simplement à préparer les répertoires de travail chargé d’héberger les configurations.
Ensuite, on traite le cas de Traefik en LAN.
On base la configuration sur un template traefik-config-lan.yaml.j2 dont le contenu est le suivant:
image:
name: traefik
tag: "{{ var_version_traefik }}"
pullPolicy: IfNotPresent
deployment:
enabled: true
kind: DaemonSet
labels:
network: lan
podLabels:
network: lan
providers:
kubernetesIngress:
labelSelector: network=lan
kubernetesCRD:
enabled: true
allowCrossNamespace: false
allowExternalNameServices: false
allowEmptyServices: false
namespaces:
- {{ var_namespace_traefik_prd_lan }}
serviceAccount:
name: "{{ var_traefik_lan_service_account }}"
logs:
level: ERROR
hostNetwork: true
ports:
web:
port: 80
ports.web.redirectTo.port: websecure
websecure:
port: 443
securityContext:
capabilities:
drop: [ALL]
add: [NET_BIND_SERVICE]
readOnlyRootFilesystem: true
runAsGroup: 0
runAsNonRoot: false
runAsUser: 0
updateStrategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: 1
type: RollingUpdate
additionalArguments:
- "--providers.kubernetesingress.ingressclass=traefik-lan"
- "--serversTransport.insecureSkipVerify=true"
Ce fichier de configuration a vocation par la suite à être passé en argument de Helm, le gestionnaire de package K8S.
Ainsi on pourra « customiser » le déploiement de Traefik, en commençant par en fixer la version via la variable var_version_traefik.
On poursuit en précisant qu’on souhaite que Traefik soit déployé sous forme de DamonSet.
Nous aurons l’occasion d’en reparler, mais ce type de déploiement permet, entre autre, d’automatiquement ajouter une nouvelle instance de Traefik sur un nouveau node qui remplirait les conditions nécessaires à son exécution.
Notre objectif est ici de se dire que si demain un nouveau control plane est déployé, il sera automatiquement retenu pour exécuter une instance Traefik.
Ensuite nous allons aborder un point important.
Traefik peut s’installer (et s’utiliser) au sein d’un cluster K8S celons deux manières:
Dans notre cas, c’est les deux intégrations qui vont être utilisées. Dans la majorité des cas, je privilégierai la manipulation d’objets Ingress classique.
Mais parfois, pour exploiter des fonctionnalités un peu avancées ou propres à Traefik , je serais obligé d’utiliser un objet customisé. Dans ce dernier cas, je vais limiter la portée à un namespace spécifique représenté par la variable var_namespace_traefik_prd_lan.
Pour fonctionner, Traefik doit échanger avec l’API du cluster, il lui faut donc un compte de service interne autorisé à dialoguer avec cette dernière. Ce compte sera traité par la suite, mais son nom est contenu dans la variable var_traefik_lan_service_account.
Vient ensuite la partie en lien avec ce que j’expliquais un peu plus haut, a savoir l’exposition des pods Traefik directement sur les ports du host, via l’option hostNetwork: true.
Ces mêmes ports sont définis juste en dessous. Le premier, appelé web, écoute sur le port 80 et dispose d’une option pour rediriger automatiquement tous les flux en entrée vers le port 443 nommé websecure. (et voilà comment on fait de la redirection HTTPS simplement et par défaut).
On pourrait définir autant de ports que souhaité, y compris en UDP. Si certaines de vos applications sont à exposer via d’autre port que 80 et le 443, alors il faudra les déclarer à ce niveau.
À noter que le nom web et websecure sont purement arbitraire, vous pouvez choisir les noms de ports que vous voulez, l’important sera de les référencer correctement par la suite.
Le reste des options est propre à l’usage fait dans ce contexte, et traite également de la manière dont seront mises à jour les instances en cas d’upgrade. Je ne vais pas rentrer dans le détail.
Les deux dernières options importantes figurent dans la section additionalArguments.
La première ligne --providers.kubernetesingress.ingressclass= traefik-lan permet de nommer la class de cette ingress contrôleur, comme j’ai pu l’expliquer précédemment.
La seconde, --serversTransport.insecureSkipVerify= true, autorise Traefik à discuter en backend avec des services présentant des certificats invalides. Ce n’est pas le mieux en termes de sécurité, mais c’est beaucoup plus simple à gérer. Maintenant si vous en avez la capacité, je vous encourage à ne pas utiliser cette option.
Les actions suivantes définies dans le fichier Ansible traitent du compte de service, basé lui aussi sur un template svc-traefik-lan.yaml.j2
apiVersion: v1
kind: ServiceAccount
metadata:
name: "{{ var_traefik_lan_service_account }}"
namespace: "{{ var_namespace_traefik_prd_lan }}"
Comme pour le reste, un compte de service est un objet. On pourrait laisser Traefik créer un compte par défaut, mais le fait de le déclarer nous donne une meilleure visibilité sur son usage et surtout ne risque pas de se confondre avec celui utilisé par les instances Traefik en DMZ.
Un autre template est ensuite utilisé traefik-lan-dashboard.yaml.j2.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: traefik-lan-dashboard
namespace: "{{ var_namespace_traefik_prd_lan }}"
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`{{ var_url_traefik_lan }}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
services:
- name: api@internal
kind: TraefikService
middlewares:
- name: traefik-dashboard-lan-auth # Referencing the BasicAuth middleware
namespace: {{ var_namespace_traefik_prd_lan }}
tls:
secretName: sec-certif-traefik-k8s-lan
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: traefik-dashboard-lan-auth
namespace: {{ var_namespace_traefik_prd_lan }}
spec:
basicAuth:
secret: sec-traefik-dashboard-lan-password
Ce fichier va permettre d’exposer le dashboard fournit par Traefik. Il sera exposé sur l’URL var_url_traefik_lan et l’objet sera créé dans var_namespace_traefik_prd_lan.
C’est un dashboard très basique, mais très pratique pour avoir une vue sur l’état de Traefik et des objets associés.
Malgré le fait qu’il ne donne qu’un accès en lecture, il est bon de le protéger par une authentification. C’est le rôle de l’objet Middleware, qui associé à l’objet IngressRoute, va permettre d’afficher un prompt imposant un login/password lors de l’accès à l’URL.
Je ne vais pas rentrer dans le détail à ce niveau, mais ce fichier fait référence à des objets situés dans la branche API traefik.io/v1alpha1. C’est une branche additionnelle de l’API, qui n’existe pas par défaut, mais qui sera ajoutée par le fait qu’on exploitera les fameux Custom Ressource Definition cité précédemment.
Pour la partie DMZ, c’est exactement la même chose. Seuls les template varient légèrement, mais leur contenu diffère très peu du LAN.
Le fichier de config traefik-config-dmz.yaml.j2:
image:
name: traefik
tag: "{{ var_version_traefik }}"
pullPolicy: IfNotPresent
deployment:
enabled: true
kind: DaemonSet
labels:
network: dmz
podLabels:
network: dmz
providers:
kubernetesIngress:
labelSelector: network=dmz
kubernetesCRD:
enabled: true
allowCrossNamespace: false
allowExternalNameServices: false
allowEmptyServices: false
namespaces:
- {{ var_namespace_traefik_prd_dmz }}
serviceAccount:
name: "{{ var_traefik_dmz_service_account }}"
logs:
level: ERROR
hostNetwork: true
ports:
web:
port: 80
ports.web.redirectTo.port: websecure
websecure:
port: 443
securityContext:
capabilities:
drop: [ALL]
add: [NET_BIND_SERVICE]
readOnlyRootFilesystem: true
runAsGroup: 0
runAsNonRoot: false
runAsUser: 0
updateStrategy:
rollingUpdate:
maxSurge: 0
maxUnavailable: 1
type: RollingUpdate
additionalArguments:
- "--providers.kubernetesingress.ingressclass=traefik-dmz"
- "--serversTransport.insecureSkipVerify=true"
Le fichier du compte de service svc-traefik-dmz.yaml.j2:
apiVersion: v1
kind: ServiceAccount
metadata:
name: "{{ var_traefik_dmz_service_account }}"
namespace: "{{ var_namespace_traefik_prd_dmz }}"
Le fichier pour le dashboard traefik-dmz-dashboard.yaml.j2:
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dmz-dashboard
namespace: "{{ var_namespace_traefik_prd_dmz }}"
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`{{ var_url_traefik_dmz }}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
services:
- name: api@internal
kind: TraefikService
middlewares:
- name: traefik-dashboard-dmz-auth # Referencing the BasicAuth middleware
namespace: {{ var_namespace_traefik_prd_dmz }}
tls:
secretName: sec-certif-traefik-k8s-dmz
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: traefik-dashboard-dmz-auth
namespace: {{ var_namespace_traefik_prd_dmz }}
spec:
basicAuth:
secret: sec-traefik-dashboard-dmz-password
La préparation des composants tiers permettant l’exposition des applications à l’extérieur du cluster est maintenant terminée. Il est possible que tout ne soit pas forcément clair à ce stade, mais d’autres informations et explications arriveront lors de la mise en œuvre.
Ce qu’il est important de retenir, c’est la logique globale avec le principe de loadbalancing à deux niveaux et l’usage de deux instances Traefik.
Chacune de ces instances est indépendante l’une de l’autre et ne voit pas ce que traite son homologue. Elles communiquent toutes les deux avec l’API K8S, mais via un compte dédié et n’ont pas le même niveau de visibilité sur le cluster.
Encore une fois, ces choix d’architecture ne sont pas des obligations à respecter. Vous êtes libre d’implémenter de nombreux schémas. C’est justement la force de l’écosystème Kubernetes. Sa modularité, même si elle peut paraitre complexe au début, permet d’envisager de nombreux scénarios et d’associer aux briques de base, de nombreux produits tiers ajoutant telle ou telle fonctionnalité.
Dans tous les cas, il est important que vous compreniez bien ce que vous faite et pourquoi vous la faite. À l’ère des IA, il devient de plus en plus facile de générer des configurations d’infrastructure K8S. Moi-même je m’en sers de plus en plus, mais attention a ce qui est proposé et à la manière dont vous exprimez vos besoins. Vous pourriez vous retrouver à mettre en production des logiques de flux et d’objets à risque sans même vous en rendre compte.
Enfin, au moment de l’écriture de cet article, l’API associée aux Ingress se fait concurrencer par l’API Gateway qui inclut de nouveaux objets. Kubernetes est toujours en pleine évolution et il possible que le l’API Gateway deviennent progressivement la nouvelle norme ou du moins devienne la solution pour traiter des cas de routage plus complexes et avoir une meilleure gestion du trafic réseau. Cela donnera peut-être lieu à un sujet dédié.
Pour poursuivre le cookbook c'est par ici.