Configura una malla de servicios de varios clústeres

En esta guía, se muestra cómo agregar un clúster de GKE nuevo a una malla de servicios existente.

Antes de comenzar

Antes de agregar un clúster, asegúrate de completar las instrucciones en Prepárate para implementar con la API de puerta de enlace de GKE, incluida Habilita Services de varios clústeres.

Crea un nuevo clúster de GKE

  1. Crea un clúster nuevo con el comando siguiente:

    gcloud container clusters create gke-2 \
      --zone=us-west1-a \
      --enable-ip-alias \
      --workload-pool=PROJECT_ID.svc.id.goog \
      --scopes=https://www.googleapis.com/auth/cloud-platform \
      --release-channel regular \
      --project=PROJECT_ID
    
  2. Cambia al clúster que acabas de crear mediante el siguiente comando:

    gcloud container clusters get-credentials gke-2 --zone us-west1-a
    
  3. Cambia el nombre del contexto del clúster:

    kubectl config rename-context gke_PROJECT_ID_us-west1-a_gke-2 gke-2
    

Registra el clúster en una flota

  1. Después de crear el clúster, regístralo en tu flota:

    gcloud alpha container hub memberships register gke-2 \
      --gke-cluster us-west1-a/gke-2 \
      --enable-workload-identity \
      --project=PROJECT_ID
    
  2. Verifica que los clústeres estén registrados en la flota:

    gcloud alpha container hub memberships list --project=PROJECT_ID
    

    La flota incluye el clúster que acabas de crear y el que creaste antes:

    NAME          EXTERNAL_ID
    gke-1  657e835d-3b6b-4bc5-9283-99d2da8c2e1b
    gke-2  f3727836-9cb0-4ffa-b0c8-d51001742f19
    

Implementa el inyector de sidecar de Envoy en el nuevo clúster de GKE

Sigue las instrucciones para implementar el inyector de sidecar de Envoy y, luego, implementa el inyector en el clúster gke-2.

Expande tu malla de servicios al nuevo clúster de GKE

Implementa una malla de servicios de sidecar de Envoy te muestra cómo configurar una malla de servicios en el clúster gke-1, en el que se ejecuta el service store. En esta sección, se muestra cómo expandir la malla de servicios para incluir un service payments que se ejecute en el clúster gke-2. Ya existe un recurso Mesh en el clúster de configuración, por lo que no necesitas crear un recurso Mesh en el clúster nuevo.

Implemente el servicio payments

  1. En el archivo payments.yaml, guarda el siguiente manifiesto:

    kind: Namespace
    apiVersion: v1
    metadata:
      name: payments
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: payments
      namespace: payments
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: payments
          version: v1
      template:
        metadata:
          labels:
            app: payments
            version: v1
        spec:
          containers:
          - name: whereami
            image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1.2.20
            ports:
            - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: payments
      namespace: payments
    spec:
      selector:
        app: payments
      ports:
      - port: 8080
        targetPort: 8080
    
  2. Aplica el manifiesto al clúster gke-2:

    kubectl apply --context gke-2 -f payments.yaml
    

Exporta el service payments

Todos los recursos de la API de puerta de enlace se almacenan de forma centralizada en el clúster de configuración gke-1. Los servicios en otros clústeres de la flota deben exportarse para que los recursos de la API de puerta de enlace en el clúster gke-1 puedan hacer referencia a ellos cuando configures el comportamiento de herramientas de redes de la malla de servicios.

Para obtener una explicación detallada de cómo funcionan ServiceExport y ServiceImport, lee Services de varios clústeres.

  1. Crea el espacio de nombres payments en el clúster gke-1. El service payments en el clúster gke-1 se exporta a todos los clústeres en la flota que se encuentran en el mismo espacio de nombres.

    kubectl create namespace payments --context gke-1
    
  2. En el archivo export-payments.yaml, guarda el siguiente manifiesto:

    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: payments
      namespace: payments
    
  3. Aplica el manifiesto ServiceExport en el clúster gke-2:

    kubectl apply --context gke-2 -f export-payments.yaml
    
  4. Después de unos minutos, ejecuta el siguiente comando para verificar que el controlador de Services de varios clústeres de gke-1 creó el serviceImports adjunto:

    kubectl get serviceimports --context gke-1 --namespace payments
    

    El resultado debería ser similar al siguiente:

    NAME           TYPE           IP                  AGE
    payments       ClusterSetIP   ["10.112.31.15"]    6m54s
    

