NGINX-Referenzimplementierung für Layer-7-Load-Balancing

Google Distributed Cloud (GDC) mit Air Gap bietet einen integrierten verwalteten Layer 4 (L4)-Load-Balancer. Viele Unternehmensanwendungen erfordern jedoch erweiterte Layer 7 (L7)-Funktionen wie hostbasiertes Routing, zentralisierte TLS-Verwaltung und komplexe Trafficaufteilung. Bisher wurde dies mit der Ingress API erreicht, die in der Kubernetes-Community jetzt als funktionsmäßig eingefroren gilt.

Diese Referenzarchitektur bietet eine selbstverwaltete Layer 7-Load-Balancing-Lösung. Durch die Bereitstellung des beliebten Open-Source-Controllers NGINX Gateway Fabric in einem GDC-Standardcluster können Kunden L7-Traffic nahtlos an Hybridumgebungen weiterleiten. Diese Architektur verwendet die TLS-Terminierung (HTTPRoute), um Traffic basierend auf der Server Name Indication (SNI) sowohl an integrierte containerisierte Pods als auch an Anwendungen weiterzuleiten, die auf externen virtuellen Maschinen gehostet werden.

Architektur

Architekturdiagramm für NGINX-Layer-7-Load-Balancing in GDC mit Air Gap

Zu den wichtigsten Komponenten der Lösung gehören:

  • Client:Eine Entität, die HTTPS-Anfragen initiiert, um mit den Anwendungen zu interagieren.
  • GDC-Standardcluster:GDC bietet eine integrierte Möglichkeit zum Erstellen von Kubernetes-Vanilla-Clustern. In dieser Lösung hostet der Cluster den L7-Load-Balancer und seine Controller sowie die Arbeitslasten und den monitorlosen Dienst für externe VMs.
  • GDC-L4-Load-Balancer:Der integrierte L4-Load-Balancer dient als Einstiegspunkt und verteilt TCP/443-Traffic direkt an die Kubernetes-Pods, auf denen die Gateway-Controller ausgeführt werden.
  • Gateway-Controller:NGINX-Operatoren, die im Standardcluster ausgeführt werden. Sie überwachen Gateway API-Ressourcen (z. B. Gateway und HTTPRoute) und aktualisieren die zugrunde liegenden Proxys dynamisch. Für die Lösung wird NGINX Gateway Fabric verwendet.
  • Gateway (mit HTTPRoute) : Standardisierte Kubernetes-Ressourcen, die den physischen Listening-Port (443) und die SNI-basierten Host-Routing-Regeln mit TLS-Terminierung definieren.
  • Containerisierte Arbeitslast (Pods) : Eine Standard-Kubernetes-Bereitstellung, die intern mit einem regulären Kubernetes-Service bereitgestellt wird.
  • VM-basierte Arbeitslast (extern) : Eine Arbeitslast, die auf einer externen VM im Projektnetzwerk gehostet wird und für den Proxy mit einem monitorlosen Kubernetes-Service und einem benutzerdefinierten Endpunkt mit der direkten IP-Adresse der VM bereitgestellt wird.
  • Harbor Registry:Eine private Container-Registry, die zum Speichern und Bereitstellen der Proxy- und Anwendungs-Images in der Umgebung mit Air Gap verwendet wird.

Im Standardcluster erstellen Sie vier Namespaces:

  • Der Namespace nginx-gateway, der die NGINX Gateway Fabric-Ressourcen hostet:

    Die Ressourcen des nginx-gateway-Namespace.

  • Der Namespace load-balancer, der die Gateway-Ressourcen hostet:

    Die Load-Balancer-Namespace-Ressourcen.

  • Der Namespace vm-app hostet die externe VM-IP-Adresse vm-app, einen monitorlosen Dienst, ein EndpointSlice, das auf die externe IP-Adresse verweist, und eine HTTPRoute für das Gateway:

    Die Ressourcen des vm-app-Namespace.

  • Der Namespace hello-app hostet die Deployment, einen Service, eine HTTPRoute und ein Gateway für die containerisierte Demo-Arbeitslast:

    Die Ressourcen des Namespace „hello-app“.

Hinweis

