Configura el balanceador de cargas de aplicaciones clásico para Cloud Service Mesh
Descripción general
Este documento es para ti si eres un usuario existente de Cloud Service Mesh que tiene el plano de control administrado de Istiod y deseas configurar el balanceador de cargas de aplicaciones clásico como una puerta de enlace de entrada. El balanceador de cargas de aplicaciones clásico también se conoce como balanceador de cargas de aplicaciones externo clásico.
No uses este documento si eres un usuario nuevo de Cloud Service Mesh. Los usuarios nuevos se configuran automáticamente con el plano de control administrado de Cloud Service Mesh. No puedes usar la configuración que se describe en este documento con el plano de control administrado de Cloud Service Mesh.
Cloud Load Balancing proporciona muchas capacidades de borde administradas por la nube, como el balanceo de cargas global de difusión a cualquier dirección, los certificados administrados por Google, Identity and Access Management, Cloud Next Generation Firewall y Sistema de detección de intrusiones de Cloud. Cloud Service Mesh puede integrar sin problemas estas capacidades de borde en el siguiente modelo de entrada de malla. La puerta de enlace de Cloud Service Mesh proporciona una forma unificada de configurar la puerta de enlace de entrada de Cloud Service Mesh con Cloud Load Balancing de forma simultánea a través de la API de puerta de enlace de Kubernetes.
En comparación con nuestra guía del usuario anterior, Del perímetro a la malla: Exposición de aplicaciones de la malla de servicios a través de Ingress de GKE, con la puerta de enlace de la nube de la malla de servicios, este modelo ahora se puede implementar a través de un recurso de puerta de enlace de Kubernetes, lo que simplifica el proceso de implementación conjunta del balanceo de cargas alojado en la nube y en el clúster.
Limitaciones de la vista previa
En la versión preliminar de esta función, se aplican las siguientes limitaciones:
- No se admiten las puertas de enlace de varios clústeres.
- Los clústeres de Autopilot no son compatibles.
- Solo se admite el balanceador de cargas de aplicaciones clásico. No se admiten el balanceador de cargas de aplicaciones externo global (a veces llamado balanceador de cargas avanzado) ni el balanceador de cargas de aplicaciones interno.
- El tráfico entre el balanceador de cargas de aplicaciones clásico y la puerta de enlace de entrada de Cloud Service Mesh se encripta con TLS. Sin embargo, el balanceador de cargas de aplicaciones clásico no verificará el certificado proporcionado por la puerta de enlace de entrada de Cloud Service Mesh. Esta limitación se aplica a todos los usuarios del balanceador de cargas de Google Cloud HTTP(S).
- Si se borran los objetos
GatewayClasses
de Cloud Service Mesh de un clúster, no se volverán a instalar automáticamente. Sin embargo, esto no afectará la usabilidad de la función. - La lógica de coincidencia de rutas no sigue las especificaciones de la API de Gateway y, en cambio, coincide en el orden de
HTTPRoute
. Esto cambiará en versiones futuras para seguir las especificaciones de la API de Gateway.
Requisitos
- Managed Cloud Service Mesh instalado en un clúster de Google Kubernetes Engine (GKE) que ejecuta la versión 1.24 o posterior No se admiten otros clústeres de GKE Enterprise.
- Solo la versión v1beta1 de la API de Gateway de Kubernetes.
Requisitos previos
Habilita las siguientes APIs en tu proyecto:
- compute.googleapis.com
- container.googleapis.com
- certificatemanager.googleapis.com
- serviceusage.googleapis.com
gcloud services enable \ compute.googleapis.com \ container.googleapis.com \ certificatemanager.googleapis.com \ serviceusage.googleapis.com
Implementa una puerta de enlace de Cloud de malla de servicios para una malla de un solo clúster
En esta sección, se muestra cómo implementar un recurso de puerta de enlace de Kubernetes que implementa un balanceador de cargas de aplicaciones clásico y una puerta de enlace de entrada de Cloud Service Mesh.
Habilita la API de Gateway con Cloud Service Mesh administrada
Habilita la API de Gateway en tu clúster. El clúster de GKE debe estar en la versión 1.24 o posterior.
Instala Cloud Service Mesh administrado con
rapid
oregular
como su canal de versiones.
Implementa el recurso Gateway
Cuando se implementa la puerta de enlace de Cloud malla de servicios, los recursos de la puerta de enlace de Kubernetes se usan para implementar tanto Cloud Load Balancing como la puerta de enlace de entrada de Cloud Service Mesh en un solo paso. Ten en cuenta que los recursos de puerta de enlace de Kubernetes son diferentes de los recursos de puerta de enlace de Istio.
Para obtener más información sobre las diferencias, consulta Puertas de enlace de Kubernetes y puertas de enlace de Istio. Cada puerta de enlace de Kubernetes tiene un GatewayClass que indica su tipo y sus capacidades inherentes. La puerta de enlace de Cloud malla de servicios tiene un GatewayClass que tiene la capacidad de implementar tanto Cloud Load Balancing como la puerta de enlace de entrada de Cloud Service Mesh.
Guarda el siguiente manifiesto de GatewayClass en un archivo llamado
l7-gateway-class.yaml
:apiVersion: gateway.networking.k8s.io/v1beta1 kind: GatewayClass metadata: name: asm-l7-gxlb spec: controllerName: mesh.cloud.google.com/gateway
Implementa la GatewayClass en tu clúster:
kubectl apply -f l7-gateway-class.yaml
Verifica que la GatewayClass esté presente después de la instalación:
kubectl get gatewayclasses.gateway.networking.k8s.io
El resultado es similar al siguiente:
NAME CONTROLLER asm-l7-gxlb mesh.cloud.google.com/gateway gke-l7-rilb networking.gke.io/gateway gke-l7-gxlb networking.gke.io/gateway
Es posible que la implementación de todos los recursos tarde unos minutos. Si no ves el resultado esperado, verifica que hayas cumplido correctamente con los requisitos previos.
También verás la siguiente GatewayClass:
gke-l7-gxlb networking.gke.io/gateway
Se usa para implementar el balanceador de cargas de aplicaciones clásico subyacente de Google Cloud.
Crea un espacio de nombres dedicado para tu puerta de enlace de Cloud de malla de servicios:
kubectl create namespace istio-ingress
Guarda el siguiente manifiesto de Gateway en un archivo llamado
gateway.yaml
:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: servicemesh-cloud-gw namespace: istio-ingress spec: gatewayClassName: asm-l7-gxlb listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: All
Implementa la puerta de enlace en tu clúster en el espacio de nombres istio-ingress:
kubectl apply -f gateway.yaml
Verifica que se hayan creado los objetos de la API de Gateway de Kubernetes:
kubectl get gateways.gateway.networking.k8s.io -n istio-ingress
El resultado es similar al siguiente:
NAME CLASS ADDRESS READY AGE asm-gw-gke-servicemesh-cloud-gw gke-l7-gxlb 34.111.114.64 True 9m40s asm-gw-istio-servicemesh-cloud-gw istio 9m44s servicemesh-cloud-gw asm-l7-gxlb 9m44s
Cuando se implemente este objeto de la API de Gateway de Kubernetes, sucederán los siguientes eventos:
- Se implementó y configuró un balanceador de cargas de HTTP(S) externo. Puede tardar unos minutos en aparecer, pero, cuando lo haga, la puerta de enlace indicará la dirección IP y se anotará con los nombres de los recursos del balanceador de cargas de Compute Engine que se crearon.
- Se crea una Deployment de la puerta de enlace de entrada de Cloud Service Mesh en el espacio de nombres istio-ingress. Esto crea las instancias del proxy de Envoy que recibirán tráfico del balanceador de cargas.
- El balanceador de cargas encriptará y enrutará todo el tráfico a la puerta de enlace de entrada de Cloud Service Mesh.
Ahora tienes toda la infraestructura necesaria para aceptar tráfico de Internet en tu malla. Ten en cuenta que esta es la implementación de Gateway más simple posible. En las siguientes secciones, agregarás políticas y capacidades adicionales que lo prepararán para la producción.
Implementación de la app y el enrutamiento
Para demostrar por completo las capacidades, implementarás una aplicación en Cloud Service Mesh y recibirás tráfico de Internet a través de tu puerta de enlace a modo de ejemplo.
Etiqueta el espacio de nombres
default
para habilitar la inserción del sidecar.kubectl label namespace default istio-injection=enabled istio.io/rev- --overwrite
Guarda el siguiente manifiesto de Gateway en un archivo llamado
whereami.yaml
:apiVersion: apps/v1 kind: Deployment metadata: name: whereami-v1 spec: replicas: 2 selector: matchLabels: app: whereami-v1 template: metadata: labels: app: whereami-v1 spec: containers: - name: whereami image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1 ports: - containerPort: 8080 env: - name: METADATA value: "whereami-v1" --- apiVersion: v1 kind: Service metadata: name: whereami-v1 spec: selector: app: whereami-v1 ports: - port: 8080 targetPort: 8080 --- apiVersion: apps/v1 kind: Deployment metadata: name: whereami-v2 spec: replicas: 2 selector: matchLabels: app: whereami-v2 template: metadata: labels: app: whereami-v2 spec: containers: - name: whereami image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1 ports: - containerPort: 8080 env: - name: METADATA value: "whereami-v2" --- apiVersion: v1 kind: Service metadata: name: whereami-v2 spec: selector: app: whereami-v2 ports: - port: 8080 targetPort: 8080
Este manifiesto crea
Service/whereami-v1
,Service/whereami-v2
,Deployment/whereami-v1
yDeployment/whereami-v2
para whereami, una aplicación simple que genera JSON para indicar su identidad y ubicación. Implementarás dos versiones diferentes de ella.Crea los servicios y las implementaciones:
kubectl apply -f whereami.yaml
Una vez que esté en funcionamiento, tendrás cuatro Pods de whereami ejecutándose en tu clúster.
Verifica que los cuatro Pods se estén ejecutando:
kubectl get pods
El resultado es similar al siguiente:
whereami-v1-7c76d89d55-qg6vs 2/2 Running 0 28s whereami-v1-7c76d89d55-vx9nm 2/2 Running 0 28s whereami-v2-67f6b9c987-p9kqm 2/2 Running 0 27s whereami-v2-67f6b9c987-qhj76 2/2 Running 0 27s
Guarda el siguiente manifiesto de HTTPRoute en un archivo llamado
http-route.yaml
:kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: where-route spec: parentRefs: - kind: Gateway name: servicemesh-cloud-gw namespace: istio-ingress hostnames: - "where.example.com" rules: - matches: - headers: - name: version value: v2 backendRefs: - name: whereami-v2 port: 8080 - backendRefs: - name: whereami-v1 port: 8080
Implementa
http-route.yaml
en tu clúster:kubectl apply -f http-route.yaml
Esta HTTPRoute hace referencia a
servicemesh-cloud-gw
, lo que significa que configurará la puerta de enlace de Cloud Service malla de servicios para que configure la puerta de enlace de entrada subyacente de Cloud Service Mesh con estas reglas de enrutamiento. HTTPRoute realiza la misma función que VirtualService de Istio, pero usa la API de Gateway de Kubernetes para hacerlo. Debido a que la API de Gateway es una especificación de OSS con muchas implementaciones subyacentes, es la mejor API adecuada para definir el enrutamiento en una combinación de diferentes balanceadores de cargas (como los proxies y los balanceadores de cargas de Cloud Service Mesh).Recupera la dirección IP de la puerta de enlace para que puedas enviar tráfico a tu aplicación:
VIP=$(kubectl get gateways.gateway.networking.k8s.io asm-gw-gke-servicemesh-cloud-gw -o=jsonpath="{.status.addresses[0].value}" -n istio-ingress)
El resultado es una dirección IP.
echo $VIP 34.111.61.135
Envía tráfico a la dirección IP de la puerta de enlace para validar que esta configuración funcione correctamente. Envía una solicitud con el encabezado
version: v2
y otra sin él para determinar que el enrutamiento se realiza correctamente en las dos versiones de la aplicación.curl ${VIP} -H "host: where.example.com" { "cluster_name": "gke1", "host_header": "where.example.com", "metadata": "whereami-v1", "node_name": "gke-gke1-default-pool-9b3b5b18-hw5z.c.church-243723.internal", "pod_name": "whereami-v1-67d9c5d48b-zhr4l", "pod_name_emoji": "⚒", "project_id": "church-243723", "timestamp": "2021-02-08T18:55:01", "zone": "us-central1-a" } curl ${VIP} -H "host: where.example.com" -H "version: v2" { "cluster_name": "gke1", "host_header": "where.example.com", "metadata": "whereami-v2", "node_name": "gke-gke1-default-pool-9b3b5b18-hw5z.c.church-243723.internal", "pod_name": "whereami-v2-67d9c5d48b-zhr4l", "pod_name_emoji": "⚒", "project_id": "church-243723", "timestamp": "2021-02-08T18:55:01", "zone": "us-central1-a" }
Implementación de la puerta de enlace de producción
En la sección anterior, se mostró un ejemplo muy simple de una puerta de enlace de nube de malla de servicios. Los siguientes pasos se basan en el ejemplo simple para mostrar una configuración lista para la producción que demuestra las ventajas de delegar parte de la funcionalidad de enrutamiento de entrada al balanceador de cargas.
En el siguiente ejemplo, tomarás el servicemesh-cloud-gw
de la sección anterior y agregarás las siguientes capacidades para crear una puerta de enlace más segura y fácil de administrar:
- Implementa la puerta de enlace con una dirección IP estática que se conservará incluso si cambia la infraestructura subyacente.
- Convierte la puerta de enlace para que reciba tráfico HTTPS con un certificado autofirmado.
Crea una dirección IP externa estática. Una IP estática es útil porque la infraestructura subyacente puede cambiar en el futuro, pero la dirección IP se puede conservar.
gcloud compute addresses create whereami-ip \ --global \ --project PROJECT_ID
Crea un certificado autofirmado para el dominio
where-example-com
:openssl genrsa -out key.pem 2048 cat <<EOF >ca.conf [req] default_bits = 2048 req_extensions = extension_requirements distinguished_name = dn_requirements prompt = no [extension_requirements] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @sans_list [dn_requirements] 0.organizationName = example commonName = where.example.com [sans_list] DNS.1 = where.example.com EOF
openssl req -new -key key.pem \ -out csr.pem \ -config ca.conf
openssl x509 -req \ -signkey key.pem \ -in csr.pem \ -out cert.pem \ -extfile ca.conf \ -extensions extension_requirements \ -days 365
gcloud compute ssl-certificates create where-example-com \ --certificate=cert.pem \ --private-key=key.pem \ --global \ --project PROJECT_ID
Existen muchas formas de generar certificados TLS. Se pueden generar de forma manual en la línea de comandos, mediante certificados administrados por Google o de forma interna en el sistema de infraestructura de clave pública (PKI) de tu empresa. En este ejemplo, generarás manualmente un certificado autofirmado. Si bien los certificados autofirmados no se suelen usar para servicios públicos, demuestran estos conceptos con mayor facilidad.
Para obtener más información sobre cómo crear un certificado autofirmado a través de un Secret de Kubernetes, consulta Protege una puerta de enlace.
Actualiza
gateway.yaml
con el siguiente manifiesto:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: servicemesh-cloud-gw namespace: istio-ingress spec: gatewayClassName: asm-l7-gxlb listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: All - name: https protocol: HTTPS port: 443 allowedRoutes: namespaces: from: All tls: mode: Terminate options: networking.gke.io/pre-shared-certs: where-example-com addresses: - type: NamedAddress value: whereami-ip
Vuelve a implementar la puerta de enlace en tu clúster:
kubectl apply -f gateway.yaml
Obtén la dirección IP de la IP estática:
VIP=$(gcloud compute addresses describe whereami-ip --global --format="value(address)")
Usa
curl
para acceder al dominio de la puerta de enlace. Debido a que el DNS no está configurado para este dominio, usa la opción --resolve para indicarle a curl que resuelva el nombre de dominio a la dirección IP de la puerta de enlace:curl https://where.example.com --resolve where.example.com:443:${VIP} --cacert cert.pem -v
Una vez que se completa, el resultado es similar al siguiente:
... * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 * ALPN, server accepted to use h2 * Server certificate: * subject: O=example; CN=where.example.com * start date: Apr 19 15:54:50 2021 GMT * expire date: Apr 19 15:54:50 2022 GMT * common name: where.example.com (matched) * issuer: O=example; CN=where.example.com * SSL certificate verify ok. ... { "cluster_name": "gke1", "host_header": "where.example.com", "metadata": "where-v1", "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal", "pod_name": "where-v1-84b47c7f58-tj5mn", "pod_name_emoji": "😍", "project_id": "agmsb-k8s", "timestamp": "2021-04-19T16:30:08", "zone": "us-west1-a" }
El resultado detallado incluye un protocolo de enlace TLS exitoso seguido de una respuesta de la aplicación, como el siguiente resultado. Esto demuestra que TLS se cierra en la puerta de enlace correctamente y que la aplicación responde al cliente de forma segura.
Implementaste correctamente la siguiente arquitectura:
El objeto servicemesh-cloud-gw
y su GatewayClass asm-l7-gxlb
abstrajeron algunos componentes internos de la infraestructura para simplificar la experiencia del usuario.
Cloud Load Balancing finaliza el tráfico de TLS con un certificado interno y también realiza verificaciones de estado en la capa de proxy de la puerta de enlace de entrada de Cloud Service Mesh. El proxy whereami-route
implementado en App & Routing Deployment configura los proxies de la puerta de enlace de entrada de Cloud Service Mesh para enrutar el tráfico al servicio correcto alojado en la malla.
En el siguiente ejemplo, tomarás el servicemesh-cloud-gw
de la sección anterior y agregarás las siguientes capacidades para crear una puerta de enlace más segura y fácil de administrar:
- Implementa la puerta de enlace con una dirección IP estática que se conservará incluso si cambia la infraestructura subyacente.
- Convierte la puerta de enlace para que reciba tráfico HTTPS con un certificado autofirmado.
Crea una dirección IP externa estática. Una IP estática es útil porque la infraestructura subyacente puede cambiar en el futuro, pero la dirección IP se puede conservar.
gcloud compute addresses create whereami-ip \ --global \ --project PROJECT_ID
Crea un certificado autofirmado para el dominio
where-example-com
:openssl genrsa -out key.pem 2048 cat <<EOF >ca.conf [req] default_bits = 2048 req_extensions = extension_requirements distinguished_name = dn_requirements prompt = no [extension_requirements] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @sans_list [dn_requirements] 0.organizationName = example commonName = where.example.com [sans_list] DNS.1 = where.example.com EOF
openssl req -new -key key.pem \ -out csr.pem \ -config ca.conf
openssl x509 -req \ -signkey key.pem \ -in csr.pem \ -out cert.pem \ -extfile ca.conf \ -extensions extension_requirements \ -days 365
gcloud compute ssl-certificates create where-example-com \ --certificate=cert.pem \ --private-key=key.pem \ --global \ --project PROJECT_ID
Existen muchas formas de generar certificados TLS. Se pueden generar de forma manual en la línea de comandos, mediante certificados administrados por Google o de forma interna en el sistema de infraestructura de clave pública (PKI) de tu empresa. En este ejemplo, generarás manualmente un certificado autofirmado. Si bien los certificados autofirmados no se suelen usar para servicios públicos, demuestran estos conceptos con mayor facilidad.
Para obtener más información sobre cómo crear un certificado autofirmado a través de un Secret de Kubernetes, consulta Protege una puerta de enlace.
Actualiza
gateway.yaml
con el siguiente manifiesto:kind: Gateway apiVersion: gateway.networking.k8s.io/v1beta1 metadata: name: servicemesh-cloud-gw namespace: istio-ingress spec: gatewayClassName: asm-l7-gxlb listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: All - name: https protocol: HTTPS port: 443 allowedRoutes: namespaces: from: All tls: mode: Terminate options: networking.gke.io/pre-shared-certs: where-example-com addresses: - type: NamedAddress value: whereami-ip
Vuelve a implementar la puerta de enlace en tu clúster:
kubectl apply -f gateway.yaml
Obtén la dirección IP de la IP estática:
VIP=$(gcloud compute addresses describe whereami-ip --global --format="value(address)")
Usa
curl
para acceder al dominio de la puerta de enlace. Debido a que el DNS no está configurado para este dominio, usa la opción --resolve para indicarle a curl que resuelva el nombre de dominio a la dirección IP de la puerta de enlace:curl https://where.example.com --resolve where.example.com:443:${VIP} --cacert cert.pem -v
Una vez que se completa, el resultado es similar al siguiente:
... * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305 * ALPN, server accepted to use h2 * Server certificate: * subject: O=example; CN=where.example.com * start date: Apr 19 15:54:50 2021 GMT * expire date: Apr 19 15:54:50 2022 GMT * common name: where.example.com (matched) * issuer: O=example; CN=where.example.com * SSL certificate verify ok. ... { "cluster_name": "gke1", "host_header": "where.example.com", "metadata": "where-v1", "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal", "pod_name": "where-v1-84b47c7f58-tj5mn", "pod_name_emoji": "😍", "project_id": "agmsb-k8s", "timestamp": "2021-04-19T16:30:08", "zone": "us-west1-a" }
El resultado detallado incluye un protocolo de enlace TLS exitoso seguido de una respuesta de la aplicación, como el siguiente resultado. Esto demuestra que TLS se cierra en la puerta de enlace correctamente y que la aplicación responde al cliente de forma segura.
Implementaste correctamente la siguiente arquitectura:
El objeto servicemesh-cloud-gw
y su GatewayClass asm-l7-gxlb
abstrajeron algunos componentes internos de la infraestructura para simplificar la experiencia del usuario.
Cloud Load Balancing finaliza el tráfico de TLS con un certificado interno y también realiza verificaciones de estado en la capa de proxy de la puerta de enlace de entrada de Cloud Service Mesh. El proxy whereami-route
implementado en App & Routing Deployment configura los proxies de la puerta de enlace de entrada de Cloud Service Mesh para enrutar el tráfico al servicio correcto alojado en la malla.
¿Qué sigue?
- Obtén más información sobre la implementación de Google Kubernetes Engine (GKE) de la API de Gateway de Kubernetes.
- Consulta cómo habilitar funciones opcionales administradas de Cloud Service Mesh.