Del perímetro a la malla de varios clústeres: Implementa aplicaciones distribuidas globalmente a través de la puerta de enlace de GKE y Cloud Service Mesh

Last reviewed 2026-06-04 UTC

En este documento, se muestra cómo completar las siguientes tareas:

Esta guía de implementación está dirigida a los administradores de la plataforma. También está dirigido a profesionales avanzados que ejecutan Cloud Service Mesh. Las instrucciones también funcionan para Istio on GKE.

Arquitectura

En el siguiente diagrama, se muestra la topología de entrada predeterminada de una malla de servicios: un balanceador de cargas de TCP/UDP externo que expone los proxies de puerta de enlace de entrada en un solo clúster:

Un balanceador de cargas externo enruta los clientes externos a la malla a través de proxies de puerta de enlace de entrada.

En esta guía de implementación, se usan recursos de puerta de enlace de Google Kubernetes Engine (GKE). Específicamente, usa una puerta de enlace de varios clústeres para configurar el balanceo de cargas multirregional frente a varios clústeres de Autopilot que se distribuyen en dos regiones.

Encriptación TLS del cliente, un balanceador de cargas y la malla

En el diagrama anterior, se muestra cómo fluyen los datos a través de situaciones de entrada de la nube y entrada de la malla. Para obtener más información, consulta la explicación del diagrama de arquitectura en el documento de arquitectura de referencia asociado.

Objetivos

  • Implementa un par de clústeres de GKE Autopilot en Google Cloud en la misma flota.
  • Implementar una Cloud Service Mesh basada en Istio en la misma flota
  • Configurar un balanceador de cargas a través de la puerta de enlace de GKE para finalizar el tráfico HTTPS público.
  • Dirigir el tráfico de HTTPS público a las aplicaciones alojadas en Cloud Service Mesh que se implementan en varios clústeres y regiones.
  • Implementar la aplicación de muestra whereami en ambos clústeres de Autopilot.

Optimización de costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Es posible que los usuarios de Google Cloud nuevos cumplan con los requisitos para acceder a una prueba gratuita.

Cuando completes las tareas que se describen en este documento, podrás borrar los recursos que creaste para evitar que se te siga facturando. Para obtener más información, consulta Realiza una limpieza.

Antes de comenzar

  1. En la consola de Google Cloud , en la página del selector de proyectos, selecciona o crea un proyecto de Google Cloud .

    Roles necesarios para seleccionar o crear un proyecto

    • Selecciona un proyecto: Para seleccionar un proyecto, no se requiere un rol de IAM específico. Puedes seleccionar cualquier proyecto en el que se te haya otorgado un rol.
    • Crear un proyecto: Para crear un proyecto, necesitas el rol de Creador de proyectos (roles/resourcemanager.projectCreator), que contiene el permiso resourcemanager.projects.create. Obtén más información para otorgar roles.

    Ir al selector de proyectos

  2. Verifica que la facturación esté habilitada para tu proyecto de Google Cloud .

  3. En la consola de Google Cloud , activa Cloud Shell.

    Activa Cloud Shell

    Ejecuta todos los comandos de terminal de esta implementación desde Cloud Shell.

  4. Configura tu proyecto Google Cloud predeterminado:

    export PROJECT=PROJECT_ID
    export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format="value(projectNumber)")
    gcloud config set project PROJECT_ID
    

    Reemplaza PROJECT_ID por el ID del proyecto que deseas usar para esta implementación.

  5. Cree un directorio de trabajo:

    mkdir -p ${HOME}/edge-to-mesh-multi-region
    cd ${HOME}/edge-to-mesh-multi-region
    export WORKDIR=`pwd`
    

Crea clústeres de GKE

