Acheminer le trafic Kubernetes avec Ingress

KubernetesBeginner
Pratiquer maintenant

Introduction

Les Services fournissent des points d’accès stables aux applications au sein d’un cluster. Ingress ajoute des règles de routage HTTP devant ces Services, ce qui permet à plusieurs applications de partager un même point d’entrée selon le nom d’hôte ou le chemin de l’URL.

Vous allez examiner le contrôleur ingress-nginx déjà préparé, déployer deux backends, ajouter un routage par hôte et par chemin, puis suivre une requête à travers Ingress, le Service et le Pod.

Gardez à l’esprit le parcours de la requête pendant tout le laboratoire : client → point d’entrée ingress-nginx → règle Ingress → Service → Pod prêt. Lorsqu’une requête échoue, il est beaucoup plus simple de vérifier ces maillons dans cet ordre que de considérer Ingress comme une boîte noire unique.

Examiner le contrôleur Ingress

Dans cette étape, examinez le contrôleur déjà fourni par l’environnement CKA au lieu d’en installer une seconde instance.

Un objet Ingress contient une configuration, et non un processus proxy. Il n’a aucun effet si aucun contrôleur compatible ne le surveille. Commencez par vérifier que les deux éléments d’infrastructure existent : une IngressClass nommée nginx et un déploiement ingress-nginx disponible.

cd /home/labex/project/ingress-routing
kubectl get ingressclasses
kubectl get deployments,pods,services -n ingress-nginx
kubectl wait --for=condition=Available deployment/ingress-nginx-controller -n ingress-nginx --timeout=60s

Une ressource Ingress décrit l’intention de routage. Le contrôleur ingress-nginx surveille les ressources dont le champ ingressClassName vaut nginx, puis configure le proxy réel.

Le Service du contrôleur expose le proxy via un NodePort dans ce cluster local. Vous découvrirez ce port plus tard au lieu de le coder en dur.

L’environnement préparé indique une classe nginx, un contrôleur disponible et un Service de type NodePort :

NAME    CONTROLLER
nginx   k8s.io/ingress-nginx

deployment.apps/ingress-nginx-controller   1/1   ...
service/ingress-nginx-controller           NodePort   ...   80:.../TCP,443:.../TCP

Les deux Pods d’admission Completed que vous pourrez également voir sont des Jobs d’installation déjà terminés ; ils ne correspondent pas à des réplicas du contrôleur en échec.

Déployer deux backends de Service

Dans cette étape, créez deux workloads web à réplica unique ainsi que les Services ClusterIP correspondants à partir d’un seul fichier contenant plusieurs documents.

Ces backends utilisent des concepts présentés dans Kubernetes pour débutants. L’objectif est donc de comprendre leur relation de routage plutôt que la syntaxe d’un Deployment. Le fichier contient cinq documents YAML séparés par --- : un namespace, puis un Deployment et un Service pour chaque application. Comparez le Service.spec.selector de chaque Service avec le label du Pod correspondant ; ils doivent être identiques avant qu’Ingress puisse atteindre quoi que ce soit.

cd /home/labex/project/ingress-routing
cat <<'EOF' > backends.yaml
apiVersion: v1
kind: Namespace
metadata: {name: practice-ingress}
---
apiVersion: apps/v1
kind: Deployment
metadata: {name: storefront, namespace: practice-ingress}
spec:
  replicas: 1
  selector: {matchLabels: {app: storefront}}
  template:
    metadata: {labels: {app: storefront}}
    spec:
      containers: [{name: web, image: nginx:1.27-alpine, imagePullPolicy: IfNotPresent, ports: [{name: http, containerPort: 80}]}]
---
apiVersion: v1
kind: Service
metadata: {name: storefront, namespace: practice-ingress}
spec: {selector: {app: storefront}, ports: [{name: http, port: 80, targetPort: http}]}
---
apiVersion: apps/v1
kind: Deployment
metadata: {name: reports, namespace: practice-ingress}
spec:
  replicas: 1
  selector: {matchLabels: {app: reports}}
  template:
    metadata: {labels: {app: reports}}
    spec:
      containers: [{name: web, image: httpd:2.4-alpine, imagePullPolicy: IfNotPresent, ports: [{name: http, containerPort: 80}]}]
---
apiVersion: v1
kind: Service
metadata: {name: reports, namespace: practice-ingress}
spec: {selector: {app: reports}, ports: [{name: http, port: 80, targetPort: http}]}
EOF

Appliquez les cinq documents ensemble, puis attendez que les deux Deployments soient prêts. Le fait d’attendre séparément permet d’identifier clairement le backend en échec si une image ou un sélecteur est incorrect :

kubectl apply -f backends.yaml
kubectl rollout status deployment/storefront -n practice-ingress --timeout=60s
kubectl rollout status deployment/reports -n practice-ingress --timeout=60s

Ingress ne route que vers des Services ; chaque backend doit donc déjà disposer de points de terminaison prêts.

Vérifiez explicitement ce prérequis avant de créer les règles de routage :

kubectl get services,endpointslices -n practice-ingress

Chaque Service doit avoir un EndpointSlice correspondant avec une adresse prête.

service/reports      ClusterIP   ...   80/TCP
service/storefront   ClusterIP   ...   80/TCP

