Comment fournir un accès externe à plusieurs services Kubernetes dans mon cluster Amazon EKS ?

Lecture de 11 minute(s)
0

Je veux fournir un accès externe à plusieurs services Kubernetes dans mon cluster Amazon Elastic Kubernetes Service (Amazon EKS).

Brève description

Utilisez le contrôleur d'Ingress NGINX ou AWS Load Balancer Controller pour Kubernetes afin de fournir un accès externe à plusieurs services Kubernetes dans votre cluster Amazon EKS. Le contrôleur d'Ingress NGINX est géré principalement par NGINX. En cas de problèmes liés au contrôleur d'Ingress NGINX, veuillez consulter la liste des problèmes sur le site web de GitHub. AWS Load Balancer Controller est géré par Amazon Web Services (AWS). En cas de problèmes liés à AWS Load Balancer Controller, veuillez consulter la liste des problèmes sur le site web de GitHub.

Important : le contrôleur d'Ingress et IngressClass (du site de Kubernetes) sont différents de l'Ingress (du site web de Kubernetes). L'Ingress est une ressource Kubernetes qui expose les routes HTTP et HTTPS de l'extérieur du cluster à des services au sein du cluster. Le contrôleur d'Ingress est généralement responsable de l'exécution de l'Ingress avec un équilibreur de charge. Vous ne pouvez pas utiliser d'Ingress sans contrôleur d'Ingress. L'IngressClass permet d'identifier le contrôleur d'Ingress à utiliser pour répondre à la demande d'objet Ingress.

Condition préalable : installez AWS Load Balancer Controller. Il est recommandé d'utiliser AWS Load Balancer Controller pour créer et gérer un Network Load Balancer pour les objets de service de type LoadBalancer dans Amazon EKS.

Solution

La solution suivante utilise le contrôleur d'Ingress kubernetes/ingress-nginx de la section Kubernetes du site web de GitHub. nginxinc/kubernetes-ingress de la section NGINX du site web de GitHub constitue l'autre contrôleur d'Ingress disponible pour un usage public.

Déploiement du contrôleur d'Ingress NGINX pour Kubernetes

Vous pouvez déployer le contrôleur d'Ingress NGINX pour Kubernetes par le biais du protocole TCP (Transmission Control Protocol) ou TLS (Transport Layer Security).

Remarque : la solution suivante est testée sur Amazon EKS version 1.22, le contrôleur d'Ingress NGINX version 1.3.0 et AWS Load Balancer Controller version 2.4.3.

(Option 1) Contrôleur d'Ingress NGINX avec TCP sur Network Load Balancer

1.    Récupérez le fichier YAML pour déployer les objets Kubernetes suivants : namespace, serviceaccounts, configmap, clusterroles, clusterrolebindings, roles, rolebindings, services, deployments, ingressclasses et validatingwebhookconfigurations.

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/deploy.yaml

2.    Modifiez le fichier. Ensuite, dans la section de l'objet de service ingress-nginx-controller, remplacez l'ensemble des annotations service.beta.kubernetes.io par ce qui suit :

service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

3.    Appliquez le manifeste :

kubectl apply -f deploy.yaml

Exemple de sortie :

namespace/ingress-nginx created 
serviceaccount/ingress-nginx created 
configmap/ingress-nginx-controller created 
clusterrole.rbac.authorization.k8s.io/ingress-nginx created 
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created 
role.rbac.authorization.k8s.io/ingress-nginx created 
rolebinding.rbac.authorization.k8s.io/ingress-nginx created 
service/ingress-nginx-controller-admission created 
service/ingress-nginx-controller created 
deployment.apps/ingress-nginx-controller created 
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created 
serviceaccount/ingress-nginx-admission created 
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created 
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created

(Option 2) Terminaison TLS de contrôleur d'Ingress NGINX sur Network Load Balancer

Par défaut, la solution précédente établit la terminaison du protocole TLS au niveau du contrôleur d'Ingress NGINX. Vous pouvez également configurer le service Ingress NGINX afin qu'il établisse la terminaison du protocole TLS au niveau du Network Load Balancer.

1.    Téléchargez le modèle deploy.yaml :

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/aws/nlb-with-tls-termination/deploy.yaml

2.    Modifiez le fichier. Ensuite, dans la section de l'objet de service ingress-nginx-controller, remplacez l'ensemble des annotations service.beta.kubernetes.io par ce qui suit :

service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-2:XXXXXXXX:certificate/XXXXXX-XXXXXXX-XXXXXXX-XXXXXXXX
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

Remarque : assurez-vous d'inclure votre ARN pour service.beta.kubernetes.io/aws-load-balancer-ssl-cert.