Bevor Sie diese Lösung bereitstellen, müssen die folgenden Voraussetzungen erfüllt sein:

  • Erforderliche Software:helm, docker, kubectl
  • CLI-Anmeldung und lokale Einrichtung:Laden Sie die gdcloud CLI aus der GDC-Konsole herunter und richten Sie Ihre Umgebung lokal ein.

    export USER_NAME="USER_NAME"
    export PROJECT_ID="PROJECT_ID"
    export ZONE="ZONE"
    export ORG_NAME="ORG_NAME"
    export GDCH_URL="GDC_URL"
    
    gdcloud components install gdcloud-k8s-auth-plugin
    
    gdcloud config set core/organization_console_url \
      https://console.$ORG_NAME.$ZONE.$GDC_URL
    gdcloud config set core/zone $ZONE
    gdcloud config set core/project ${PROJECT_ID}
    
    gdcloud auth login # use --login-config-cert option in case of TLS error
    
  • Projekteinrichtung: Erstellen Sie ein Projekt in Ihrer GDC-Umgebung mit Air Gap, um die Ressourcen zu hosten.

    gdcloud projects create $PROJECT_ID
    
  • IAM-Rollen:Gewähren Sie Ihrem Nutzer die Rollen Cluster Admin und Standard Cluster Admin , um Kubernetes-Ressourcen zu verwalten, und die Rolle Harbor Instance Admin , um Images zu übertragen.

    # Grant standard cluster and cluster admin roles
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=cluster-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=standard-cluster-admin
    
    # Grant Harbor instance admin role
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=harbor-instance-admin
    

Standardcluster erstellen

In diesem Abschnitt wird beschrieben, wie Sie einen Standard-Kubernetes-Cluster in Ihrer GDC-Umgebung mit Air Gap einrichten. Ein Standardcluster bietet eine flexible und robuste Grundlage für die Bereitstellung verschiedener Arbeitslasten, einschließlich des NGINX Gateway-Controllers und Ihrer benutzerdefinierten Anwendungen. Mit den folgenden Schritten wird sichergestellt, dass Ihr Cluster ordnungsgemäß konfiguriert und für nachfolgende Bereitstellungen zugänglich ist.

  1. Ermitteln Sie die verfügbaren VM-Image-Typen mit folgendem Befehl:

    gdcloud compute machine-types list
    
  2. Wählen Sie einen geeigneten Maschinentyp für Ihre Cluster-Worker-Knoten aus. Für diese Anleitung wird ein Maschinentyp mit mindestens 4 vCPUs empfohlen.

    export MACHINE_TYPE="MACHINE_TYPE"
    
  3. Rufen Sie die kubeconfig-Datei des Management API-Servers ab und legen Sie einen Alias fest:

    export CLUSTER_NAME="CLUSTER_NAME"
    
    KUBECONFIG=kubeconfig-admin.yaml gdcloud clusters \
      get-credentials ${ORG_NAME}-admin
    
    alias km="kubectl --kubeconfig kubeconfig-admin.yaml"
    
  4. Erstellen Sie einen Standardcluster mit zwei Worker-Knoten:

    km create -f - <<EOF
    apiVersion: cluster.gdc.goog/v1
    kind: Cluster
    metadata:
      name: ${CLUSTER_NAME}
      namespace: ${PROJECT_ID}
    spec:
      nodePools:
      - machineTypeName: ${MACHINE_TYPE}
        nodeCount: 2
        name: ${CLUSTER_NAME}-node-pool
    EOF
    

    Weitere Informationen zu den verfügbaren Optionen finden Sie in der Dokumentation.

    Die Erstellung eines Standardclusters kann bis zu 60 Minuten dauern. Verwenden Sie den folgenden Befehl, um den Status zu prüfen:

    km get clusters/${CLUSTER_NAME} \
      -n ${PROJECT_ID} \
      --watch
    

    Wenn der Cluster bereit ist, sollte die Ausgabe den Status „Running“ (Wird ausgeführt) anzeigen, wie hier:

    NAME         STATE     K8S VERSION
    my-cluster   Running   1.30.12-gke.300
    
  5. Rufen Sie die Anmeldedaten des Clusters ab, nachdem er bereit ist:

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml gdcloud clusters \
      get-credentials ${CLUSTER_NAME} \
      --standard \
      --project ${PROJECT_ID} \
      --zone ${ZONE}
    
  6. Erstellen Sie einen Alias, um kubectl-Befehle im Rest dieser Anleitung kürzer zu halten. Dieser Alias wird für die Interaktion mit dem Standardcluster verwendet:

    alias kk="kubectl --kubeconfig kubeconfig-${CLUSTER_NAME}.yaml"
    
  7. Erstellen Sie Namespaces für den Controller, die containerisierte Demoanwendung „hello-app“ und die VM-basierte Demoanwendung:

    kk create namespace load-balancer
    kk create namespace hello-app
    kk create namespace vm-app
    

