Étape 5 : déploiement des outils tiers

Introduction

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.

Principe d'exposition des applications

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.

  • Un premier niveau à l’extérieur du cluster. Portée par la solution HAproxy, cela va nous permettre d’avoir un point d’entrée pour l’accès à l’API ainsi que pour d’autres types de flux et de les rediriger vers les nœuds du cluster.
  • Un second niveau à l’intérieur du cluster. Porté par la solution Traefik, cela va nous permettre de rediriger les flux vers les bons services en interne du cluster qui eux-mêmes redirigeront vers les bon pods. On parlera d’Ingress Controller.

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.

Fonctionnement des flux

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.

Ingress Controller

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é.

06-configure-haproxy.yml

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.

07-configure-traefik.yml

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:

  • kubernetesIngress : c’est l’intégration standard d’un Ingress Contrôleur. De cette manière, il n’y a pas nécessité de modifier particulièrement son cluster. On définit un label (ici network=lan) et tout objet Ingress qui présentera ce label sera traité par Traefik.
  • kubernetesCRD : c’est l’intégration avancée. CRD signifies Custom Ressource Definition. Cela indique que Traefik va s’installer en ajoutant à l’API kubernetes des définitions de nouveaux objets qui lui sont propres. Cela va permettre d’aller plus loin dans les configurations possibles et de simplifier l’usage de Traefik. L’inconvénient de cette méthode est de rendre l’API Kubernetes « customisée ». Dans un environnement OnPrem, avec une installation Vanilla telle que décrite sur ce site ce n’est pas un problème. Mais dans un environnement cloud public par exemple, ou une offre « Kube As A Service » quelconque, il est très peu probable que vous puissiez étendre l’API Kubernetes. C’est pourquoi, même si les « Custom Ressource Definition” sont utilisés dans bien des cas (et pas que pour Traefik), il est conseillé d’en exploiter le moins possible. SI demain vous souhaitez basculer sur une architecture hybride, ou migrer vers une offre managée, il vous faudra rester au plus proche possible de l’API classique de K8S.

  • 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
      

    Conclusion

    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.

  • l’une représentée par la classe d’Ingress Controller traefik-lan. Elle sera déployée sur les control plane et chargée de traiter les ingress uniquement déclarés au sein du LAN, soit l’exposition des applications interne à une entreprise par exemple (intranet).
  • l’une représentée par la classe d’Ingress Controller traefik-dmz. Elle sera déployée sur les nodes en DMZ et chargée de traiter les ingress uniquement déclarés au sein de la DMZ, soit l’exposition des applications à l’extérieur d’une entreprise (site web).

  • 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.