3.    Modifiez le fichier, puis l'adresse CIDR Amazon Virtual Private Cloud (Amazon VPC) pour le cluster Kubernetes :

proxy-real-ip-cidr: XXX.XXX.XXX/XX

4.    Appliquez le manifeste :

kubectl apply -f deploy.yaml

Remarque : le manifeste précédent utilise ExternalTrafficPolicy en local afin de préserver l'adresse IP (client) source. L'utilisation de cette configuration avec un nom DHCP personnalisé dans l'Amazon VPC cause un problème. Pour éviter que ce problème ne se produise, appliquez le correctif suivant au kube-proxy :

kubectl edit daemonset kube-proxy -n kube-system

5.    Modifiez le manifeste pour inclure l'extrait suivant :

spec:
  template:
    spec:
      containers:
        - name: kube-proxy
          command:
            - kube-proxy
            - --hostname-override=$(NODE_NAME)
            - --v=2
            - --config=/var/lib/kube-proxy-config/config
           env:
            - name: NODE_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: spec.nodeName

Vérification des ressources déployées

AWS Load Balancer Controller

Commande :

kubectl get all -n kube-system --selector app.kubernetes.io/instance=aws-load-balancer-controller

Exemple de sortie :

NAME                                                READY   STATUS    RESTARTS   AGE   IP               NODE                                           NOMINATED NODE   READINESS GATES
pod/aws-load-balancer-controller-85cd8965dc-ctkjt   1/1     Running   0          48m   192.168.37.36    ip-192-168-59-225.us-east-2.compute.internal   none             none 
pod/aws-load-balancer-controller-85cd8965dc-wpwx9   1/1     Running   0          48m   192.168.53.110   ip-192-168-59-225.us-east-2.compute.internal   none>         none 
NAME                                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR 
service/aws-load-balancer-webhook-service   ClusterIP   10.100.154.44   none          443/TCP   19h   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller 
NAME                                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS                   IMAGES                                                                                    SELECTOR 
deployment.apps/aws-load-balancer-controller   2/2     2            2           19h   aws-load-balancer-controller 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.0   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller 
NAME                                                      DESIRED   CURRENT   READY   AGE   CONTAINERS                     IMAGES                                                                                    SELECTOR 
replicaset.apps/aws-load-balancer-controller-85cd8965dc   2         2         2       19h   aws-load-balancer-controller   602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.0   app.kubernetes.io/instance=aws-load-balancer-controller,app.kubernetes.io/name=aws-load-balancer-controller,pod-template-hash=85cd8965dc

Contrôleur d'Ingress NGINX

Commande :

kubectl get all -n ingress-nginx --selector app.kubernetes.io/instance=ingress-nginx

Exemple de sortie :

NAME                                           READY  STATUS   RESTARTS  AGE   IP               NODE                                           NOMINATED NODE  READINESS GATES
pod/ingress-nginx-controller-54d8b558d4-k4pdf  1/1    Running  0         56m   192.168.46.241   ip-192-168-59-225.us-east-2.compute.internal   none            none
NAME                                        TYPE           CLUSTER-IP      EXTERNAL-IP                                                                     PORT(S)                      AGE   SELECTOR
service/ingress-nginx-controller            LoadBalancer   10.100.99.129   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80:32578/TCP,443:30724/TCP   15h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
service/ingress-nginx-controller-admission  ClusterIP      10.100.190.61   none                                                                            443/TCP                      15h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
NAME                                       READY   UP-TO-DATE   AVAILABLE    AGE   CONTAINERS   IMAGES                                                                                                               SELECTOR
deployment.apps/ingress-nginx-controller   1/1     1            1            15h   controller   k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
NAME                                                  DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES                                                                                                               SELECTOR
replicaset.apps/ingress-nginx-controller-54d8b558d4   1         1         1       15h   controller   k8s.gcr.io/ingress-nginx/controller:v1.1.1@sha256:0bc88eb15f9e7f84e8e56c14fa5735aaa488b840983f87bd79b1054190e660de   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx,pod-template-hash=54d8b558d4
NAME                                       COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES                                                                                                                         SELECTOR
job.batch/ingress-nginx-admission-create   1/1           2s         15h   create       k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660   controller-uid=242bdf56-de16-471d-a691-1ca1dbc10a41
job.batch/ingress-nginx-admission-patch    1/1           2s         15h   patch        k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660   controller-uid=a9e710d2-5001-4d40-a435-ddc8993bfe42

IngressClass

Commande :

kubectl get ingressclass

Exemple de sortie :

NAME    CONTROLLER             PARAMETERS                             AGE 
alb     ingress.k8s.aws/alb    IngressClassParams.elbv2.k8s.aws/alb   19h 
nginx   k8s.io/ingress-nginx   none                                   15h