Harbor Registry erstellen und einbinden

Harbor ist eine Container-Image-Registry mit integrierter Unterstützung in GDC mit Air Gap. In diesem Abschnitt werden die Schritte zum Einbinden einer Harbor Registry in Ihren Standardcluster beschrieben, einschließlich der Konfiguration von Anmeldedaten und Secrets, um das sichere Abrufen und Übertragen von Images zu ermöglichen.

  1. Erstellen Sie eine Harbor Instanz in Ihrem Projekt.
  2. Erstellen Sie ein Harbor Projekt in Ihrer Harbor-Instanz.
  3. Legen Sie Umgebungsvariablen fest:

    export HARBOR_INSTANCE_NAME="HARBOR_INSTANCE_NAME"
    export HARBOR_INSTANCE_URL="HARBOR_INSTANCE_URL"
    export HARBOR_PROJECT="HARBOR_INSTANCE_PROJECT"
    export IMAGE_PULL_SECRET_NAME="harbor-secret"
    
  4. Melden Sie sich mit einem Roboter Konto in der Harbor-Instanz an:

    docker --config=./docker login ${HARBOR_INSTANCE_URL}
    
  5. Erstellen Sie die Secrets im Standardcluster:

    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n load-balancer
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n hello-app
    

Containerisierte Demoanwendung bereitstellen

In diesem Abschnitt wird die Bereitstellung einer containerisierten Demoanwendung (hello-app) in Ihrem GDC-Kubernetes-Cluster mit Air Gap beschrieben. Sie erstellen die erforderlichen Kubernetes-Bereitstellungs- und -Dienstressourcen, um die hello-app auszuführen und sie intern im Cluster bereitzustellen, damit sie mit dem L7-Load-Balancer aufgerufen werden kann.

  1. Laden Sie ein Beispiel-Image für die containerisierte Demoanwendung in Harbor hoch:

    docker pull gcr.io/google-samples/hello-app:1.0 \
      --platform linux/amd64
    docker tag gcr.io/google-samples/hello-app:1.0 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    
  2. Stellen Sie das folgende Manifest im Standardcluster bereit:

    cat << EOF > hello-app.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: hello-app
      template:
        metadata:
          labels:
            app: hello-app
        spec:
          containers:
          - name: hello-server
            image: ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
            ports:
            - containerPort: 8080
          imagePullSecrets:
          - name: ${IMAGE_PULL_SECRET_NAME}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      type: ClusterIP
      selector:
        app: hello-app
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
    EOF
    
    kk apply -f hello-app.yaml
    

Prüfen Sie dann, ob die Bereitstellung und der Dienst vorhanden sind:

kk get svc,deploy -n hello-app

Demo-App in einer VM bereitstellen

In diesem Abschnitt wird die Bereitstellung einer Demoanwendung in einer VM außerhalb Ihres Kubernetes-Clusters beschrieben. Durch das Einrichten eines HTTP-Servers auf einer VM simulieren Sie eine externe Anwendung, die der Load-Balancer bereitstellen kann. So wird gezeigt, dass er Traffic zu Ressourcen innerhalb und außerhalb des Clusters verwalten kann.

Erstellen Sie zuerst eine VM für die Demo-App.

  1. Öffnen Sie die GDC-Konsole in Ihrem Webbrowser.
  2. Wählen Sie dasselbe Projekt aus, in dem Sie Ihren Standard-Kubernetes-Cluster erstellt haben.
  3. Öffnen Sie das Menü und klicken Sie auf Virtuelle Maschinen.
  4. Klicken Sie auf Instanz erstellen.
  5. Geben Sie der VM den Namen vm-workload. Für das Beispiel reicht ein Image mit 2 vCPUs aus.
  6. Wählen Sie für das Bootlaufwerk-Image eine Ubuntu 22.04-Distribution aus, auf der Python vorinstalliert ist.
  7. Klicken Sie auf Erstellen.
  8. Warten Sie einige Minuten, bis die VM bereit ist.
  9. Stellen Sie eine SSH-Verbindung zur VM her:
    1. Klicken Sie in der GDC-Konsole auf die VM.
    2. Klicken Sie auf Mit SSH verbinden.