endpointslice.../reports-...      IPv4   80   10.244.104...
endpointslice.../storefront-...   IPv4   80   10.244.104...

Les suffixes générés et les adresses varient, mais chaque nom de Service doit correspondre à un EndpointSlice non vide. Ingress ne peut pas réparer un Service sans backend ; cette vérification sert volontairement à valider d’abord la couche inférieure.

Ajouter un routage basé sur l’hôte

Dans cette étape, acheminez store.practice.test vers le Service storefront.

Une règle Ingress prend trois décisions de routage : host, path et le port du Service backend. ingressClassName: nginx sélectionne le contrôleur. L’annotation de réécriture dépend du contrôleur ; elle modifie le chemin de la requête envoyée au backend en /, chemin auquel les deux serveurs de démonstration peuvent répondre.

cd /home/labex/project/ingress-routing
cat <<'EOF' > ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: practice-routing
  namespace: practice-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: store.practice.test
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: storefront
                port: {name: http}
EOF

Appliquez la règle, puis utilisez describe pour lire l’interprétation du contrôleur, notamment le point de terminaison backend résolu :

kubectl apply -f ingress.yaml
kubectl describe ingress practice-routing -n practice-ingress

pathType: Prefix correspond à / ainsi qu’à ses sous-chemins. L’annotation de réécriture envoie la requête sélectionnée vers / sur le backend, où le serveur web de démonstration possède une page. L’hôte est une clé de routage HTTP ; il n’est pas nécessaire de disposer d’un DNS public pour ce test local.

describe doit résoudre la règle jusqu’à l’adresse d’un Pod :

Rules:
  Host                 Path  Backends
  store.practice.test
                       /   storefront:http (10.244.104...:80)

Une valeur Address globale vide immédiatement après la création n’indique pas forcément un échec dans cette configuration locale. Le backend storefront:http résolu et l’adresse de son Pod constituent les éléments de preuve importants.

Ajouter le routage par chemin et tester les requêtes

Dans cette étape, ajoutez le routage /reports, puis testez les deux règles via le point d’entrée du nœud.

Le chemin du correctif JSON se termine par /-. Pour un tableau, - signifie qu’un nouvel élément doit être ajouté plutôt que de remplacer la route / existante. Le nouveau backend pointe vers le Service reports en utilisant son port nommé http.

Exécutez ce correctif d’ajout une seule fois. Contrairement à kubectl apply, l’ajout à /- n’est pas idempotent : si vous le répétez, un autre élément /reports identique sera ajouté au lieu que l’élément précédent soit reconnu.

Les deux affectations suivantes découvrent le point de terminaison au lieu de coder son adresse en dur. minikube ip -p labex-v135 renvoie l’adresse IP du nœud pour le profil Minikube nommé, et la substitution de commande $(...) stocke la sortie de chaque commande dans une variable shell. La requête JSONPath sélectionne le port du Service nommé http et en extrait le NodePort.

kubectl patch ingress practice-routing -n practice-ingress --type='json' -p='[{"op":"add","path":"/spec/rules/0/http/paths/-","value":{"path":"/reports","pathType":"Prefix","backend":{"service":{"name":"reports","port":{"name":"http"}}}}}]'
NODE_IP=$(minikube ip -p labex-v135)
HTTP_NODE_PORT=$(kubectl get service ingress-nginx-controller -n ingress-nginx -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}')
echo "Ingress endpoint: ${NODE_IP}:${HTTP_NODE_PORT}"

Ces deux variables évitent d’intégrer dans les instructions des adresses propres à l’environnement. Envoyez maintenant les requêtes avec l’en-tête d’hôte requis par la règle. Pour chaque commande curl, -s masque l’indicateur de progression, --retry 5 retente les échecs temporaires, --retry-connrefused retente également une connexion initialement refusée et --retry-delay 2 attend deux secondes entre les tentatives. -H fournit l’en-tête HTTP Host, tandis que le tube transmet la réponse à grep afin de n’afficher que le texte permettant d’identifier la page.

curl -s --retry 5 --retry-connrefused --retry-delay 2 -H 'Host: store.practice.test' "http://${NODE_IP}:${HTTP_NODE_PORT}/" | grep 'Welcome to nginx'
curl -s --retry 5 --retry-connrefused --retry-delay 2 -H 'Host: store.practice.test' "http://${NODE_IP}:${HTTP_NODE_PORT}/reports" | grep 'It works'

Les deux réponses prouvent qu’un même point d’entrée achemine les requêtes vers des Services différents.

La première réponse provient de NGINX et la seconde d’Apache httpd. La différence entre les textes des pages constitue une preuve intentionnelle que la règle de chemin a sélectionné un autre backend, et pas simplement que le proxy a renvoyé le code HTTP 200.

Les lignes correspondantes attendues sont :

<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
<title>It works! Apache httpd</title>
<p>It works!</p>

Ce résultat explique également pourquoi l’en-tête Host personnalisé est important : les deux requêtes atteignent la même adresse IP de nœud et le même NodePort ; ce sont l’hôte et le chemin qui sélectionnent la règle et le backend.

Résumé

Vous avez réutilisé le contrôleur ingress-nginx préparé, relié les règles Ingress à des Services prêts et testé le routage basé sur l’hôte et le chemin via un seul point d’entrée.