Test de la configuration du déploiement

Remarque : l'étape suivante consiste à exécuter deux microservices. Les microservices sont exposés en interne avec Kubernetes comme type par défaut.

1.    Configurez vos déploiements ou microservices. Par exemple, hostname-app et apache-app.

Exemple d'un fichier hostname-app-svc.yaml pour hostname-app :

apiVersion: apps/v1 
kind: Deployment 
metadata:
  name: hostname-app
  namespace: default 
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hostname-app
  template:
    metadata:
      labels:
        app: hostname-app
    spec:
      containers:
      - name: hostname-app
        image: k8s.gcr.io/serve_hostname:1.1 

--- 
apiVersion: v1 
kind: Service 
metadata:
  name: hostname-svc
  namespace: default 
spec:
  ports:
  - port: 80
    targetPort: 9376
    protocol: TCP
  selector:
    app: hostname-app

Exemple d'un fichier apache-app-svc.yaml pour apache-app :

apiVersion: apps/v1 
kind: Deployment 
metadata:
  name: apache-app
  namespace: default 
spec:
  replicas: 2
  selector:
    matchLabels:
      app: apache-app
  template:
    metadata:
      labels:
        app: apache-app
    spec:
      containers:
      - name: apache-app
        image: httpd:latest
        ports:
        - containerPort: 80 

--- 
apiVersion: v1 
kind: Service 
metadata:
  name: apache-svc
  namespace: default
  labels: 
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  selector:
    app: apache-app

2.    Appliquez vos configurations.

hostname-app :

kubectl apply -f hostname-app-svc.yaml

apache-app :

kubectl apply -f apache-app-svc.yaml

3.    Vérifiez que les ressources sont créées.

Déploiements

Commande :

kubectl get deployment hostname-app apache-app -n default

Exemple de sortie :

NAME           READY   UP-TO-DATE   AVAILABLE   AGE 
hostname-app   2/2     2            2           29m
apache-app     2/2     2            2           29m

Services

Commande :

kubectl get svc apache-svc hostname-svc -n default

Exemple de sortie :

NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE 
apache-svc     ClusterIP   10.100.73.51    none          80/TCP    29m 
hostname-svc   ClusterIP   10.100.100.44   none          80/TCP    29m

Test du contrôleur d'Ingress NGINX

1.    Accédez à l'URL DNS de l'équilibreur de charge que vous avez récupéré à partir de la ligne de commande :

curl -I ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com

Exemple de sortie :

HTTP/1.1 404 Not Found 
Date: Thu, 03 Mar 2022 14:03:11 GMT 
Content-Type: text/html 
Content-Length: 146 
Connection: keep-alive

Remarque : le serveur par défaut renvoie une erreur 404 Not Found pour l'ensemble des demandes de domaine qui ne disposent pas de règles d'Ingress définies. D'après les règles définies, le contrôleur d'Ingress ne détourne pas le trafic vers le service backend spécifié, sauf si la demande correspond à la configuration. Étant donné que le champ hôte est configuré pour l'objet d'Ingress, vous devez fournir l'en-tête Host (Hôte) de la demande avec le même nom d'hôte. Dans un environnement de test, indiquez l'en-tête Host (Hôte) à l'aide d'un paramètre de ligne de commande d'action Curl (curl flag). Dans un environnement de production, mappez le nom DNS de l'équilibreur de charge sur le nom d'hôte d'un fournisseur DNS, tel qu'Amazon Route 53.

2.    Implémentez l'Ingress afin qu'il interagisse avec vos services à l'aide de l'équilibreur de charge unique fourni par le contrôleur d'Ingress NGINX.

Exemple micro-ingress.yaml :

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: micro-ingress
  namespace: default
  annotations: 
    kubernetes.io/ingress.class: nginx 
spec:
  rules:
    - host: hostname.mydomain.com
      http:
        paths:
        - backend:
            service:
              name: hostname-svc
              port:
                number: 80
          path: /
          pathType: Prefix
  - host: apache.mydomain.com
    http:
      paths:
      - backend:
          service:
            name: apache-svc
            port:
              number: 80
        path: /
        pathType: Prefix

Remarque : pour plus d'informations, veuillez consulter la section Hébergement virtuel basé sur le nom sur le site web de Kubernetes.

3.    Vérifiez que la ressource est créée.

Ingress

Commande :

kubectl get ingress -n default

Exemple de sortie :

NAME           CLASS   HOSTS                                       ADDRESS                                                                         PORTS   AGE 
micro-ingress  none    hostname.mydomain.com,apache.mydomain.com   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80      29m