Führen Sie nach der Verbindung mit der SSH-Konsole Folgendes aus:

mkdir ~/simple-server
cd ~/simple-server
echo 'Welcome to my VM!' > index.html
python3 -m http.server --bind 0.0.0.0 8080 &

Um Traffic an eine VM weiterzuleiten, erstellen Sie einen monitorlosen Dienst (ohne Selektoren). Dieser wird manuell der internen IP-Adresse der VM mit einer EndpointSlice-Ressource zugeordnet.

kk apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: vm-app-svc
  namespace: vm-app
spec:
  ports:
  - protocol: TCP
    port: 443
    targetPort: 443
EOF

Rufen Sie die IP-Adresse der VM vm-workload mit folgendem Befehl ab:

gdcloud compute instances list --project ${PROJECT_ID} \
  | grep workload-vm | awk '{print $3}'

Die Ausgabe ist die IP-Adresse der VM, die zum Einrichten der EndpointSlice-Ressource erforderlich ist.

Erstellen Sie die Ressource EndpointSlice, die eine Verbindung zum monitorlosen Dienst der VM-App herstellt und die IP-Adresse der VM angibt, an die der Traffic weitergeleitet werden soll.

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: vm-app-endpoints
  namespace: vm-app
  labels:
    kubernetes.io/service-name: vm-app-svc
addressType: IPv4
ports:
  - port: 8080
endpoints:
  - addresses:
    - "VM_IP"
    conditions:
      ready: true

Selbst signierte Zertifikate erstellen

In diesem Abschnitt wird beschrieben, wie Sie selbst signierte TLS-Zertifikate für Ihre Anwendungen generieren. In dieser Anleitung werden selbst signierte Zertifikate für Komfort verwendet, in Produktionsumgebungen müssen Sie jedoch Zertifikate für die Produktion verwenden, wie unter Optional: Zertifikate für die Produktion verwendenbeschrieben. Diese Zertifikate sind entscheidend, um die HTTPS-Terminierung am NGINX Gateway zu ermöglichen und so die verschlüsselte Kommunikation zwischen Clients und dem Load-Balancer für containerisierte und VM-basierte Arbeitslasten zu gewährleisten.

  1. Erstellen Sie ein Zertifikat für die containerisierte Anwendung:

    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout tls-containerized.key \
      -out tls-containerized.crt \
      -subj "/CN=k8s-app.example.com" \
      -days 365
    
    kk create secret tls tls-containerized \
      --namespace load-balancer \
      --key tls-containerized.key \
      --cert tls-containerized.crt
    
    kk create secret tls tls-containerized \
      --namespace hello-app \
      --key tls-containerized.key \
      --cert tls-containerized.crt
    
  2. Erstellen Sie ein Zertifikat für die VM-Anwendung:

    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout tls-vm.key \
      -out tls-vm.crt \
      -subj "/CN=vm-app.example.com" \
      -days 365
    
    kk create secret tls tls-vm \
      --namespace load-balancer \
      --key tls-vm.key \
      --cert tls-vm.crt
    
    kk create secret tls tls-vm \
      --namespace vm-app \
      --key tls-vm.key \
      --cert tls-vm.crt
    

NGINX bereitstellen

In diesem Abschnitt werden die Schritte zum Bereitstellen des NGINX Gateway-Controllers beschrieben, einschließlich der Installation der benutzerdefinierten Ressourcendefinitionen (CRDs) der Gateway API, der Einrichtung von NGINX Gateway Fabric mit Helm und der Überprüfung der Installation in Ihrem Standardcluster. So wird die Infrastruktur für das erweiterte Layer 7-Routing vorbereitet.

Gateway API-CRDs installieren

Für die Gateway API müssen benutzerdefinierte Ressourcendefinitionen (CRDs) im Cluster installiert sein, bevor der Controller bereitgestellt werden kann. Wir verwenden die offiziellen experimentellen benutzerdefinierten Ressourcendefinitionen (CRDs) aus dem Gateway API-Projekt (für diese Anleitung wird Version 1.2.0 verwendet).

  1. Installieren Sie die experimentellen CRDs:

    kk apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml
    
  2. Prüfen Sie mit kk get crd gateways.gateway.networking.k8s.io, ob die CRDs erfolgreich installiert wurden.

NGINX Gateway Fabric installieren