Configura un recurso HTTPRoute para el service payments

  1. En el archivo payments-route.yaml, guarda el siguiente manifiesto HTTPRoute:

    apiVersion: gateway.networking.k8s.io/v1alpha2
    kind: HTTPRoute
    metadata:
      name: payments-route
      namespace: payments
    spec:
      parentRefs:
      - name: td-mesh
        namespace: default
        group: net.gke.io
        kind: TDMesh
      hostnames:
      - "example.com"
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /payments
        backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          namespace: payments
          name: payments
          port: 8080
    
  2. Aplica el manifiesto de ruta a gke-1:

    kubectl apply --context gke-1 -f payments-route.yaml
    

Valida la implementación

Inspecciona el estado y los eventos de Mesh para verificar que Mesh y HTTPRoute se hayan implementado de forma correcta.

  1. Ejecuta el siguiente comando:

    kubectl describe tdmesh td-mesh -–context gke-1
    

    El resultado debería ser similar al siguiente ejemplo:

    ...
    Status:
      Conditions:
        Last Transition Time:  2022-04-14T22:49:56Z
        Message:
        Reason:                MeshReady
        Status:                True
        Type:                  Ready
        Last Transition Time:  2022-04-14T22:27:17Z
        Message:
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
    Events:
      Type    Reason  Age                From                Message
      ----    ------  ----               ----                -------
      Normal  ADD     23m                mc-mesh-controller  Processing mesh default/td-mesh
      Normal  UPDATE  23m                mc-mesh-controller  Processing mesh default/td-mesh
      Normal  SYNC    23m                mc-mesh-controller  Processing mesh default/td-mesh
      Normal  SYNC    71s                mc-mesh-controller  SYNC on default/td-mesh was a success
    
  2. Para verificar la implementación, implementa un Pod de cliente en uno de los clústeres. En el archivo client.yaml, guarda lo siguiente:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        run: client
      name: client
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: client
      template:
        metadata:
          labels:
            run: client
        spec:
          containers:
          - name: client
            image: curlimages/curl
            command:
            - sh
            - -c
            - while true; do sleep 1; done
    
  3. Aplica el manifiesto

    kubectl apply -f client.yaml --context $CLUSTER
    

    El inyector de sidecar que se ejecuta en el clúster inserta de forma automática un contenedor de Envoy en el Pod del cliente.

  4. Para verificar que se inserte el contenedor de Envoy, ejecuta el siguiente comando:

    kubectl describe pods -l run=client --context $CLUSTER
    

    El resultado es similar al siguiente:

    ...
    Init Containers:
      # Istio-init sets up traffic interception for the Pod.
      istio-init:
    ...
      # td-bootstrap-writer generates the Envoy bootstrap file for the Envoy container
      td-bootstrap-writer:
    ...
    Containers:
    # client is the client container that runs application code.
      client:
    ...
    # Envoy is the container that runs the injected Envoy proxy.
      envoy:
    ...
    
  5. Después de aprovisionar el Pod cliente y la mesh, envía una solicitud desde el Pod cliente al servicio store:

    # Get the name of the client Pod.
    CLIENT_POD=$(kubectl get pod --context $CLUSTER -l run=client -o=jsonpath='{.items[0].metadata.name}')
    
    # The VIP where the following request will be sent. Because requests from the
    # Busybox container are redirected to the Envoy proxy, the IP address can
    # be any other address, such as 10.0.0.2 or 192.168.0.1.
    VIP='10.0.0.1'
    
    # Command to send a request to store.
    TEST_CMD="curl -v -H 'Host: example.com' $VIP/store"
    
    # Execute the test command in the client container.
    kubectl exec -it $CLIENT_POD -c client --context $CLUSTER -- /bin/sh -c "$TEST_CMD"
    

    El resultado debe mostrar que uno de los Pods store en gke-1 entrega la solicitud:

    {
      "cluster_name": "gke-1",
      "zone": "us-central1-a",
      "host_header": "example.com",
    ...
    }
    
  6. Envía una solicitud al service payments:

    # Command to send a request to payments.
    TEST_CMD="curl -v -H 'host: example.com' $VIP/payments"
    
    # Execute the test command in the client container.
    kubectl exec -it $CLIENT_POD -c client -- /bin/sh -c "$TEST_CMD"
    

    El resultado debe mostrar que uno de los Pods payments en gke-2 entrega la solicitud:

    {
      "cluster_name": "gke-2",
      "zone": "us-west1-a",
      "host_header": "example.com",
    ...
    }
    

¿Qué sigue?