4.    Ajoutez l'en-tête Host (Hôte) à la demande.

Premier domaine configuré :

curl -i -H "Host: hostname.mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/

Exemple de sortie :

HTTP/1.1 200 OK Date: Sat, 26 Mar 2022 18:50:38 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 29 Connection: keep-alive

Deuxième domaine configuré :

curl -i -H "Host: apache.mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/

Exemple de sortie :

HTTP/1.1 200 OK 
Date: Sat, 26 Mar 2022 18:51:00 GMT 
Content-Type: text/html 
Content-Length: 45 
Connection: keep-alive 
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT 
ETag: "2d-432a5e4a73a80" 
Accept-Ranges: bytes

Après avoir ajouté l'en-tête Host (Hôte), le contrôleur d'Ingress redirige le trafic vers le service backend configuré car il correspond à la configuration définie dans le contrôleur d'Ingress.

Si vous voulez conserver le même nom de domaine mais détourner le trafic en fonction du chemin d'accès, vous devez ajouter un routage basé sur le chemin avec l'Ingress.

Par exemple :

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: path-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: nginxd
    nginx.ingress.kubernetes.io/rewrite-target: / 
spec:
  rules:
  - host: mydomain.com
    http:
      paths:
      - backend:
          service:
            name: hostname-svc
            port:
              number: 80
        path: /hostname
        pathType: Prefix
  - host: mydomain.com
    http:
      paths:
      - backend:
          service:
            name: apache-svc
            port:
              number: 80
        path: /apache
        pathType: Prefix

Remarque : si les demandes affichent mydomain.com comme en-tête Host (Hôte), l'exemple précédent ne renvoie que la réponse 200. Les demandes sont accessibles via le chemin /hostname ou /apache. Pour toutes les autres demandes, des réponses 404 sont renvoyées.

5.    Vérifiez que le routage basé sur le chemin est ajouté :

Commande :

kubectl get ingress -n default

Sortie :

NAME            CLASS  HOSTS                                       ADDRESS                                                                         PORTS  AGE
micro-ingress   none   hostname.mydomain.com,apache.mydomain.com   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     164m
path-ingress    none   mydomain.com,mydomain.com                   ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     120m

Commande :

curl -i -H "Host: mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/hostname
  • ou -
curl -i -H "Host: mydomain.com" http://aaa71bxxxxx-11xxxxx10.us-east-2.elb.amazonaws.com/apache

Test de l'Ingress à l'aide d'AWS Load Balancer Controller

1.    Lancez l'Application Load Balancer en utilisant l'exemple de manifeste d'Ingress suivant :

apiVersion: networking.k8s.io/v1 
kind: Ingress 
metadata:
  name: micro-ingress-alb
  namespace: default
  annotations:
    kubernetes.io/ingress.class: alb 
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip 
spec:
  rules:
  - host: alb.hostname.mydomain.com
    http:
      paths:
      - backend:
          service:
            name: hostname-svc
            port:
              number: 80
        path: /
        pathType: Prefix
   - host: alb.apache.mydomain.com
     http:
       - backend:
            service:
              name: apache-svc
              port:
                number: 80
         path: /
         pathType: Prefix

2.    Vérifiez que l'Application Load Balancer est lancé.

Commande :

kubectl get ingress -n default

Sortie :

NAME               CLASS  HOSTS                                               ADDRESS                                                                         PORTS  AGE
micro-ingress      none   hostname.mydomain.com,apache.mydomain.com           ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     164m
micro-ingress-alb  none   alb.hostname.mydomain.com,alb.apache.mydomain.com   k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com          80     18m
path-ingress       none   mydomain.com,mydomain.com                           ad9bba7a8239a475297d24bd2f617782-a579e639079f8270.elb.us-east-2.amazonaws.com   80     120m

Demande basée sur le premier domaine configuré :

curl -i -H "Host: alb.hostname.mydomain.com" http://k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com

Exemple de sortie :

HTTP/1.1 200 OK Date: Sat, 26 Mar 2022 20:46:02 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 29 Connection: keep-alive

Demande basée sur le deuxième domaine configuré :

curl -i -H "Host: alb.apache.mydomain.com" http://k8s-default-microing-8a252bde81-1907206594.us-east-2.elb.amazonaws.com

Exemple de sortie :

HTTP/1.1 200 OK 
Date: Sat, 26 Mar 2022 20:46:14 GMT 
Content-Type: text/html Content-Length: 45 
Connection: keep-alive 
Server: Apache/2.4.53 (Unix) 
Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT 
ETag: "2d-432a5e4a73a80" 
Accept-Ranges: bytes

AWS OFFICIEL
AWS OFFICIELA mis à jour il y a 2 ans