Stellen Sie den NGINX Gateway Fabric-Controller mit Helm bereit. Dieser Controller überwacht Gateway API-Ressourcen und konfiguriert NGINX für die Verarbeitung des Traffics.

  1. Legen Sie das NGINX-Image-Tag fest:

    helm template nfg oci://ghcr.io/nginx/charts/nginx-gateway-fabric | grep "image:" # get the tag of the nginx-gateway-fabric (in following case 2.4.2)
    
    export NGINX_TAG="2.4.2"
    
  2. Rufen Sie die NGINX Gateway Fabric- und NGINX-Images ab und übertragen Sie sie per Push in Ihre Harbor Registry:

    docker pull ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG}
    docker tag ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG} \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG}
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG}
    
    docker pull nginx:1.27.3
    docker tag nginx:1.27.3 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3
    
  3. Erstellen Sie den Namespace nginx-gateway und fügen Sie das Harbor-Image-Pull-Secret hinzu:

    kk create namespace nginx-gateway
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n nginx-gateway
    
  4. Stellen Sie NGINX Gateway Fabric mit Helm bereit und verweisen Sie auf die Images in Ihrer Harbor Registry:

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml helm upgrade --install ngf \
      oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
      --create-namespace -n nginx-gateway \
      --set nginxGateway.image.tag="${NGINX_TAG}" \
      --set nginxGateway.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric" \
      --set nginx.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx" \
      --set nginxGateway.serviceAccount.imagePullSecret="${IMAGE_PULL_SECRET_NAME}" \
      --set nginx.imagePullSecret="${IMAGE_PULL_SECRET_NAME}"
    

    Die Kubernetes-Bereitstellung ruft Images sicher aus Harbor ab. Dazu wird das bereitgestellte Secret (${IMAGE_PULL_SECRET_NAME}) verwendet, das die Anmeldedaten des Harbor-Roboter-Kontos enthält.

  5. Prüfen Sie, ob die GatewayClass-Ressourcen akzeptiert wurden:

    kk get gatewayclass
    

    Sie sollten nginx mit ACCEPTED = True sehen.

Gateway-Instanz erstellen

Definieren Sie die logische Load-Balancer-Instanz, die an Port 443 lauscht. Wir konfigurieren sie für den Modus Terminate. Das bedeutet, dass das Gateway die TLS-Terminierung durchführt und den Traffic entschlüsselt, bevor er weitergeleitet wird.

Erstellen und wenden Sie gateway.yaml an:

cat << EOF > gateway.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: load-balancer
spec:
  gatewayClassName: nginx
  listeners:
  - name: https-k8s-workload
    hostname: "k8s-app.example.com"
    port: 443
    protocol: HTTPS
    allowedRoutes: 
      namespaces: 
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-containerized 
  - name: https-vm-workload
    hostname: "vm-app.example.com"
    port: 443
    protocol: HTTPS
    allowedRoutes: 
      namespaces: 
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-vm 
EOF

kk apply -f gateway.yaml

Prüfen Sie, ob das Gateway erfolgreich bereitgestellt wurde, indem Sie prüfen, ob PROGRAMMED auf True gesetzt ist:

kk get gateway my-gateway --n load-balancer

Prüfen Sie, ob ein verwalteter GDC-L4-Load-Balancer als Dienst neben dem Gateway bereitgestellt wurde.

kk get services -n load-balancer

Prüfen Sie, ob der NGINX-Dienst erstellt und konfiguriert wurde. Die Ausgabe sollte so aussehen:

NAME               TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)         AGE
my-gateway-nginx   LoadBalancer   10.252.19.148   10.200.32.43   443:30649/TCP   45h

L7-Routing-Logik definieren (HTTPRoute)

Binden Sie HTTPRoutes an Ihr Gateway, um festzulegen, wie Traffic basierend auf dem angeforderten Hostnamen (SNI) verteilt werden soll.

Erstellen und wenden Sie routing.yaml an:

cat << EOF > routing.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: k8s-http-route
  namespace: hello-app
spec:
  parentRefs:
  - name: my-gateway 
    namespace: load-balancer
  hostnames:
  - "k8s-app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: hello-app 
      namespace: hello-app
      port: 80          
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: vm-http-route
  namespace: vm-app
spec:
  parentRefs:
  - name: my-gateway
    namespace: load-balancer
  hostnames:
  - "vm-app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: vm-app-svc  
      namespace: vm-app
      port: 443       
EOF

kk apply -f routing.yaml   

IP-Adresse des Load-Balancers abrufen

Führen Sie den Befehl aus, um die IP-Adresse des NGINX-Load-Balancers abzurufen:

kk get services/my-gateway-nginx \
  -n load-balancer \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

Diese ist erforderlich, um den Zugriff auf die Anwendungen zu prüfen. Sie wird als LOAD_BALANCER_IP bezeichnet.

Client-VM erstellen

Folgen Sie der Anleitung, um eine Client-VM zu erstellen.

  1. Öffnen Sie die GDC-Konsole in Ihrem Webbrowser.
  2. Öffnen Sie das Menü und klicken Sie auf Virtuelle Maschinen.
  3. Klicken Sie auf Instanz erstellen.
  4. Erstellen Sie eine VM mit dem Namen client, wählen Sie einen kleinen Maschinentyp und entweder Rocky Linux oder Ubuntu aus, auf denen curl vorinstalliert ist.
  5. Klicken Sie auf Erstellen.
  6. Warten Sie einige Minuten, bis die VM bereit ist.
  7. Nachdem die VM bereit ist, stellen Sie eine SSH-Verbindung zur VM her:
    1. Klicken Sie in der GDC-Konsole auf die VM.
    2. Klicken Sie auf Mit SSH verbinden.

Zugriff und Routing prüfen

Führen Sie curl-Befehle von Ihrer Client-VM aus, um das Routing zu testen. Sie können mit den definierten Hostnamen und der IP-Adresse des Load-Balancers eine Verbindung zu beiden Anwendungen herstellen.

Wenn Sie das Flag --resolve in curl übergeben, können Sie erzwingen, dass die Domainnamen in die IP-Adresse Ihres GDC-L4-Load-Balancers mit Air Gap aufgelöst werden. Beachten Sie, dass wir das Flag -k übergeben, um die selbst signierten Zertifikate als vertrauenswürdig einzustufen.

Testen Sie die containerisierte Kubernetes-Anwendung:

curl -k --resolve k8s-app.example.com:443:$LOAD_BALANCER_IP https://k8s-app.example.com -v

Testen Sie die externe VM-Anwendung:

curl -k --resolve vm-app.example.com:443:$LOAD_BALANCER_IP https://vm-app.example.com -v

Wenn alles richtig konfiguriert ist, fungiert der Gateway-Controller nahtlos als TLS-Terminator und leitet den Traffic an das Ziel weiter.

Optional: Zertifikate für die Produktion verwenden

In diesem Abschnitt wird beschrieben, wie Sie den GDC-CA-Dienst mit Air Gap verwenden, um eine private Stammzertifizierungsstelle (CA) zu erstellen, signierte Zertifikate für Ihre Arbeitslasten auszustellen und Ihren GDC-Standardcluster mit Air Gap und Ihre Client-VMs sicher zu aktualisieren.

In diesem Abschnitt wird beschrieben, wie Sie den GDC-CA -Dienst mit Air Gap verwenden, um eine private Stammzertifizierungsstelle (CA) zu erstellen und gültige Zertifikate für Ihre Anwendungen auszustellen. Wenn Sie diese Stammzertifizierungsstelle auf Ihrer Client-VM installieren, können Sie prüfen, ob die TLS-Terminierung nahtlos mit vertrauenswürdigen Zertifikaten funktioniert, ohne SSL-Warnungen umgehen zu müssen (z. B. mit curl -k).

Erforderliche Berechtigungen gewähren und Anmeldedaten abrufen

Um den CA-Dienst zu verwalten und Zertifikate auszustellen, benötigt Ihr Nutzer die entsprechenden IAM-Rollen im Projekt.

  1. Gewähren Sie die Rollen certificate-authority-service-admin und certificate-requester:

    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-authority-service-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-requester
    
  2. Rufen Sie die Anmeldedaten des Management API-Servers ab:

    gdcloud clusters get-credentials ${ORG_NAME}-admin
    

Stammzertifizierungsstelle erstellen

Sie erstellen eine Zertifizierungsstelle auf dem Management API-Server in Ihrem Projekt-Namespace.

  1. Wenden Sie die CertificateAuthority-Ressource an:

    km apply -f - <<EOF
    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateAuthority
    metadata:
      name: my-root-ca
      namespace: ${PROJECT_ID}
    spec:
      caProfile:
        commonName: "My Root CA"
        duration: 87600h # 10 years
        keyAlgorithm: RSA_2048
        maxChainLength: 1
      caType: ROOT
      keyLocation: HSM
      rotationPolicy:
        cronTime: 0 0 1 1 *
    EOF
    
    km -n ${PROJECT_ID} get \
    certificateauthority.pki.security.gdc.goog/my-root-ca -ojson \
    | jq -r '
    .status.conditions[] | select( .type as $id | "Ready" | index($id)) .status'
    

Zertifikate ausstellen und bereitstellen

Nachdem die Zertifizierungsstelle bereit ist, fordern Sie Zertifikate für die containerisierte Anwendung und die VM-basierte Anwendung an. Diese Anfragen erfolgen auf dem Management API-Server und die resultierenden Schlüssel müssen in Ihren Standardcluster verschoben werden.

Erstellen Sie Anfragen für beide Domains:

km apply -f - <<EOF
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-containerized-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "k8s-app.example.com"
      dnsNames:
      - "k8s-app.example.com"
  signedCertificateSecret: tls-containerized-signed
---
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-vm-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "vm-app.example.com"
      dnsNames:
      - "vm-app.example.com"
  signedCertificateSecret: tls-vm-signed
EOF

Warten Sie einige Minuten, bis die Zertifikate ausgestellt wurden. Sie können prüfen, ob sie bereit sind, wenn die Bedingung „Ready“ (Bereit) auf „True“ gesetzt ist:

km get certificaterequests -n ${PROJECT_ID}

Standardcluster aktualisieren

Wenn Sie die vorherigen Abschnitte dieser Anleitung befolgt haben, haben Sie selbst signierte Secrets in Ihrem Standardcluster. Sie müssen sie löschen, bevor Sie die neuen signierten Versionen erstellen:

kk delete secret tls-containerized -n load-balancer
kk delete secret tls-vm -n load-balancer

kk delete secret tls-containerized -n hello-app
kk delete secret tls-vm -n vm-app

Extrahieren Sie nun die signierten Zertifikate vom Management API-Server und erstellen Sie die neuen Secrets im Standardcluster.

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-containerized.key

kk create secret tls tls-containerized \
  --namespace load-balancer \
  --key tls-containerized.key \
  --cert tls-containerized.crt

kk create secret tls tls-containerized \
  --namespace hello-app \
  --key tls-containerized.key \
  --cert tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-vm.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-vm.key

kk create secret tls tls-vm \
  --namespace load-balancer \
  --key tls-vm.key \
  --cert tls-vm.crt

kk create secret tls tls-vm \
  --namespace vm-app \
  --key tls-vm.key \
  --cert tls-vm.crt

Die neuen Secrets werden automatisch abgerufen und von Load-Balancern aktualisiert.

Client-Vertrauenswürdigkeit konfigurieren

Um die Einrichtung zu prüfen, müssen Sie Ihrer Client-VM mitteilen, dass sie Ihrer neuen Stammzertifizierungsstelle vertrauen soll.

Extrahieren Sie das Stamm-CA-Zertifikat in eine Datei:

km get secret -n ${PROJECT_ID} my-root-ca-secret \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > my-root-ca.crt

Übertragen Sie das Zertifikat auf Ihre Client-VM. Sie können den Inhalt von „my-root-ca.crt“ kopieren und in eine Datei auf der Client-VM einfügen.

Aktualisieren Sie auf der Client-VM den Trust Store.

Wenn die client-VM Ubuntu ist:

sudo cp my-root-ca.crt /usr/local/share/ca-certificates/
sudo chmod 644 /usr/local/share/ca-certificates/my-root-ca.crt
sudo update-ca-certificates

Wenn die client-VM Rocky Linux ist:

sudo cp my-root-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

Zugriff prüfen

Sie können jetzt mit curl ohne das Flag -k auf Ihre Anwendungen zugreifen. Die Verbindung ist vollständig vertrauenswürdig.

Testen Sie die containerisierte Kubernetes-Anwendung:

curl -v --resolve k8s-app.example.com:443:LOAD_BALANDER_IP https://k8s-app.example.com

Testen Sie die VM-Anwendung:

curl -v --resolve vm.example.com:443:LOAD_BALANDER_IP https://vm-app.example.com

Wenn alles erfolgreich war, wird die Anwendungsausgabe sofort ohne SSL-Zertifikatswarnungen angezeigt.