Aller au contenu principal

Cours optionnel - Réseau Kubernetes avancé

Le réseau Pod-to-Pod et les CNI plugins

La base du réseau Kubernetes consiste dans les communication entre les pods car tout est pod dans un cluster (même les éléments réseau comme les ingress et souvent le kube-proxy)

Sous Linux les conteneurs (quelle que soit la runtime choisie, Docker, containerd etc) tirent partie d'une fonctionnalité du noyau appelée Network namespace c'est à dire des espaces réseau isolés du réseau principal du serveur grâce à une forme de virtualisation. On peut s'en rendre compte en créant soit même des interfaces vituelle dans un namespace (cf https://linuxhint.com/use-linux-network-namespace/).

Les pods sont composés de plusieurs conteneurs qui partagent le même namespace réseau. Au moment de la création d'un pod, le premier conteneur créé est appelé pause, il est vide mais sert de support à la création de l'interface réseau virtuelle pour le pod. Les conteneurs démarrés ensuite récupèrent cette interface commune. On peut constater la création de ce conteneur en utilisant la cli docker ou ctr.

Dans Kubernetes cette interface virtuelle de chaque pod est créée et routée automatiquement par le plugin CNI (Container Network Interface, une norme standard qui permet à toutes les runtime de conteneurs et tous les plugins d'être compatibles.).

Ce plugin doit être présent dans le cluster pour pouvoir automatiser la communication entre les pods. À l'installation (manuelle) du cluster on configure donc un CIDR pour les pods généralement un /16, et un plugin CNI.

Il existe de nombreux plugin CNI du plus simple au plus sophistiqué pour pouvoir répondre à des edge cases (notamment la communication interne/externe du cluster) des problématiques de performance, sécurité, observabilité. Voir plus loin.

On peut même implémenter un plugin simple en bash a des fins pédagogiques : https://www.altoros.com/blog/kubernetes-networking-writing-your-own-simple-cni-plug-in-with-bash/.

Une fois cette configuration mise en place les pods sont capables de communiquer avec tous les autres pods du cluster sans NAT (à leur niveau), c'est à dire sans modification de l'adresse IP au cours de la communication.

On donc peut tester la base du fonctionnement d'un plugin CNI installé en essayant de pinguer depuis un pod l'IP d'un autre pod sur un autre noeud.

https://projectcalico.docs.tigera.io/about/about-k8s-networking

Communication inter-services avec le kube-proxy

Une fois que l'on a mis en place un moyen de communication inter-pod la communication est-ouest de notre cluster n'est pas encore opérationnelle. En effet Kubernetes étant un environnement dynamique avec des pods créés et détruit automatiquement par des Deployment ou autre controller, gérer les IP des pods manuellement est en réalité impraticable. Pour cela nous avons besoin de la gestion automatique d'une ip virtuelle associée fournissant le loadbalancing proposé par les resources de type Service.

Cette gestion d'IP virtuelle est réalisée traditionnellement par le composant Kubernetes appelé kube-proxy. Le kube-proxy est généralement installé dans le cluster en temps que pod privilégié sur chaque noeud (mais peut également être un service systemd) et manipule iptable. On peut s'en rendre compte par exemple avec la commande sudo iptables-save | grep KUBE | grep "kubernetes-dashboard" # ou autre nom de service.

Ainsi, kube-proxy créé dynamiquement des règles iptable qui indiquent que tout paquet venant du CIDR des pods et à destination de l'IP virtuelle du service (en réalité l'IP de l'objet endpoint) doit être redirigé aléatoirement vers l'un des pods de backend d'un groupe désignés comme nous l'avons vu grace à un selecteur de labels.

kube-proxy peut également être configuré pour utiliser à la place de iptable la fonctionnalité d'IP virtuelle du noyau Linux appelé IPVS. Cela amène surtout de meilleures performances dans le cas d'un grand nombre de services (<500).

Enfin depuis quelques temps la gestion du traffic inter-node avec kube-proxy peut être remplacée par une implémentation eBPF dans le noyau linux par exemple grâce à Calico ou Cilium.

Video: Kubernetes Services networking

Découverte de service avec kube-DNS

Les services viennent avec un nom de domaine local au namespace et local grâce à au composant kube-dns. Ce composant peut depuis longtemps être remplacé par coreDNS plus performant et modulaire (recommandé).

On peut tester le bon fonctionnement du composant DNS avec nslookup depuis par exemple un pods du conteneur dnsutils.

Deux types de services moins connus :

  • service de type headless avec ClusterIP=None -> une requête vers le nom de domaine du service renvoie la liste des IP des pods backend. On peut ensuite implémenter soit même d'une manière ou d'une autre la connexion/loadbalancing vers ces backend.

  • service ExternalName: utilise CoreDNS pour mapper le nom de domaine du service à un enregistrement CNAME renvoyant vers un autre service par exemple à l'extérieur du Cluster. Aucun proxy d’aucune sorte n’est utilisé.

Fournir des services LoadBalancer on premise avec MetalLB

Dans un cluster managé provenant d'un fournisseur de cloud, la création d'un objet Service Lodbalancer entraine le provisionning d'une nouvelle machine de loadbalancing à l'extérieur du cluster avec une IPv4 publique grâce à l'offre d'IaaS du provideur (impliquant des frais supplémentaires).

Cette intégration n'existe pas par défaut dans les clusters de dev comme minikube ou les cluster on premise (le service restera pending et fonctionnera comme un NodePort). Le projet MetalLB cherche à y remédier en vous permettant d'installer un loadbalancer directement dans votre cluster en utilisant une connexion IP classique ou BGP pour la haute disponibilité.

Le mesh networking et les service meshes

Un service mesh est un type d'outil réseau pour connecter un ensemble de pods, généralement les parties d'une application microservices de façon encore plus intégrée que ne le permet Kubernetes.

En effet opérer une application composée de nombreux services fortement couplés discutant sur le réseau implique des besoins particuliers en terme de routage des requêtes, sécurité et monitoring qui nécessite l'installation d'outils fortement dynamique autour des nos conteneurs.

Un exemple de service mesh est https://istio.io qui, en ajoutant dynamiquement un conteneur "sidecar" à chacun des pods à supervisés, ajoute à notre application microservice un ensemble de fonctionnalités d'intégration très puissant.

Un autre service mesh populaire et plus simple/léger qu'Istio, Linkerd : https://linkerd.io/

Les network policies : des firewalls dans le cluster

Voir cours sur la sécurité

Comparaison des plugins CNI

https://platform9.com/blog/the-ultimate-guide-to-using-calico-flannel-weave-and-cilium/

Flannel

Flannel est le plugin le plus ancien et simple pour kubernetes. Il implémente la communication Pod-to-Pod créant un réseau overlay par dessus un backend linux standard comme VXLAN. Il ne s'occupe pas de la communication inter-service.

Son principal avantage est d'être plus simple à implémenter et maintenir que Calico ou Cillium et plus compatible (pas besoin d'un noyau eBPF par exemple). Idéal pour les petits clusters peu critiques.

Il ne dispose pas d'implémentation des Network Policies à moins d'être complémenté par Calico (Cannal)

Calico

Calico développé par l'entreprise Tigera est le plugin CNI le plus populaire pour les clusters à grande échelle avec des configurations avancées et des performances exemplaires.

Il peut implémente la communication inter-Pod avec un réseau overlay ou en routant le traffic entre les noeuds à l'aide d'un routeur virtuel utilisant BGP (protocole inter-routeur structurant internet) : https://projectcalico.docs.tigera.io/networking/determine-best-networking

Calico est assez modulaire et très configurable. Il peut:

Calico est extrêment fin sur les network policies mais peut aussi gérer le traffic en dehors de kubernetes et notamment s'occuper de règles de firewall pour des VM. Toutes ces règles sont alors configurées par exemple avec des CRD kubernetes ou via la dashboard Tigera (offre Saas) : https://www.tigera.io/features/microsegmentation/

Calico dispose de plus de nombreuses offres managées de différents vendeurs. Il s'intègre en particulier avec l'offre de Tigera et stack complète d'observabilité et sécurité réseau. Cf cours sur la sécurité.

Cilium

Solution plus récente mais très en vogue, Cilium implémente depuis le départ un dataplane eBPF qui lui permet d'associer une configuration simple avec des fonctionnalités puissantes qui concurrencent Calico:

  • remplace kube-proxy avec sa communication inter-services eBPF ()
  • fournit une observabilité réseau puissante via une récolte de métrique et son dashboard Hubble (Open source ce qui est un avantage par rapport à Tigera)
  • fournit des Network Policies standard et avancées au niveau transport (OSI 3-4) et application (OSI 7) qui sont DNS-aware
  • fournit en option un chiffrement du traffic
  • Permet de créer facilement un multi-cluster

Comparaison Cilium et Calico

Cilium et Calico on a peu prêt le même périmetre de fonctionnalités puissantes et performances exemplaires mais :

  • Calico est un peu plus modulaire et peut s'installer de plusieurs façons... ce qui peut être un avantage mais peut aussi amener de la complexité.
  • Cilium est plus open source côté dashboard et intégration SIEM car non adossé à une offre SaaS
  • Calico est capable d'étendre sa gestion de sécurité réseau au delà du cluster à d'autres machines avec l'agent calico installé ce qui peut être très puissant.

Ressources sur le réseau