En esta sección, crearás clústeres de GKE para alojar las aplicaciones y la infraestructura de asistencia, que crearás más adelante en esta guía de implementación.

  1. En Cloud Shell, crea un archivo kubeconfig nuevo. Con este paso te aseguras de no causar un conflicto con el archivo kubeconfig (predeterminado) existente.

    touch edge2mesh_mr_kubeconfig
    export KUBECONFIG=${WORKDIR}/edge2mesh_mr_kubeconfig
    
  2. Define las variables de entorno que se usan cuando se crean los clústeres de GKE y los recursos que contienen. Modifica las opciones de región predeterminadas para que se adapten a tus propósitos.

    export CLUSTER_1_NAME=edge-to-mesh-01
    export CLUSTER_2_NAME=edge-to-mesh-02
    export CLUSTER_1_REGION=us-central1
    export CLUSTER_2_REGION=us-east4
    export PUBLIC_ENDPOINT=frontend.endpoints.PROJECT_ID.cloud.goog
    
  3. Habilita las APIs de Google Cloud que se usan en esta guía:

    gcloud services enable \
      container.googleapis.com \
      mesh.googleapis.com \
      gkehub.googleapis.com \
      multiclusterservicediscovery.googleapis.com \
      multiclusteringress.googleapis.com \
      trafficdirector.googleapis.com \
      certificatemanager.googleapis.com
    
  4. Crea un clúster de GKE Autopilot con nodos privados en CLUSTER_1_REGION. Usa la marca --async para evitar esperar a que el primer clúster se aprovisione y se registre en la flota:

    gcloud container clusters create-auto --async \
    ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} \
    --release-channel rapid \
    --enable-private-nodes --enable-fleet
    
  5. Crea y registra un segundo clúster de Autopilot en CLUSTER_2_REGION:

    gcloud container clusters create-auto \
    ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} \
    --release-channel rapid \
    --enable-private-nodes --enable-fleet
    
  6. Asegúrate de que los clústeres estén en ejecución. Puede tomar hasta 20 minutos hasta que todos los clústeres estén en ejecución:

    gcloud container clusters list
    

    El resultado es similar a este:

    NAME             LOCATION     MASTER_VERSION      MASTER_IP      MACHINE_TYPE   NODE_VERSION        NUM_NODES  STATUS   STACK_TYPE
    edge-to-mesh-01  us-central1  1.35.5-gke.1000000  34.31.166.104  ek-standard-8  1.35.5-gke.1000000  1          RUNNING  IPV4
    edge-to-mesh-02  us-east4     1.35.5-gke.1000000  35.245.233.88  ek-standard-8  1.35.5-gke.1000000  1          RUNNING  IPV4
    
  7. Recopila las credenciales para CLUSTER_1_NAME. Creaste CLUSTER_1_NAME de forma asíncrona para poder ejecutar comandos adicionales mientras se aprovisiona el clúster.

    gcloud container clusters get-credentials ${CLUSTER_1_NAME} \
        --region ${CLUSTER_1_REGION}
    
  8. Para aclarar los nombres de los contextos de Kubernetes, cámbialos por los nombres de los clústeres:

    kubectl config rename-context gke_PROJECT_ID_${CLUSTER_1_REGION}_${CLUSTER_1_NAME} ${CLUSTER_1_NAME}
    kubectl config rename-context gke_PROJECT_ID_${CLUSTER_2_REGION}_${CLUSTER_2_NAME} ${CLUSTER_2_NAME}
    

Instala una malla de servicios

En esta sección, debes configurar Cloud Service Mesh administrado con la API de Fleet. El uso de la API de la flota para habilitar Cloud Service Mesh proporciona un enfoque declarativo a fin de aprovisionar una malla de servicios.

  1. En Cloud Shell, habilita Cloud Service Mesh en la flota:

    gcloud container fleet mesh enable
    
  2. Habilita la administración automática del plano de control y del plano de datos:

    gcloud container fleet mesh update \
      --management automatic \
      --memberships ${CLUSTER_1_NAME},${CLUSTER_2_NAME}
    
  3. Espera alrededor de 20 minutos. Luego, verifica que el estado del plano de control sea ACTIVE:

    gcloud container fleet mesh describe
    

    El resultado es similar a este:

    createTime: '2026-06-04T23:40:02.666228685Z'
    membershipSpecs:
      projects/497535075790/locations/us-central1/memberships/edge-to-mesh-01:
        mesh:
          management: MANAGEMENT_AUTOMATIC
      projects/497535075790/locations/us-east4/memberships/edge-to-mesh-02:
        mesh:
          management: MANAGEMENT_AUTOMATIC
    membershipStates:
      projects/497535075790/locations/us-central1/memberships/edge-to-mesh-01:
        servicemesh:
          conditions:
          - code: VPCSC_GA_SUPPORTED
            details: This control plane supports VPC-SC GA.
            documentationLink: http://cloud.google.com/service-mesh/docs/managed/vpc-sc
            severity: INFO
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            implementation: TRAFFIC_DIRECTOR
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
          code: OK
          description: 'Revision ready for use: asm-managed-rapid.'
          updateTime: '2026-06-04T23:45:52.958139396Z'
      projects/497535075790/locations/us-east4/memberships/edge-to-mesh-02:
        servicemesh:
          conditions:
          - code: VPCSC_GA_SUPPORTED
            details: This control plane supports VPC-SC GA.
            documentationLink: http://cloud.google.com/service-mesh/docs/managed/vpc-sc
            severity: INFO
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            implementation: TRAFFIC_DIRECTOR
            state: ACTIVE
          dataPlaneManagement:
            details:
            - code: OK
              details: Service is running.
            state: ACTIVE
        state:
          code: OK
          description: 'Revision ready for use: asm-managed-rapid.'
          updateTime: '2026-06-04T23:45:54.621862416Z'
    name: projects/e2m-mc-h2c/locations/global/features/servicemesh
    resourceState:
      state: ACTIVE
    spec: {}
    updateTime: '2026-06-04T23:40:55.123874541Z'
    

Implementa un balanceador de cargas de aplicaciones externo y crea puertas de enlace de entrada

En esta sección, implementarás un balanceador de cargas de aplicaciones externo a través de GKE Gateway Controller y crearás puertas de enlace de entrada para ambos clústeres. Los recursos gateway y gatewayClass automatizan el aprovisionamiento del balanceador de cargas y la verificación de estado del backend. Para proporcionar la finalización de TLS en el balanceador de cargas, crea recursos del Administrador de certificados y adjúntalos al balanceador de cargas. Además, debes usar Endpoints para aprovisionar de forma automática un nombre de DNS público para la aplicación.

