Cilium ExternalIP et service DNS pour le réseau local dans un cluster Kube

Cilium ExternalIP et service DNS pour le réseau local dans un cluster Kube
Photo by Brittany Colette / Unsplash

Le DNS est un composant central dans un réseau, ou alors on aime bien les chiffres (je ne juge pas). Alors dans mon précédent billet je parlais de la migration vers le cloud native, un gros mot marketing pour dire tout mettre dans des conteneurs et kube, et globalement la migration du DNS c'est toujours un peu une étape bloquante. Cela marche ou rien ne marche.

Dans mes essais rapides de migration de mon vénérable bind9, qui marchait très bien vers coreDNS dans Kubernetes, j'avais tenté d'utiliser le service du cluster qui tourne dans le namespace kube-system. C'était un raccourci qui ne fait pas bon prendre car si tu te foires dans ta configuration c'est tout le cluster qui ne fonctionne plus correctement. Tu peux facilement rollback heureusement. Dans une volonté d'itérer en revenant sur une bonne pratique d'isolation des services, la mutualisation du DNS n'est pas vraiment pas recommendable, les effets de bords sont trop important. L'essai date un peu mais globalement, je reprenais la configuration de base et j'ajoutais la zone DNS de mon réseau local et ajoutais un service LoadBalancer pour avoir une IP sur le réseau local qui puisse être adressé par le port 53 :D Pour cela, j'ai mis en place l'IPAM de Cilium, avec le support des externalIPs et l'announce sur la couche L2 du réseau pour mettre au courant le réseau local qu'on a une nouvelle IP disponible à l'adresse MAC d'un des nodes élus par Cilium pour host l'IP.

Donc, j'ai laissé de côté le DNS le temps de finir de migrer le reste de mes applis/bdd etc, ainsi que tout mettre as-code. Une fois les bases posées, il ne restait plus qu'à dupliquer le POC avec les configmap contenant le Corefile et le fichier de zone repris de ma configuration bind9, le service avec une externalIP fixe ainsi qu'une clusterIP fixe et on avait un service DNS qui tient la route.

Une autre erreur fût de ne pas mettre d'IP interne fixe. On n'a pas envie de cela, au même titre que pour le service DNS du cluster ou tout infra réseau en fait. Il faut pouvoir adresser le service avec une IP fixe, on pourrait se dire que vu qu'on en a besoin pour le réseau en dehors de Kube, il n'est pas nécessaire d'avoir une IP interne fixe mais pas en utilisant la feature L2Announce de Cilium, ou autre. La particularité ici étant que l'IP utilise la même adresse MAC qu'un des nœuds du cluster. On se retrouve avec plusieurs IPs pour 1 adresse MAC. A ce moment-là, le nœud qui héberge l'IP du service n'arrive pas à requêter le DNS. En effet, on voit la requête partir vers le service mais la réponse ne revient jamais et tombe en i/o timeout. D'un point de vue L2 du réseau le client est le même que le serveur mais pas en L3. Visiblement Cilium n'arrive pas à s'en sortir avec ce cas de figure.

La solution dans cas de figure est donc d'utiliser une IP interne, clusterIP, fixe qui sera l'IP du serveur DNS des nodes qui eux peuvent communiquer naturellement sur les 2 réseaux de base. Et ensuite, pour éviter que les pods ne requêtent le DNS depuis l'IP externe, reconfigurer le coredns interne pour forward d'abord sur l'IP interne du DNS avant de forward sur /etc/resolv.conf. Le reste du réseau local utilisant l'IP externe.

apiVersion: v1
kind: Service
metadata:
  labels:
    announced: "true"
  name: coredns-lb
  namespace: coredns
spec:
  clusterIP: 10.96.0.53
  clusterIPs:
  - 10.96.0.53
  externalIPs:
  - 192.168.1.53
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: dnsudp
    port: 53
    protocol: UDP
    targetPort: 53
  - name: dnstcp
    port: 53
    protocol: TCP
    targetPort: 53
  - name: dns-over-tls
    port: 853
    protocol: TCP
    targetPort: 853
  - name: dns-over-https
    port: 443
    protocol: TCP
    targetPort: 443
  selector:
    k8s-app: coredns-claneys
  type: ClusterIP

coredns service manifest

Et la conf du kube-dns du cluster avec les arguments de forward modifiés:

.:53 {
    errors
    health {
        lameduck 5s
    }
    ready
    log . {
        class error
    }
    prometheus :9153

    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
    }

    forward . 10.96.0.53 /etc/resolv.conf
    cache 30
    loop
    reload
    loadbalance
}

Corefile kube-system