Wie stelle ich externen Zugriff auf mehrere Kubernetes-Services in meinem Amazon EKS-Cluster bereit?

Lesedauer: 10 Minute
0

Ich möchte externen Zugriff auf mehrere Kubernetes-Services in meinem Amazon Elastic Kubernetes Service (Amazon EKS)-Cluster bereitstellen.

Kurzbeschreibung

Verwenden Sie den NGINX-Eingangscontroller oder den AWS Load Balancer-Controller für Kubernetes, um externen Zugriff auf mehrere Kubernetes-Services im Amazon EKS-Cluster bereitzustellen. Der NGINX-Eingangscontroller wird hauptsächlich von NGINX verwaltet. Um nach Problemen mit dem NGINX-Eingangscontroller zu suchen, sehen Sie sich die Liste der Probleme auf der GitHub-Website an. Der AWS Load Balancer-Controller wird von Amazon Web Services (AWS) verwaltet. Informationen zur Überprüfung auf Probleme mit dem AWS Load Balancer-Controller finden Sie in der Liste der Probleme auf der GitHub-Website.

Wichtig: Der Eingangscontroller und IngressClass (von der Kubernetes-Website) sind nicht identisch mit Ingress (von der Kubernetes-Website). Der Ingress ist eine Kubernetes-Ressource, die HTTP- und HTTPS-Routen von außerhalb des Clusters für die Services innerhalb des Clusters verfügbar macht. Der Eingangscontroller erfüllt den Ingress normalerweise mit einem Load Balancer. Sie können Ingress nicht ohne einen Eingangscontroller verwenden. Die IngressClass wird verwendet, um zu ermitteln, welcher Ingress-Controller für die Erfüllung der Ingress-Objektanforderung verwendet werden soll.

Voraussetzung: Installieren Sie den AWS Load Balancer-Controller. Es ist eine bewährte Methode, den AWS Load Balancer-Controller zu verwenden, um einen Network Load Balancer für Serviceobjekte vom Typ LoadBalancer in Amazon EKS zu erstellen und zu verwalten.

Lösung

Bei der folgenden Lösung wird der kubernetes/ingress-nginx-Eingangscontroller auf der Kubernetes-GitHub-Website verwendet. Der andere Eingangscontroller, der für die öffentliche Nutzung verfügbar ist, ist der nginxinc/kubernetes-ingress auf der NGINX-GitHub-Website.

NGINX-Eingangscontroller für Kubernetes bereitstellen

Sie können den NGINX-Eingangscontroller für Kubernetes entweder über das Transmission Control Protocol (TCP) oder Transport Layer Security (TLS) bereitstellen.

Hinweis: Die folgende Lösung wurde auf Amazon EKS Version 1.22, NGINX-Eingangscontroller Version 1.3.0 und AWS Load Balancer-Controller Version 2.4.3 getestet.

**(Option 1) NGINX-Eingangscontroller mit TCP auf Network Load Balancer **

1.    Rufen Sie die YAML-Datei ab, um die folgenden Kubernetes-Objekte bereitzustellen: namespace, serviceaccounts, configmap, clusterroles, clusterrolebindings, roles, rolebindings, services, deployments, ingressclasses und validatingwebhookconfigurations.

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

2.    Bearbeiten Sie die Datei. Ersetzen Sie dann im Abschnitt mit den Serviceobjekten ingress-nginx-controller alle service.beta.kubernetes.io-Anmerkungen durch die folgenden:

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.    Wenden Sie das Manifest an:

kubectl apply -f deploy.yaml

Beispiel für eine Ausgabe:

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) TLS-Terminierung des NGINX**-Eingangscontrollers auf dem Network Load Balancer**

Standardmäßig beendet die vorherige Lösung TLS im NGINX-Eingangscontroller. Sie können den NGINX Ingress-Dienst auch so konfigurieren, dass TLS am Network Load Balancer beendet wird.

1.    Laden Sie die deploy.yaml-Vorlage herunter:

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

2.    Bearbeiten Sie die Datei. Ersetzen Sie dann im Abschnitt mit den Serviceobjekten von ingress-nginx-controller alle service.beta.kubernetes.io-Anmerkungen durch die folgenden:

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"

Hinweis: Stellen Sie sicher, dass Sie Ihren ARN für service.beta.kubernetes.io/aws-load-balancer-ssl-cert angeben.

3.    Bearbeiten Sie die Datei und ändern Sie den CIDR von Amazon Virtual Private Cloud (Amazon VPC) für den Kubernetes-Cluster:

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

4.    Wenden Sie das Manifest an:

kubectl apply -f deploy.yaml

Hinweis: Das vorherige Manifest verwendet ExternalTrafficPolicy als lokal, um die Quell-IP-Adresse (Client) beizubehalten. Die Verwendung dieser Konfiguration mit einem benutzerdefinierten DHCP-Namen in der Amazon VPC verursacht ein Problem. Um das Auftreten des Problems zu verhindern, wenden Sie den folgenden Patch auf den Kube-Proxy an:

kubectl edit daemonset kube-proxy -n kube-system

5.    Bearbeiten Sie das Manifest so, dass es den folgenden Codeausschnitt enthält:

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

Überprüfen der bereitgestellten Ressourcen

AWS Load Balancer-Controller

Befehl:

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

Beispiel für eine Ausgabe:

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

NGINX-Eingangscontroller

Befehl:

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

Beispiel für eine Ausgabe:

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

Befehl:

kubectl get ingressclass

Beispiel für eine Ausgabe:

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

Testen des Setup der Bereitstellung

Hinweis: Im folgenden Schritt werden zwei Microservices ausgeführt. Die Microservices werden intern mit Kubernetes als Standardtyp bereitgestellt.

1.    Richten Sie Ihre Bereitstellungen oder Microservices ein. Zum Beispiel hostname-app und apache-app.

Beispiel einer hostname-app-svc.yaml-Datei für 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

Beispiel einer apache-app-svc.yaml-Datei für 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.    Wenden Sie Ihre Konfigurationen an.

hostname-app:

kubectl apply -f hostname-app-svc.yaml

apache-app:

kubectl apply -f apache-app-svc.yaml

3.    Stellen Sie sicher, dass die Ressourcen erstellt werden.

Bereitstellungen

Befehl:

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

Beispiel für eine Ausgabe:

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

Services

Befehl:

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

Beispiel für eine Ausgabe:

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

Testen des NGINX-Eingangscontrollers

1.    Greifen Sie über die Befehlszeile auf die DNS-URL des Load Balancers zu, den Sie abgerufen haben:

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

Beispiel für eine Ausgabe:

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

Hinweis: Der Standardserver gibt für alle Domainanfragen, für die keine definierten Eingangsregeln gelten, eine 404 Nicht gefunden-Seite zurück. Basierend auf den definierten Regeln leitet der Eingangscontroller keinen Datenverkehr an den angegebenen Backend-Dienst um, es sei denn, die Anfrage entspricht der Konfiguration. Da das Host-Feld für das Eingangsobjekt konfiguriert ist, müssen Sie den Host-Header der Anfrage mit demselben Hostnamen angeben. Verwenden Sie in einer Testumgebung eine Curl-Flag, um den Host-Header bereitzustellen. Ordnen Sie in einer Produktionsumgebung den DNS-Namen des Load Balancers dem Hostnamen eines beliebigen DNS-Anbieters zu, z. B. Amazon Route 53.

2.    Implementieren Sie den Eingang so, dass er mit Ihren Services verbunden ist, indem Sie einen einzigen Load Balancer verwenden, der vom NGINX-Eingangscontroller bereitgestellt wird.

Beispiel 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

Hinweis: Weitere Informationen finden Sie unter Namensbasiertes virtuelles Hosting (auf der Kubernetes-Website).

3.    Stellen Sie sicher, dass die Ressource erstellt wird.

Eingang

Befehl:

kubectl get ingress -n default

Beispiel für eine Ausgabe:

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.    Fügen Sie der Anfrage den Host-Header hinzu.

Erste konfigurierte Domain:

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

Beispiel für eine Ausgabe:

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

Zweite konfigurierte Domain:

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

Beispiel für eine Ausgabe:

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

Nach dem Hinzufügen des Host-Headers leitet der Eingangscontroller den Datenverkehr an den im Backend konfigurierten Dienst weiter, sofern er der Konfiguration entspricht, die im Eingang definiert ist.

Um den gleichen Domainnamen beizubehalten, den Datenverkehr jedoch auf der Grundlage des Pfads umzuleiten, auf den zugegriffen wird, müssen Sie dem Eingang pfadbasiertes Routing hinzufügen.

Zum Beispiel:

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

Hinweis: Wenn in Anfragen mydomain.com als Host-Header steht, gibt das vorherige Beispiel nur den Antwortcode 200 zurück. Auf die Anfragen wird entweder über die Pfade /hostname oder /apache zugegriffen. Für alle anderen Anfragen wird der Antwortcode 404 zurückgegeben.

5.    Stellen Sie sicher, dass das pfadbasierte Routing hinzugefügt wird:

Befehl:

kubectl get ingress -n default

Ausgabe:

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

Befehl:

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

– oder –

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

Eingang mit dem AWS Load Balancer-Controller testen

1.    Starten Sie den Application Load Balancer mithilfe des folgenden Beispiel-Ingress-Manifests:

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.    Stellen Sie sicher, dass der Application Load Balancer gestartet wird.

Befehl:

kubectl get ingress -n default

Ausgabe:

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

Anfrage basierend auf der ersten konfigurierten Domain:

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

Beispiel für eine Ausgabe:

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

Anfrage basierend auf der zweiten konfigurierten Domain:

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

Beispiel für eine Ausgabe:

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 OFFICIAL
AWS OFFICIALAktualisiert vor 2 Jahren