Instala una puerta de enlace de entrada en ambos clústeres

Como práctica recomendada de seguridad, te recomendamos que implementes la puerta de enlace de entrada en un espacio de nombres diferente en el plano de control de malla.

  1. En Cloud Shell, crea un espacio de nombres ingress-gateway dedicado en cada clúster:

    kubectl --context=${CLUSTER_1_NAME} create namespace ingress-gateway
    kubectl --context=${CLUSTER_2_NAME} create namespace ingress-gateway
    
  2. Agrega una etiqueta de espacio de nombres al espacio de nombres ingress-gateway:

    kubectl --context=${CLUSTER_1_NAME} label namespace ingress-gateway istio-injection=enabled
    kubectl --context=${CLUSTER_2_NAME} label namespace ingress-gateway istio-injection=enabled
    

    El resultado es similar a este:

    namespace/ingress-gateway labeled
    

    Si etiquetas los espacios de nombres ingress-gateway con istio-injection=enabled, se indica a Cloud Service Mesh que inserte de manera automática proxies de sidecar de Envoy cuando se implementa un Pod.

  3. Genera un certificado autofirmado para usarlo en el futuro:

    openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
     -subj "/CN=frontend.endpoints.PROJECT_ID.cloud.goog/O=Edge2Mesh Inc" \
     -keyout ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
     -out ${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
    

    El certificado proporciona una capa adicional de encriptación entre el balanceador de cargas y las puertas de enlace de entrada de la malla de servicios. También habilita la compatibilidad con protocolos basados en HTTP/2, como gRPC. Las instrucciones para adjuntar el certificado autofirmado a las puertas de enlace de entrada se proporcionan más adelante en Crea recursos de dirección IP externa, registro DNS y certificado TLS.

    Si deseas usar HTTP/2 para la conexión de GFE a la malla, pero no necesitas tu propia encriptación, puedes usar H2C.

    Para obtener más información sobre los requisitos del certificado de puerta de enlace de entrada, consulta Encriptación del balanceador de cargas a los backends.

  4. Crea un Secret de Kubernetes en cada clúster para almacenar el certificado autofirmado:

    kubectl --context ${CLUSTER_1_NAME} -n ingress-gateway create secret tls \
     edge2mesh-credential \
     --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
     --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
    kubectl --context ${CLUSTER_2_NAME} -n ingress-gateway create secret tls \
     edge2mesh-credential \
     --key=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.key \
     --cert=${WORKDIR}/frontend.endpoints.PROJECT_ID.cloud.goog.crt
    
  5. Para integrarla al balanceador de cargas de aplicaciones externo, crea una variante de kustomize para configurar los recursos de la puerta de enlace de entrada:

    mkdir -p ${WORKDIR}/asm-ig/base
    
    cat <<EOF > ${WORKDIR}/asm-ig/base/kustomization.yaml
    resources:
      - github.com/GoogleCloudPlatform/anthos-service-mesh-samples/docs/ingress-gateway-asm-manifests/base
    EOF
    
    mkdir ${WORKDIR}/asm-ig/variant
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/role.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: asm-ingressgateway
      namespace: ingress-gateway
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    EOF
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/rolebinding.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: asm-ingressgateway
      namespace: ingress-gateway
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: asm-ingressgateway
    subjects:
      - kind: ServiceAccount
        name: asm-ingressgateway
    EOF
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/service-proto-type.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: asm-ingressgateway
      namespace: ingress-gateway
    spec:
      ports:
      - name: status-port
        port: 15021
        protocol: TCP
        targetPort: 15021
      - name: http
        port: 80
        targetPort: 8080
        appProtocol: HTTP
      - name: https
        port: 443
        targetPort: 8443
        appProtocol: HTTP2
      type: ClusterIP
    EOF
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/gateway.yaml
    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
      name: asm-ingressgateway
      namespace: ingress-gateway
    spec:
     servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        hosts:
        - "*" # IMPORTANT: Must use wildcard here when using SSL, as SNI isn't passed from GFE
        tls:
          mode: SIMPLE
          credentialName: edge2mesh-credential
    EOF
    
    cat <<EOF > ${WORKDIR}/asm-ig/variant/kustomization.yaml
    namespace: ingress-gateway
    resources:
    - ../base
    - role.yaml
    - rolebinding.yaml
    patches:
    - path: service-proto-type.yaml
      target:
        kind: Service
    - path: gateway.yaml
      target:
        kind: Gateway
    EOF
    
  6. Aplica la configuración de la puerta de enlace de entrada a ambos clústeres:

    kubectl --context ${CLUSTER_1_NAME} apply -k ${WORKDIR}/asm-ig/variant
    kubectl --context ${CLUSTER_2_NAME} apply -k ${WORKDIR}/asm-ig/variant
    

Expón los Pods de la puerta de enlace de entrada al balanceador de cargas mediante un servicio de varios clústeres

En esta sección, exportarás los Pods de la puerta de enlace de entrada a través de un recurso personalizado ServiceExport. Debes exportar los Pods de la puerta de enlace de entrada a través de un recurso personalizado ServiceExport por los siguientes motivos:

  1. En Cloud Shell, habilita los servicios de varios clústeres (MCS) para la flota:

    gcloud container fleet multi-cluster-services enable
    
  2. Otorga al MCS los permisos de IAM necesarios para el proyecto o la flota:

    gcloud projects add-iam-policy-binding PROJECT_ID \
     --member "serviceAccount:PROJECT_ID.svc.id.goog[gke-mcs/gke-mcs-importer]" \
     --role "roles/compute.networkViewer"
    
  3. Crea el archivo YAML ServiceExport:

    cat <<EOF > ${WORKDIR}/svc_export.yaml
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: asm-ingressgateway
      namespace: ingress-gateway
    EOF
    
  4. Aplica el archivo YAML de ServiceExport a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/svc_export.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/svc_export.yaml
    

    Si recibes el siguiente mensaje de error, espera unos minutos para que se instalen las definiciones de recursos personalizados (CRD) de MCS. Luego, vuelve a ejecutar los comandos para aplicar el archivo YAML de ServiceExport a ambos clústeres.

    error: resource mapping not found for name: "asm-ingressgateway" namespace: "ingress-gateway" from "svc_export.yaml": no matches for kind "ServiceExport" in version "net.gke.io/v1"
    ensure CRDs are installed first
    

Crea recursos de direcciones IP externas, registros DNS y certificados TLS

En esta sección, crearás recursos de redes que admitan los recursos de balanceo de cargas que crearás más adelante en esta implementación.

  1. En Cloud Shell, reserva una dirección IP externa estática:

    gcloud compute addresses create mcg-ip --global
    

    El recurso de GKE Gateway usa una dirección IP estática. Permite que la dirección IP siga siendo la misma, incluso si se vuelve a crear el balanceador de cargas externo.

  2. Obtén la dirección IP estática y almacénala como una variable de entorno:

    export MCG_IP=$(gcloud compute addresses describe mcg-ip --global --format "value(address)")
    echo ${MCG_IP}
    

    Para crear una asignación estable y fácil de usar para la dirección IP de Ingress, debes tener un registro DNS público.

    Puedes usar el proveedor de DNS y el esquema de automatización que desees. En esta implementación, se usa Endpoints en lugar de crear una zona del DNS administrada. Endpoints proporciona un registro DNS administrado por Google gratuito para una dirección IP externa.

  3. Ejecuta el siguiente comando para crear un archivo YAML llamado dns-spec.yaml:

    cat <<EOF > ${WORKDIR}/dns-spec.yaml
    swagger: "2.0"
    info:
      description: "Cloud Endpoints DNS"
      title: "Cloud Endpoints DNS"
      version: "1.0.0"
    paths: {}
    host: "frontend.endpoints.PROJECT_ID.cloud.goog"
    x-google-endpoints:
    - name: "frontend.endpoints.PROJECT_ID.cloud.goog"
      target: "${MCG_IP}"
    EOF
    

    El archivo dns-spec.yaml define el registro DNS público en el formato frontend.endpoints.PROJECT_ID.cloud.goog, en el que PROJECT_ID es tu identificador de proyecto único.

  4. Implementa el archivo dns-spec.yaml para crear la entrada de DNS. Este proceso tarda unos minutos.

    gcloud endpoints services deploy ${WORKDIR}/dns-spec.yaml
    
  5. Crea un certificado con el Administrador de certificados para el nombre de entrada de DNS que creaste en el paso anterior:

    gcloud certificate-manager certificates create mcg-cert \
        --domains="frontend.endpoints.PROJECT_ID.cloud.goog"
    

    Se usa un certificado TLS administrado por Google para finalizar las solicitudes entrantes de clientes en el balanceador de cargas.

  6. Crea un mapa de certificados:

    gcloud certificate-manager maps create mcg-cert-map
    

    El balanceador de cargas hace referencia al certificado a través de la entrada del mapa de certificados que creas en el siguiente paso.

  7. Crea una entrada de mapa de certificados para el certificado que creaste anteriormente en esta sección:

    gcloud certificate-manager maps entries create mcg-cert-map-entry \
        --map="mcg-cert-map" \
        --certificates="mcg-cert" \
        --hostname="frontend.endpoints.PROJECT_ID.cloud.goog"
    

Crea políticas de servicio de backend y recursos de balanceador de cargas

En esta sección, completarás las siguientes tareas:

  • Crea una política de seguridad de Cloud Armor con reglas.
  • Crea una política que permita que el balanceador de cargas verifique la capacidad de respuesta de los Pods de la puerta de enlace de entrada a través del archivo YAML ServiceExport que creaste antes.
  • Usa la API de GKE Gateway para crear un recurso de balanceador de cargas.
  • Usa el recurso personalizado GatewayClass para establecer el tipo específico de balanceador de cargas.
  • Habilita el balanceo de cargas de varios clústeres para la flota y designa uno de los clústeres como el clúster de configuración para la flota.
  1. En Cloud Shell, crea una política de seguridad de Cloud Armor:

    gcloud compute security-policies create edge-fw-policy \
        --description "Block XSS attacks"
    
  2. Crea una regla para la política de seguridad:

    gcloud compute security-policies rules create 1000 \
        --security-policy edge-fw-policy \
        --expression "evaluatePreconfiguredExpr('xss-stable')" \
        --action "deny-403" \
        --description "XSS attack filtering"
    
  3. Crea un archivo YAML para la política de seguridad y haz referencia al archivo YAML ServiceExport a través de un archivo YAML ServiceImport correspondiente:

    cat <<EOF > ${WORKDIR}/cloud-armor-backendpolicy.yaml
    apiVersion: networking.gke.io/v1
    kind: GCPBackendPolicy
    metadata:
      name: cloud-armor-backendpolicy
      namespace: ingress-gateway
    spec:
      default:
        securityPolicy: edge-fw-policy
      targetRef:
        group: net.gke.io
        kind: ServiceImport
        name: asm-ingressgateway
    EOF
    
  4. Aplica la política de Cloud Armor a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
    
  5. Crea un archivo YAML personalizado que permita que el balanceador de cargas realice verificaciones de estado en el extremo de estado de Envoy (puerto 15021 en la ruta de acceso /healthz/ready) de los Pods de la puerta de enlace de entrada en ambos clústeres:

    cat <<EOF > ${WORKDIR}/ingress-gateway-healthcheck.yaml
    apiVersion: networking.gke.io/v1
    kind: HealthCheckPolicy
    metadata:
      name: ingress-gateway-healthcheck
      namespace: ingress-gateway
    spec:
      default:
        config:
          httpHealthCheck:
            port: 15021
            portSpecification: USE_FIXED_PORT
            requestPath: /healthz/ready
          type: HTTP
      targetRef:
        group: net.gke.io
        kind: ServiceImport
        name: asm-ingressgateway
    EOF
    
  6. Aplica el archivo YAML personalizado que creaste en el paso anterior a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
    
  7. Habilita el balanceo de cargas de varios clústeres para la flota y designa CLUSTER_1_NAME como el clúster de configuración:

    gcloud container fleet ingress enable \
      --config-membership=${CLUSTER_1_NAME} \
      --location=${CLUSTER_1_REGION}
    
  8. Otorga permisos de IAM para el controlador de puerta de enlace en la flota:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-multiclusteringress.iam.gserviceaccount.com" \
        --role "roles/container.admin"
    
  9. Crea el archivo YAML del balanceador de cargas a través de un recurso personalizado de puerta de enlace que haga referencia a gke-l7-global-external-managed-mc gatewayClass y a la dirección IP estática que creaste antes:

    cat <<EOF > ${WORKDIR}/frontend-gateway.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: external-http
      namespace: ingress-gateway
      annotations:
        networking.gke.io/certmap: mcg-cert-map
    spec:
      gatewayClassName: gke-l7-global-external-managed-mc
      listeners:
      - name: http # list the port only so we can redirect any incoming http requests to https
        protocol: HTTP
        port: 80
      - name: https
        protocol: HTTPS
        port: 443
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
      addresses:
      - type: NamedAddress
        value: mcg-ip
    EOF
    
  10. Aplica el archivo YAML de frontend-gateway a ambos clústeres. Solo CLUSTER_1_NAME es autoritativo, a menos que designes otro clúster de configuración como autoritativo:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-gateway.yaml
    
  11. Crea un archivo YAML HTTPRoute llamado default-httproute.yaml que indique al recurso de Gateway que envíe solicitudes a las puertas de enlace de entrada:

    cat << EOF > ${WORKDIR}/default-httproute.yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: default-httproute
      namespace: ingress-gateway
    spec:
      parentRefs:
      - name: external-http
        namespace: ingress-gateway
        sectionName: https
      rules:
      - backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: asm-ingressgateway
          port: 443
    EOF
    
  12. Aplica el archivo YAML HTTPRoute que creaste en el paso anterior a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute.yaml
    
  13. Para realizar redireccionamientos de HTTP a HTTP(S), crea un archivo HTTPRoute YAML adicional llamado default-httproute-redirect.yaml:

    cat << EOF > ${WORKDIR}/default-httproute-redirect.yaml
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: http-to-https-redirect-httproute
      namespace: ingress-gateway
    spec:
      parentRefs:
      - name: external-http
        namespace: ingress-gateway
        sectionName: http
      rules:
      - filters:
        - type: RequestRedirect
          requestRedirect:
            scheme: https
            statusCode: 301
    EOF
    
  14. Aplica el archivo YAML de redireccionamiento HTTPRoute a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/default-httproute-redirect.yaml
    
  15. Inspecciona el recurso Gateway para verificar el progreso de la implementación del balanceador de cargas:

    kubectl --context=${CLUSTER_1_NAME} describe gateway external-http -n ingress-gateway
    

    En el resultado, se muestra la información que ingresaste en esta sección.

Implementa la aplicación de ejemplo de whereami

En esta guía, se usa whereami como una aplicación de ejemplo para proporcionar comentarios directos sobre qué clústeres responden a las solicitudes. En la siguiente sección, se configuran dos implementaciones separadas de whereami en ambos clústeres: una implementación de frontend y una implementación de backend.

La implementación de frontend es la primera carga de trabajo en recibir la solicitud. Luego, llama a la implementación de backend.

Este modelo se usa para demostrar una arquitectura de aplicación de varios servicios. Los servicios frontend y backend se implementan en ambos clústeres.

  1. En Cloud Shell, crea los espacios de nombres para un frontend y un backend de Donami en ambos clústeres y habilita la inserción de espacios de nombres:

    kubectl --context=${CLUSTER_1_NAME} create ns frontend
    kubectl --context=${CLUSTER_1_NAME} label namespace frontend istio-injection=enabled
    kubectl --context=${CLUSTER_1_NAME} create ns backend
    kubectl --context=${CLUSTER_1_NAME} label namespace backend istio-injection=enabled
    kubectl --context=${CLUSTER_2_NAME} create ns frontend
    kubectl --context=${CLUSTER_2_NAME} label namespace frontend istio-injection=enabled
    kubectl --context=${CLUSTER_2_NAME} create ns backend
    kubectl --context=${CLUSTER_2_NAME} label namespace backend istio-injection=enabled
    
  2. Crea una variante de kustomize para el whereami backend:

    mkdir -p ${WORKDIR}/whereami-backend/base
    
    cat <<EOF > ${WORKDIR}/whereami-backend/base/kustomization.yaml
    resources:
      - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s
    EOF
    
    mkdir ${WORKDIR}/whereami-backend/variant
    
    cat <<EOF > ${WORKDIR}/whereami-backend/variant/cm-flag.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: whereami
    data:
      BACKEND_ENABLED: "False" # assuming you don't want a chain of backend calls
      METADATA:        "backend"
    EOF
    
    cat <<EOF > ${WORKDIR}/whereami-backend/variant/service-type.yaml
    apiVersion: "v1"
    kind: "Service"
    metadata:
      name: "whereami"
    spec:
      type: ClusterIP
    EOF
    
    cat <<EOF > ${WORKDIR}/whereami-backend/variant/kustomization.yaml
    nameSuffix: "-backend"
    namespace: backend
    labels:
    - includeSelectors: true
      includeTemplates: true
      pairs:
        app: whereami-backend
    resources:
    - ../base
    patches:
    - path: cm-flag.yaml
      target:
        kind: ConfigMap
    - path: service-type.yaml
      target:
        kind: Service
    EOF
    
  3. Aplica la variante backend de whereami a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-backend/variant
    kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-backend/variant
    
  4. Crea una variante de kustomize para el whereami frontend:

    mkdir -p ${WORKDIR}/whereami-frontend/base
    
    cat <<EOF > ${WORKDIR}/whereami-frontend/base/kustomization.yaml
    resources:
      - github.com/GoogleCloudPlatform/kubernetes-engine-samples/quickstarts/whereami/k8s
    EOF
    
    mkdir whereami-frontend/variant
    
    cat <<EOF > ${WORKDIR}/whereami-frontend/variant/cm-flag.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: whereami
    data:
      BACKEND_ENABLED: "True"
      BACKEND_SERVICE: "http://whereami-backend.backend.svc.cluster.local"
    EOF
    
    cat <<EOF > ${WORKDIR}/whereami-frontend/variant/service-type.yaml
    apiVersion: "v1"
    kind: "Service"
    metadata:
      name: "whereami"
    spec:
      type: ClusterIP
    EOF
    
    cat <<EOF > ${WORKDIR}/whereami-frontend/variant/kustomization.yaml
    nameSuffix: "-frontend"
    namespace: frontend
    labels:
    - includeSelectors: true
      includeTemplates: true
      pairs:
        app: whereami-frontend
    resources:
    - ../base
    patches:
    - path: cm-flag.yaml
      target:
        kind: ConfigMap
    - path: service-type.yaml
      target:
        kind: Service
    EOF
    
  5. Aplica la variante frontend de whereami a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
    kubectl --context=${CLUSTER_2_NAME} apply -k ${WORKDIR}/whereami-frontend/variant
    
  6. Crea un archivo YAML VirtualService para enrutar las solicitudes al frontend de whereami:

    cat << EOF > ${WORKDIR}/frontend-vs.yaml
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: whereami-vs
      namespace: frontend
    spec:
      gateways:
      - ingress-gateway/asm-ingressgateway
      hosts:
      - 'frontend.endpoints.PROJECT_ID.cloud.goog'
      http:
      - route:
        - destination:
            host: whereami-frontend
            port:
              number: 80
    EOF
    
  7. Aplica el archivo YAML de frontend-vs a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-vs.yaml
    
  8. Ahora que implementaste frontend-vs.yaml en ambos clústeres, intenta llamar al extremo público de tus clústeres:

    curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
    

    El resultado es similar a este:

    {
      "backend_result": {
        "cluster_name": "edge-to-mesh-02",
        "gce_instance_id": "8396338201253702608",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "whereami-backend.backend.svc.cluster.local",
        "metadata": "backend",
        "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-645h",
        "pod_ip": "10.124.0.199",
        "pod_name": "whereami-backend-7cbdfd788-8mmnq",
        "pod_name_emoji": "📸",
        "pod_namespace": "backend",
        "pod_service_account": "whereami-backend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T03:46:24",
        "zone": "us-east4-b"
      },
      "cluster_name": "edge-to-mesh-01",
      "gce_instance_id": "1047264075324910451",
      "gce_service_account": "e2m-mcg-01.svc.id.goog",
      "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
      "metadata": "frontend",
      "node_name": "gk3-edge-to-mesh-01-pool-2-d687e3c0-5kf2",
      "pod_ip": "10.54.1.71",
      "pod_name": "whereami-frontend-69c4c867cb-dgg8t",
      "pod_name_emoji": "🪴",
      "pod_namespace": "frontend",
      "pod_service_account": "whereami-frontend",
      "project_id": "e2m-mcg-01",
      "timestamp": "2023-12-01T03:46:24",
      "zone": "us-central1-c"
    }
    

Si ejecutas el comando curl varias veces, verás que las respuestas (tanto de frontend como de backend) provienen de diferentes regiones. En su respuesta, el balanceador de cargas proporciona el enrutamiento geográfico. Esto significa que el balanceador de cargas está enrutando las solicitudes del cliente al clúster activo más cercano, pero las solicitudes siguen llegando de forma aleatoria. Cuando las solicitudes van ocasionalmente de una región a otra, aumentan la latencia y el costo.

En la siguiente sección, implementarás el balanceo de cargas de localidad en la malla de servicios para mantener las solicitudes locales.

Habilita y prueba el balanceo de cargas de localidad para whereami

En esta sección, implementarás el balanceo de cargas por localidad en la malla de servicios para mantener las solicitudes locales. También debes realizar algunas pruebas para ver cómo whereami maneja varias situaciones de falla.

Cuando realizas una solicitud al servicio frontend de whereami, el balanceador de cargas envía la solicitud al clúster con la latencia más baja en relación con el cliente. Esto significa que los Pods de la puerta de enlace de entrada dentro de la malla balancean las solicitudes de carga a los Pods de whereami frontend en ambos clústeres. En esta sección, se abordará ese problema habilitando el balanceo de cargas por localidad dentro de la malla.

  1. En Cloud Shell, crea un archivo YAML DestinationRule que permita la conmutación por error regional del balanceo de cargas de localidad al servicio frontend:

    cat << EOF > ${WORKDIR}/frontend-dr.yaml
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: frontend
      namespace: frontend
    spec:
      host: whereami-frontend.frontend.svc.cluster.local
      trafficPolicy:
        connectionPool:
          http:
            maxRequestsPerConnection: 0
        loadBalancer:
          simple: LEAST_REQUEST
          localityLbSetting:
            enabled: true
        outlierDetection:
          consecutive5xxErrors: 1
          interval: 1s
          baseEjectionTime: 1m
    EOF
    

    La muestra de código anterior solo habilita el enrutamiento local para el servicio frontend. También necesitas una configuración adicional que controle el backend.

  2. Aplica el archivo YAML de frontend-dr a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/frontend-dr.yaml
    
  3. Crea un archivo YAML DestinationRule que habilite la conmutación por error regional del balanceo de cargas de localidad al servicio backend:

    cat << EOF > ${WORKDIR}/backend-dr.yaml
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: backend
      namespace: backend
    spec:
      host: whereami-backend.backend.svc.cluster.local
      trafficPolicy:
        connectionPool:
          http:
            maxRequestsPerConnection: 0
        loadBalancer:
          simple: LEAST_REQUEST
          localityLbSetting:
            enabled: true
        outlierDetection:
          consecutive5xxErrors: 1
          interval: 1s
          baseEjectionTime: 1m
    EOF
    
  4. Aplica el archivo YAML de backend-dr a ambos clústeres:

    kubectl --context=${CLUSTER_1_NAME} apply -f ${WORKDIR}/backend-dr.yaml
    kubectl --context=${CLUSTER_2_NAME} apply -f ${WORKDIR}/backend-dr.yaml
    

    Con ambos conjuntos de archivos YAML de DestinationRule aplicados a ambos clústeres, las solicitudes permanecen locales para el clúster al que se enrutan.

    Para probar la conmutación por error del servicio frontend, reduce la cantidad de réplicas de la puerta de enlace de entrada en el clúster principal.

    Desde la perspectiva del balanceador de cargas multirregional, esta acción simula una falla del clúster. Esto hace que el clúster falle en las verificaciones de estado del balanceador de cargas. En este ejemplo, se usa el clúster en CLUSTER_1_REGION. Solo deberías ver respuestas del clúster en CLUSTER_2_REGION.

  5. Reduce a cero la cantidad de réplicas de la puerta de enlace de entrada en el clúster principal y llama al extremo público para verificar que las solicitudes hayan conmutado por error al otro clúster:

    kubectl --context=${CLUSTER_1_NAME} -n ingress-gateway scale --replicas=0 deployment/asm-ingressgateway
    

    El resultado debe parecerse al siguiente:

    $ curl -s https://frontend.endpoints.PROJECT_ID.cloud.goog | jq
    {
      "backend_result": {
        "cluster_name": "edge-to-mesh-02",
        "gce_instance_id": "2717459599837162415",
        "gce_service_account": "e2m-mcg-01.svc.id.goog",
        "host_header": "whereami-backend.backend.svc.cluster.local",
        "metadata": "backend",
        "node_name": "gk3-edge-to-mesh-02-pool-2-675f6abf-dxs2",
        "pod_ip": "10.124.1.7",
        "pod_name": "whereami-backend-7cbdfd788-mp8zv",
        "pod_name_emoji": "🏌🏽‍♀",
        "pod_namespace": "backend",
        "pod_service_account": "whereami-backend",
        "project_id": "e2m-mcg-01",
        "timestamp": "2023-12-01T05:41:18",
        "zone": "us-east4-b"
      },
      "cluster_name": "edge-to-mesh-02",
      "gce_instance_id": "6983018919754001204",
      "gce_service_account": "e2m-mcg-01.svc.id.goog",
      "host_header": "frontend.endpoints.e2m-mcg-01.cloud.goog",
      "metadata": "frontend",
      "node_name": "gk3-edge-to-mesh-02-pool-3-d42ddfbf-qmkn",
      "pod_ip": "10.124.1.142",
      "pod_name": "whereami-frontend-69c4c867cb-xf8db",
      "pod_name_emoji": "🏴",
      "pod_namespace": "frontend",
      "pod_service_account": "whereami-frontend",
      "project_id": "e2m-mcg-01",
      "timestamp": "2023-12-01T05:41:18",
      "zone": "us-east4-b"
    }
    
  6. Para reanudar el enrutamiento de tráfico típico, restablece las réplicas de la puerta de enlace de entrada al valor original en el clúster:

    kubectl --context=${CLUSTER_1_NAME} -n ingress-gateway scale --replicas=3 deployment/asm-ingressgateway
    
  7. Simula una falla para el servicio backend reduciendo la cantidad de réplicas en la región principal a 0:

    kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=0 deployment/whereami-backend
    

    Verifica que las respuestas del servicio frontend provengan de la región principal us-central1 a través del balanceador de cargas y que las respuestas del servicio backend provengan de la región secundaria us-east4.

    El resultado también debe incluir una respuesta para el servicio frontend de la región principal (us-central1) y una respuesta para el servicio backend de la región secundaria (us-east4), como se esperaba.

  8. Restablece las réplicas del servicio de backend al valor original para reanudar el enrutamiento de tráfico típico:

    kubectl --context=${CLUSTER_1_NAME} -n backend scale --replicas=3 deployment/whereami-backend
    

Ahora tienes un balanceador de cargas de HTTP(S) global que funciona como frontend en tu aplicación multirregional alojada en la malla de servicios.

Realiza una limpieza

Para evitar que se apliquen cargos a tu Google Cloud cuenta por los recursos usados en esta implementación, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

Borra el proyecto

  1. En la Google Cloud consola, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Borra los recursos individuales

Si deseas conservar el proyecto Google Cloud que usaste en esta implementación, borra los recursos individuales:

  1. En Cloud Shell, borra los recursos de HTTPRoute:

    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute-redirect.yaml
    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/default-httproute.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/default-httproute.yaml
    
  2. Borra los recursos de la puerta de enlace de GKE:

    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/frontend-gateway.yaml
    
  3. Borra las políticas:

    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/ingress-gateway-healthcheck.yaml
    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/cloud-armor-backendpolicy.yaml
    
  4. Borra las exportaciones de servicio:

    kubectl --context=${CLUSTER_1_NAME} delete -f ${WORKDIR}/svc_export.yaml
    kubectl --context=${CLUSTER_2_NAME} delete -f ${WORKDIR}/svc_export.yaml
    
  5. Borra los recursos de Cloud Armor:

    gcloud --project=PROJECT_ID compute security-policies rules delete 1000 --security-policy edge-fw-policy --quiet
    gcloud --project=PROJECT_ID compute security-policies delete edge-fw-policy --quiet
    
  6. Borra los recursos de Administrador de certificados:

    gcloud --project=PROJECT_ID certificate-manager maps entries delete mcg-cert-map-entry --map="mcg-cert-map" --quiet
    gcloud --project=PROJECT_ID certificate-manager maps delete mcg-cert-map --quiet
    gcloud --project=PROJECT_ID certificate-manager certificates delete mcg-cert --quiet
    
  7. Borra la entrada de DNS de Endpoints:

    gcloud --project=PROJECT_ID endpoints services delete "frontend.endpoints.PROJECT_ID.cloud.goog" --quiet
    
  8. Borra la dirección IP estática:

    gcloud --project=PROJECT_ID compute addresses delete mcg-ip --global --quiet
    
  9. Borra los clústeres de GKE Autopilot. Este paso tarda varios minutos.

    gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_1_NAME} --region ${CLUSTER_1_REGION} --quiet
    gcloud --project=PROJECT_ID container clusters delete ${CLUSTER_2_NAME} --region ${CLUSTER_2_REGION} --quiet
    

¿Qué sigue?

Colaboradores

Autores:

Otros colaboradores: