Como implantar gateways

Nesta página, descrevemos como implantar recursos de gateway do Kubernetes no Google Kubernetes Engine (GKE). Explicamos como implantar um gateway particular e um gateway voltado para a Internet para expor aplicativos. Também demonstramos alguns dos conceitos do modelo de recursos da API Gateway.

Para ver como os gateways são implantados no balanceamento de carga de vários clusters, consulte Como implantar gateways de vários clusters. Para entender as diferenças entre GatewayClasses, consulte Recursos do GatewayClass.

Requisitos do GKE Gateway Controller

  • GKE versão 1.20 ou posterior
  • A API Gateway é compatível apenas com clusters nativo de VPC (IP de alias).
  • Se você estiver usando os recursos GatewayClasses internos, será necessário ativar uma sub-rede somente proxy.
  • Os gateways de vários clusters e de cluster único são compatíveis com todas as regiões do Google Cloud.

Visualizar limitações e problemas conhecidos

Embora o suporte do GKE à API Gateway esteja em prévia, as seguintes limitações se aplicam:

  • Os clusters do Autopilot não são suportados.
  • O GatewayClasses do GKE é compatível com diferentes recursos, dependendo do balanceador de carga subjacente. Consulte os recursos do GatewayClass para saber mais sobre os diferentes recursos compatíveis com os GatewayClasses disponíveis.
  • Os clusters do GKE que têm recursos Gateway ou Istio do ASM entrarão em conflito com os recursos do gateway do Kubernetes ao usar o kubectl. Talvez o kubectl get gateway não retorne os recursos do gateway do Istio ou do ASM conforme esperado. Para evitar conflitos de recursos da linha de comando com os gateways do Istio, consulte Gateways do Kubernetes e gateways do Istio
  • Os recursos do balanceador de carga do Google Cloud criados por gateways não são visíveis na IU do console do Google Cloud.
  • A visualização dos recursos de gateway, HTTPRoute e ServiceExport na IU do GKE não é compatível.
  • O uso do GKE Gateway Controller com o Kubernetes no Compute Engine (Kubernetes autogerenciado) não é compatível.
  • Não é possível encerrar o tráfego TLS usando credenciais armazenadas em secrets do Kubernetes. No entanto, é possível referenciar recursos de certificado SSL do Google Cloud para encerrar o TLS.
  • Não é possível configurar políticas de SSL ou de redirecionamentos HTTPS usando o recurso FrontendConfig.
  • O recurso BackendConfig não é compatível com as GatewayClasses de vários clusters (-mc). No entanto, ele é compatível com gateways de cluster único.
  • Não é possível gerar automaticamente certificados SSL gerenciados pelo Google. No entanto, um certificado SSL gerenciado pelo Google pode ser criado e consultado manualmente usando a opção networking.gke.io/pre-shared-certs do TLS.
  • As configurações de capacidade de tráfego do serviço max-rate-per-endpoint, max-rate e capacity-scaler não são compatíveis.

Instale os CRDs da API Gateway

Antes de usar os recursos do Gateway no GKE, instale as definições de recursos personalizados da API Gateway (CRDs, na sigla em inglês) no cluster. Instale os CRDs v1alpha1 e v1alpha2 na seguinte ordem:

  1. Execute o seguinte comando no cluster do GKE em que você quer implantar os recursos de gateway:

    kubectl apply -k "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.4.3"
    

    Esse comando instala os CRDs v1alpha2.

    A saída será assim:

    customresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/gateways.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/httproutes.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/referencepolicies.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/tcproutes.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/tlsroutes.gateway.networking.k8s.io configured
    customresourcedefinition.apiextensions.k8s.io/udproutes.gateway.networking.k8s.io configured
    
  2. Execute o seguinte comando no cluster do GKE em que você quer implantar os recursos de gateway:

    kubectl apply -k "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.3.0"
    

    Esse comando instala os CRDs v1alpha1.

    A saída será assim:

    customresourcedefinition.apiextensions.k8s.io/backendpolicies.networking.x-k8s.io created
    customresourcedefinition.apiextensions.k8s.io/gatewayclasses.networking.x-k8s.io created
    customresourcedefinition.apiextensions.k8s.io/gateways.networking.x-k8s.io created
    customresourcedefinition.apiextensions.k8s.io/httproutes.networking.x-k8s.io created
    customresourcedefinition.apiextensions.k8s.io/tcproutes.networking.x-k8s.io created
    customresourcedefinition.apiextensions.k8s.io/tlsroutes.networking.x-k8s.io created
    customresourcedefinition.apiextensions.k8s.io/udproutes.networking.x-k8s.io created
    

GatewayClasses do GKE

Depois que um cluster do GKE detecta a existência de CRDs da API Gateway, as seguintes GatewayClasses do GKE são instaladas automaticamente pelo GKE Gateway Controller. Pode levar alguns minutos para que o controlador reconheça os CRDs e instale o GatewayClasses.

  1. Verifique se o GatewayClasses está disponível com o seguinte comando:

    kubectl get gatewayclass
    

    Esta saída confirma que as GatewayClasses do GKE estão prontas para uso no cluster:

    NAME          CONTROLLER
    gke-l7-rilb   networking.gke.io/gateway
    gke-l7-gxlb   networking.gke.io/gateway
    

    Para entender os recursos de cada GatewayClass do GKE, consulte Recursos do GatewayClass.

Como configurar uma sub-rede somente proxy

Se você ainda não tiver feito isso, configure uma sub-rede somente proxy para cada região em que os gateways internos estão sendo implantados. Essa sub-rede é usada para fornecer endereços IP internos aos proxies do balanceador de carga.

É necessário criar uma sub-rede somente proxy antes de gerar gateways que gerenciam balanceadores de carga HTTP(S) internos. Cada região de uma VPC em que você usa balanceadores de carga HTTP(S) internos precisa ter uma sub-rede somente proxy.

O comando gcloud compute networks subnets create cria uma sub-rede somente proxy.

gcloud compute networks subnets create SUBNET_NAME \
    --purpose=REGIONAL_MANAGED_PROXY \
    --role=ACTIVE \
    --region=REGION \
    --network=VPC_NETWORK_NAME \
    --range=CIDR_RANGE

Substitua:

  • SUBNET_NAME: o nome da sub-rede somente proxy.
  • REGION: a região da sub-rede somente proxy.
  • VPC_NETWORK_NAME: o nome da rede VPC que contém a sub-rede.
  • CIDR_RANGE: o intervalo de endereços IP principal da sub-rede. Use uma máscara de sub-rede de até /26 de comprimento para que ao menos 64 endereços IP estejam disponíveis para os proxies na região. A máscara de sub-rede recomendada é /23.

Se o evento a seguir aparecer no gateway interno, não existe uma sub-rede apenas proxy nessa região. Para resolver esse problema, implante uma sub-rede apenas de proxy.

generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.

Como implantar um gateway interno

Um recurso de gateway representa um plano de dados que roteia o tráfego no Kubernetes. Um Gateway pode representar vários tipos diferentes de balanceamento de carga e roteamento, dependendo do GatewayClass que o deriva. Para saber mais sobre o recurso Gateway, consulte a descrição do recurso de gateway ou a especificação da API.

Nesse caso, o administrador do cluster do GKE quer criar um gateway que possa ser usado por equipes diferentes para expor aplicativos internamente. O administrador implanta o gateway e as equipes de aplicativo implantam as rotas de maneira independente e as anexam a esse gateway.

  1. Salve o seguinte manifesto de gateway em um arquivo chamado gateway.yaml:

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: internal-http
    spec:
      gatewayClassName: gke-l7-rilb
      listeners:
      - name: http
        protocol: HTTP
        port: 80
    

    Explicação dos campos:

    • gatewayClassName: gke-l7-rilb especifica o GatewayClass que deriva este gateway. gke-l7-rilb corresponde ao balanceador de carga HTTP(S) interno regional.
    • port: 80 especifica que o gateway expõe apenas a porta 80 para detectar o tráfego HTTP.
  2. Para implantar o gateway no cluster:

    kubectl apply -f gateway.yaml
    
  3. Verifique se o gateway foi implantado corretamente. Pode levar alguns minutos para implantar todos os recursos.

    kubectl describe gateways.gateway.networking.k8s.io internal-http
    

    A saída será assim:

    Name:         internal-http
    Namespace:    default
    ...
    Status:
      Addresses:
        Type:   IPAddress
        Value:  192.168.1.14
      Conditions:
        Last Transition Time:  1970-01-01T00:00:00Z
        Message:               Waiting for controller
        Reason:                NotReconciled
        Status:                False
        Type:                  Scheduled
    Events:
      Type    Reason  Age                From                       Message
      ----    ------  ----               ----                       -------
      Normal  ADD     92s                networking.gke.io/gateway  test/internal-http
      Normal  UPDATE  45s (x3 over 91s)  networking.gke.io/gateway  test/internal-http
      Normal  SYNC    45s                networking.gke.io/gateway  SYNC on test/internal-http was a success
    

    Neste ponto, um gateway implantado no cluster já provisionou um balanceador de carga e um endereço IP. No entanto, o gateway não tem rotas. Portanto, ele ainda não sabe como enviar tráfego para os back-ends. Sem as rotas, todo o tráfego vai para um back-end padrão, que retorna um HTTP 404. Em seguida, implante um aplicativo e rotas que informam ao gateway como acessar os back-ends do aplicativo.

Como implantar os aplicativos de demonstração

As equipes de aplicativos podem implantar os próprios aplicativos e rotas independentemente da implantação dos gateways. Em alguns casos, a equipe de aplicativos pode querer ser proprietária do gateway e implantá-lo por conta própria como um recurso dedicado aos aplicativos deles. Consulte Vinculação de rotas para ver diferentes modelos de propriedade de gateways e rotas. No entanto, neste exemplo, a equipe da loja implanta o aplicativo e um HTTPRoute associado para expor o aplicativo dela pelo gateway internal-http criado na seção anterior.

O recurso HTTPRoute tem muitos campos configuráveis para correspondência de tráfego. Para uma explicação dos campos do HTTPRoute, consulte a especificação da API.

  1. Para implantar o aplicativo da loja (store-v1, store-v2 e store-german) no cluster:

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/store.yaml
    

    Isso cria três implantações e três serviços, chamados store-v1, store-v2 e store-german.

  2. Para validar a implantação do aplicativo:

    kubectl get pod
    

    O resultado será semelhante ao seguinte depois que o aplicativo estiver em execução:

    NAME                        READY   STATUS    RESTARTS   AGE
    store-german-66dcb75977-5gr2n   1/1     Running   0          38s
    store-v1-65b47557df-jkjbm       1/1     Running   0          14m
    store-v2-6856f59f7f-sq889       1/1     Running   0          14m
    
  3. Para confirmar que os serviços também foram implantados:

    kubectl get service
    

    A saída será semelhante à seguinte, e mostrará um serviço para cada implantação de loja:

    NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    store-german   ClusterIP   10.48.3.183   <none>        8080/TCP   4s
    store-v1       ClusterIP   10.48.2.224   <none>        8080/TCP   5s
    store-v2       ClusterIP   10.48.4.48    <none>        8080/TCP   5s
    

Balanceamento de carga nativo de contêiner

O GKE Gateway Controller usa o balanceamento de carga nativo do contêiner por padrão. Isso significa que o tráfego com carga balanceada é enviado diretamente aos endereços IP do pod. O balanceador de carga tem visibilidade direta dos endereços IP do pod para que o tráfego não passe pelo balanceamento de carga do serviço do Kubernetes. Isso leva a um tráfego mais eficiente, estável e compreensível. Os GatewayClasses gke-l7-* não são compatíveis com o balanceamento de carga baseado em grupo de instâncias.

Os gateways do GKE não exigem nenhuma anotação especial especificada pelo usuário nos serviços. Qualquer serviço referenciado por um HTTPRoute é anotado automaticamente pelo GKE Gateway Controller com referências aos NEGs do serviço, como no exemplo a seguir:

Name:              store-v1
Namespace:         default
Annotations:       cloud.google.com/neg: {"exposed_ports":{"8080":{}}}
                   cloud.google.com/neg-status: {"network_endpoint_groups":{"8080":"k8s1-cb368ccb-default-foo-v1-8080-f376ae25"},"zones":["us-central1-a"]}
...

Como implantar o HTTPRoute

Os recursos de rota definem regras específicas do protocolo que mapeiam o tráfego de um gateway para os back-ends do Kubernetes. O recurso HTTPRoute faz a correspondência e filtragem de tráfego HTTP e HTTPS e é compatível com todas os GatewayClasses gke-l7.

Nesta seção, você verá como implantar um HTTPRoute, que programa o gateway com as regras de roteamento necessárias para alcançar o aplicativo da loja.

  1. Salve o seguinte manifesto HTTPRoute em um arquivo chamado store-route.yaml:

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: store
    spec:
     parentRefs:
     - kind: Gateway
       name: internal-http
     hostnames:
     - "store.example.com"
     rules:
     - backendRefs:
       - name: store-v1
         port: 8080
     - matches:
       - headers:
         - name: env
           value: canary
       backendRefs:
       - name: store-v2
         port: 8080
     - matches:
       - path:
           value: /de
       backendRefs:
       - name: store-german
         port: 8080
    
  2. Implante o HTTPRoute no cluster:

    kubectl apply -f store-route.yaml
    

A HTTPRoute store está vinculada ao gateway internal-http e, por isso, essas regras de roteamento são configuradas no balanceador de carga subjacente, como neste diagrama:

As regras de roteamento configuradas pelo HTTPRoute da loja

Essas regras de roteamento processarão o tráfego HTTP da seguinte maneira:

  • O tráfego para store.example.com/de vai para o serviço store-german.
  • O tráfego para store.example.com com o cabeçalho HTTP "env: canary" vai para o serviço store-v2.
  • O tráfego restante para store.example.com vai para o serviço store-v1.

Vinculação de rotas

Os gateways usam a vinculação de rotas para corresponder rotas com gateways. Quando uma rota é vinculada a um gateway, o balanceador de carga ou proxy subjacente é programado com as regras de roteamento especificadas na rota. Os recursos Route e Gateway têm controles integrados para permitir ou restringir o modo como eles selecionam uns aos outros, o que determina a vinculação.

O HTTPRoute store está vinculado ao gateway internal-http usando a propriedade parentsRefs:

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: internal-http
spec:
  gatewayClassName: gke-l7-gxlb
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      kinds:
      - kind: HTTPRoute
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: store
  spec:
    parentRefs:
    - name: internal-http

Um HTTPRoute é anexado a um gateway específico por meio da propriedade parentsRef. Se o gateway estiver configurado para permitir o anexo desse tipo específico de namespace e rota, a anexação será feita. Por padrão, o gateway confia em todas as rotas do mesmo namespace. As rotas anexadas aos gateways configuram as regras de roteamento do balanceador de carga subjacente. Uma rota pode ser anexada a vários gateways, e eles também podem ter várias rotas anexadas.

Quando muitas rotas se anexam ao mesmo gateway, o GKE Gateway Controller mescla essas rotas em uma única configuração de roteamento para o balanceador de carga subjacente. É isso que permite que equipes diferentes compartilhem a mesma infraestrutura subjacente, enquanto cada uma controla a respectiva parte da configuração de roteamento de forma independente.

O GKE Gateway Controller implementa uma lógica rigorosa de mesclagem, precedência e validação de rota, que oferece mesclagem previsível entre rotas e impede que rotas inválidas interrompam a configuração do balanceador de carga subjacente. Para ver detalhes, consulte Mesclagem, precedência e validação de rotas.

Para instruções sobre como implantar um segundo HTTPRoute que também use o gateway http interno, consulte a seção Gateways compartilhados.

Como enviar tráfego para o aplicativo

Agora que o gateway, a rota e o aplicativo estão implantados no cluster, é possível transmitir o tráfego para o aplicativo.

  1. Verifique se o HTTPRoute de armazenamento foi aplicado. Os eventos são emitidos na rota quando ela é vinculada a um gateway.

    kubectl describe httproute.gateway.networking.k8s.io store
    

    A seção de eventos da saída inclui eventos como os mostrados a seguir se a HTTPRoute estiver vinculada ao gateway:

    Events:
    Type    Reason  Age   From                              Message
    ----    ------  ----  ----                              -------
    Normal  ADD     11m   networking.gke.io/gateway         default/store
    Normal  ADD     11m   multi-cluster-ingress-controller  default/store
    
  2. Recuperar o endereço IP do gateway para enviar tráfego ao aplicativo:

    kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}"
    

    A saída é um endereço IP.

  3. Envie tráfego para esse endereço IP pelo shell em uma instância de máquina virtual (VM) conectada ao cluster. É possível criar uma VM para essa finalidade. Isso é necessário porque o gateway tem um endereço IP interno. Ele só é acessível na rede VPC. Como internal-http é um balanceador de carga regional, o shell do cliente precisa estar na mesma região que o cluster do GKE.

    Como você não é proprietário do nome do host example.com, defina o cabeçalho do host manualmente para que o roteamento do tráfego possa ser observado. Primeiro, solicite store.example.com:

    curl -H "host: store.example.com" VIP
    

    Substitua VIP pelo endereço IP da etapa anterior.

    A saída do app de demonstração mostra informações sobre o local em que o app está em execução:

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.church-243723.internal",
      "pod_name": "store-v1-84b47c7f58-pmgmk",
      "pod_name_emoji": "💇🏼‍♀️",
      "project_id": "church-243723",
      "timestamp": "2021-03-25T13:31:17",
      "zone": "us-central1-a"
    }
    
  4. Teste a correspondência de caminho acessando a versão em alemão do serviço da loja em store.example.com/de:

    curl -H "host: store.example.com" VIP/de
    

    A resposta confirma que a solicitação foi exibida por um pod store-german:

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "Gutentag!", 
      "node_name": "gke-gke1-pool-2-bd121936-n3xn.c.church-243723.internal",
      "pod_name": "store-german-5cb6474c55-lq5pl", 
      "pod_name_emoji": "🧞‍♀",
      "project_id": "church-243723",
      "timestamp": "2021-03-25T13:35:37",
      "zone": "us-central1-a"
    }
    
  5. Por fim, use o cabeçalho HTTP env: canary para enviar o tráfego à versão canário do serviço de armazenamento:

    curl -H "host: store.example.com" -H "env: canary " VIP
    

    A resposta confirma que a solicitação foi exibida por um pod store-v2:

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "store-v2", 
      "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.church-243723.internal",
      "pod_name": "store-v2-5788476cbd-s9thb", 
      "pod_name_emoji": "👩🏿🦰",
      "project_id": "church-243723",
      "timestamp": "2021-03-25T13:38:26",
      "zone": "us-central1-a"
    }
    

Gateways compartilhados

As APIs Gateway usam recursos separados, gateways e recursos de rota para implantar balanceadores de carga e regras de roteamento. Isso é diferente do Ingress, que combina tudo em um recurso. Ao dividir a responsabilidade entre recursos, o gateway permite que o balanceador de carga e as regras de roteamento dele sejam implantados separadamente e implantados por diferentes usuários ou equipes. Isso permite que gateways se tornem gateways compartilhados que se anexam a muitas rotas diferentes, que podem ser gerenciadas por equipes independentes e de propriedade total delas, mesmo em namespaces diferentes.

Nas etapas anteriores, a equipe da loja implantou o aplicativo store.example.com. Em seguida, a equipe independente do site implantou o aplicativo dela, site.example.com, atrás do mesmo gateway internal-http usando o mesmo endereço IP.

Como implantar rotas em um gateway compartilhado

Neste exemplo, a equipe do site implanta o aplicativo dela, os serviços e um HTTPRoute correspondente ao tráfego do gateway a esses serviços.

  1. Implantar o aplicativo de exemplo:

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/site.yaml
    
  2. Salve o seguinte manifesto HTTPRoute em um arquivo chamado site-route.yaml:

    Esse HTTPRoute site corresponde a todo o tráfego para site.example.com e o encaminha para o Serviço site-v1. Assim como o HTTPRoute do site, o HTTPRoute do site especifica o gateway internal-http. O GKE Gateway Controller mescla esses HTTPRoutes em um único URLmap subjacente com rotas para site.example.com e store.example.com.

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
     name: site
    spec:
     hostnames:
     - "site.example.com"
     rules:
     - backendRefs:
       - name: site-v1
         port: 8080
    
  3. Implantar o HTTPRoute no cluster:

    kubectl apply -f site-route.yaml
    
  4. Com ambos os HTTPRoutes implantados, a lógica de roteamento será semelhante ao diagrama a seguir. O tráfego para site.example.com precisa ir aos pods site-v1. O tráfego para store.example.com, aos pods store-v1, store-v2 ou store-german.

    Uma foto da loja e do site HTTPRoutes vinculados ao mesmo gateway

  5. Verifique se o HTTPRoute foi vinculado ao gateway internal-http:

    kubectl describe httproute.gateway.networking.k8s.io site
    

    A saída será semelhante à seguinte se o HTTPRoute for vinculado ao gateway.

    Status:
      Gateways:
        Conditions:
          Last Transition Time:  2021-04-19T16:13:46Z
          Message:               Route admitted
          Observed Generation:   1
          Reason:                RouteAdmitted
          Status:                True
          Type:                  Admitted
        Gateway Ref:
          Name:       internal-http
          Namespace:  default
    Events:
      Type    Reason  Age                 From                              Message
      ----    ------  ----                ----                              -------
      Normal  ADD     60m                 networking.gke.io/gateway         foo/foo-route
    

    Se a condição permitida para o gateway de http interno for True, isso indica que HTTPRoute/site foi vinculado ao http interno.

    Configurações inválidas, referências a serviços inexistentes do Kubernetes, rotulagem incorreta de gateways ou conflitos com outras rotas podem fazer com que a vinculação do HTTPRoute com um gateway seja rejeitada

    Para detalhes sobre como interpretar o status das rotas, consulte a seção Status da rota.

  6. Depois de confirmar que a rota de site foi vinculada, envie o tráfego ao gateway para confirmar se ele está sendo roteado corretamente. Envie o tráfego de uma VM na mesma rede VPC do gateway. Envie uma solicitação HTTP para site.example.com e store.example.com para validar as respostas:

    curl -H "host: site.example.com" VIP
    curl -H "host: store.example.com" VIP
    

Status da rota

Os recursos do HTTPRoute emitem condições e eventos para ajudar os usuários a entender o status da configuração aplicada. Juntos, eles indicam se uma rota foi vinculada a um ou mais gateways ou se foi rejeitada.

Condições do HTTPRoute

As condições do HTTPRoute indicam o status da vinculação de rota entre os gateways a que uma rota está vinculada. Como uma rota pode ser vinculada a vários gateways, mostraremos uma lista de gateways e as condições individuais entre a rota e cada gateway.

  • "Admitted=True" indica que o HTTPRoute está vinculado a um gateway.
  • "Admitted=False" indica que a vinculação do HTTPRoute ao gateway foi rejeitada.

Se não houver gateways listados na seção Gateway bindings, significa que os rótulos de rota e os seletores de rótulo de gateway provavelmente não correspondem. Isso significa que a rota não está sendo selecionada por nenhum gateway e, portanto, a configuração não é aplicada a lugar algum.

Eventos do HTTPRoute

Os eventos do HTTPRoute fornecem mais detalhes sobre o status da rota. Há algumas classes ou motivos pelos quais os eventos são agrupados:

  • Eventos ADD são acionados por um recurso que está sendo adicionado.
  • Os eventos UPDATE são acionados por um recurso que está sendo atualizado.
  • Os eventos SYNC são acionados pela reconciliação periódica.

Como implantar um gateway externo

O exemplo a seguir mostra como implantar um gateway a ser usado para balanceamento de carga externo de Internet. Ele demonstra como configurar o TLS para a conexão do cliente proteger o gateway. Este exemplo usa o GatewayClass gke-l7-gxlb, mas esses conceitos TLS se aplicam igualmente a todos os GatewayClasses gke-l7-*.

O aplicativo implantado anteriormente é um pré-requisito deste exemplo. Se você ainda não tiver implantando, volte e implante esse aplicativo no cluster antes de continuar.

Os GatewayClasses gke-l7-gxlb e gke-l7-gxlb-mc implantam um balanceador de carga HTTP(S) externo global para o tráfego voltado para a Internet. Eles têm funcionalidades equivalentes, exceto que o gke-l7-gxlb-mc também é compatível com casos de uso de vários clusters, porque ele faz o balanceamento de carga de aplicativos em vários clusters do GKE. Para uma comparação com outros GatewayClasses, consulte Recursos do GatewayClass.

TLS entre o cliente e o gateway

Um balanceador de carga HTTP(S) externo atua como um proxy entre seus clientes e o aplicativo. Se você quiser aceitar solicitações HTTPS dos seus clientes, o balanceador de carga precisará ter um certificado para provar a identidade dele aos clientes. Além disso, ele precisa ter uma chave privada para concluir o handshake HTTPS. O certificado e a chave privada são chamados de credenciais TLS.

A chave e o certificado TLS são armazenados como recursos de certificado SSL do Google Cloud.

O manifesto de gateway a seguir mostra como o TLS é configurado:

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: external-http
spec:
  gatewayClassName: gke-l7-gxlb
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      kinds:
      - kind: HTTPRoute
    tls:
      mode: Terminate
      options:
        networking.gke.io/pre-shared-certs: store-example-com

Estes elementos são obrigatórios em um gateway que use TLS:

  • A porta e o protocolo do listener do gateway precisam ser definidos como 443 e HTTPS.
  • O campo listener.tls.mode precisa ser definido como Terminate.
  • As credenciais TLS precisam ser referenciadas no bloco listeners.tls.

O manifesto de exemplo faz referência a um recurso de certificado SSL chamado store-example-com. Todo o tráfego para a porta 443 desse gateway é encerrado por esse certificado.

Como criar e armazenar um certificado TLS

Há muitas maneiras de gerar certificados TLS. Eles podem ser gerados manualmente na linha de comando, gerados com certificados gerenciados pelo Google ou internamente pelo sistema de infraestrutura de chave pública (ICP) de uma empresa. Neste exemplo, geramos manualmente um certificado autoassinado. Os certificados autoassinados geralmente não são usados para serviços públicos. Eles serão usados aqui porque demonstram estes conceitos com mais facilidade.

  1. Siga a Etapa 1: criar uma chave privada e um certificado do guia de certificados SSL autogerenciados. Isso gera um certificado autoassinado e um par de chaves usando a linha de comando. Use a seguinte configuração do OpenSSL para criar um certificado autoassinado para store.example.com.

    [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                = store.example.com
    
    [sans_list]
    DNS.1                     = store.example.com
    

    Salve os arquivos de certificado e de chave como cert.pem e key.pem, respectivamente. Não prossiga para a etapa 2 das instruções sobre como usar certificados SSL autogerenciados.

  2. Salve as credenciais do certificado como um recurso de certificado SSL global:

    gcloud compute ssl-certificates create store-example-com \
        --certificate=cert.pem \
        --private-key=key.pem \
        --global
    

    O nome do GatewayClass indica o tipo de recurso de certificado SSL que pode ser usado com os gateways dessa classe. O escopo e o local do certificado SSL precisam corresponder ao escopo e ao local do gateway que está usando o certificado. Por exemplo, um certificado SSL global não pode ser usado por um gateway regional.

    A tabela a seguir mostra os requisitos de escopo e local para os recursos de certificado SSL usados pelos gateways:

    GatewayClasses Escopo do certificado SSL Local do certificado SSL
    • gke-l7-rilb
    • gke-l7-rilb-mc
    Certificado SSL regional Precisa ser a mesma região do gateway
    • gke-l7-gxlb
    • gke-l7-gxlb-mc
    Certificado SSL global Global

Como implantar o gateway

  1. Salve o seguinte manifesto de gateway, que usa o GatewayClass gke-l7-gxlb, como external-gateway.yaml:

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-gxlb
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
        tls:
          mode: Terminate
          options:
            networking.gke.io/pre-shared-certs: store-example-com
    

    Esse manifesto de gateway externo difere do exemplo de gateway interno anterior de várias maneiras:

    • Ele usa o GatewayClass gke-l7-gxlb, que implanta um balanceador de carga HTTP(S) externo.
    • A porta e o protocolo dele estão definidos como 443 e HTTPS.
    • A seção tls do manifesto está configurada para encerrar o TLS usando um recurso de certificado SSL.
  2. Implante este gateway no cluster do GKE:

    kubectl apply -f external-gateway.yaml
    
  3. Salve o seguinte manifesto HTTPRoute como store-external-route.yaml:

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    
  4. Implantar o HTTPRoute no cluster:

    kubectl apply -f store-external-route.yaml
    

    Pode levar vários minutos para que o gateway gke-l7-gxlb seja totalmente implantado.

  5. Verifique se o gateway funciona enviando uma solicitação pela Internet.

    1. Salve o arquivo cert.pem gerado anteriormente na máquina que você está usando para se conectar ao gateway. O gateway usa um certificado autoassinado, que é necessário para autenticar o gateway.

    2. Consiga o endereço IP do balanceador de carga.

      kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}"
      

      O comando gera o endereço IP do balanceador de carga. Esse é um endereço IP público. Portanto, qualquer cliente com acesso à Internet pode se conectar a ele.

    3. Use curl para acessar o domínio do gateway. Como o DNS não está configurado para esse domínio, use a opção --resolve para instruir o curl a resolver o nome de domínio para o endereço IP do gateway:

      curl https://store.example.com --resolve store.example.com:443:VIP --cacert cert.pem -v
      

      Substitua VIP pelo endereço IP do balanceador de carga.

    4. A saída detalhada de curl inclui um handshake de TLS bem-sucedido seguido por uma resposta do aplicativo, como a saída a seguir. Isso prova que o TLS está sendo encerrado corretamente no gateway e que o aplicativo está respondendo ao cliente com segurança.

      ...
      * 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=store.example.com
      *  start date: Apr 19 15:54:50 2021 GMT
      *  expire date: Apr 19 15:54:50 2022 GMT
      *  common name: store.example.com (matched)
      *  issuer: O=example; CN=store.example.com
      *  SSL certificate verify ok.
      ...
      {
        "cluster_name": "gw",
        "host_header": "store.example.com",
        "metadata": "store-v1",
        "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
        "pod_name": "store-v1-84b47c7f58-tj5mn",
        "pod_name_emoji": "😍",
        "project_id": "agmsb-k8s",
        "timestamp": "2021-04-19T16:30:08",
        "zone": "us-west1-a"
      }
      

BackendConfig com gateway

Os GatewayClasses gke-l7 são compatíveis com o recurso BackendConfig, que personalizam configurações de back-end em nível por serviço. Isso requer a anotação de serviço cloud.google.com/backend-config para fazer referência ao recurso BackendConfig. No exemplo a seguir, as configurações de verificação de integridade e diminuição de conexão do balanceador de carga são personalizadas para o serviço store-v1.

apiVersion: v1
kind: Service
metadata:
  name: store-v1
  annotations:
    cloud.google.com/backend-config: '{"default": "store-backendconfig"}'
spec:
  selector:
    app: store
    version: v1
  ports:
  - port: 8080
    targetPort: 8080
---
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: store-backendconfig
spec:
  healthCheck:
    checkIntervalSec: 15
    port: 15020
    type: HTTPS
    requestPath: /healthz
  connectionDraining:
    drainingTimeoutSec: 60

Consulte Como configurar recursos do Ingress usando parâmetros BackendConfig para mais detalhes sobre como usar o recurso BackendConfig.

Endereçamento IP do gateway

Cada gateway tem um endereço IP em que ele escuta o tráfego. Se nenhum endereço for especificado no gateway, um endereço IP será automaticamente provisionado pelo gateway. Os endereços estáticos também podem ser pré-provisionados para que o ciclo de vida do endereço IP seja independente do gateway.

Depois que um gateway é implantado, o endereço IP dele é exibido no campo de status:

kind: Gateway
...
status:
  addresses:
    - value: 10.15.32.3

Dependendo da GatewayClass, o endereço IP é alocado das seguintes sub-redes:

GatewayClasses Pool de endereços IP padrão
  • gke-l7-rilb
  • gke-l7-rilb-mc
Endereços IP privados regionais do intervalo de sub-rede do nó do cluster do GKE
  • gke-l7-gxlb
  • gke-l7-gxlb-mc
Endereços IP públicos globais dos intervalos de IP públicos do Google

É possível especificar um endereço IP de duas maneiras:

  • addresses.IPAddress: permite especificar um endereço IP no momento da implantação do gateway. O endereço IP é configurável, em vez de provisionado automaticamente, mas tem o mesmo ciclo de vida do gateway e é liberado se o gateway for excluído.

  • addresses.NamedAddress: permite especificar um endereço IP independentemente do gateway. É possível criar um recurso de endereço IP estático antes da implantação do gateway, e o recurso é referenciado pelo NamedAddress. Reutilize o endereço IP estático mesmo que o gateway seja excluído.

É possível configurar um IPAddress especificando o endereço IP no campo addresses do gateway implantado.

  1. Implante o gateway interno a seguir e especifique 10.0.0.3 como o endereço IP estático:

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: internal-http
    spec:
      gatewayClassName: gke-l7-rilb
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
      addresses:
      - type: IPAddress
        value: 10.0.0.3
    

    Um NamedAddress exige que você provisione um IP estático fora da implantação do gateway. Isso exige duas etapas separadas:

  2. Crie um recurso de endereço IP estático. Nesse caso, um gateway interno e regional é implantado. Portanto, é necessário um endereço IP interno regional correspondente.

    gcloud compute addresses create ADDRESS_NAME \
        --region REGION \
        --subnet SUBNET \
        --project PROJECT_ID
    

    Ao usar gateways regionais, substitua PROJECT_ID e REGION pelo projeto e pela região em que o cluster do GKE está em execução. Os gateways externos globais não exigem uma especificação de região ou sub-rede.

  3. Implante seu gateway fazendo referência ao mesmo nome de recurso do endereço que o NamedAddress.

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1alpha2
    metadata:
      name: internal-http
    spec:
      gatewayClassName: gke-l7-rilb
      listeners:
      - name: http
        protocol: HTTP
        port: 80
      addresses:
      - type: NamedAddress
        value: ADDRESS_NAME
    

Combinação, precedência e validação de rotas

Precedência da rota

A API Gateway define regras de precedência rígidas que definem como o tráfego é correspondido por rotas que tenham regras de roteamento sobrepostas. A precedência entre dois HTTPRoutes sobrepostos é a seguinte:

  1. Mesclagem de nomes do host: a correspondência de nome do host mais longa ou mais específica.
  2. Mesclagem de caminho: a correspondência de caminho mais longa ou mais específica.
  3. Mesclagem de cabeçalhos: o maior número de cabeçalhos HTTP correspondentes.
  4. Conflito: se as três regras anteriores não estabelecerem precedência, a precedência irá para o recurso HTTPRoute com o carimbo de data/hora mais antigo.

Mesclagem de rotas

Para GatewayClasses gke-l7, todos os HTTPRoutes de um determinado gateway são mesclados no mesmo recurso de mapa de URL. A maneira como os HTTPRoutes são mesclados depende do tipo de sobreposição entre HTTPRoutes. O HTTPRoute do exemplo anterior pode ser dividido em três HTTPRoutes separados para ilustrar a mesclagem e a precedência de rotas:

  1. Mesclagem de rotas: todos os três HTTPRoutes se anexam com o mesmo gateway internal-http para serem mesclados.
  2. Mesclagem de nome do host: todas as três rotas correspondem a store.example.com. Portanto, as regras de nome de host delas são mescladas.
  3. Mesclagem de caminhos: store-german-route tem um caminho /de mais específico. Portanto, ele não é mesclado. As rotas store-v1-route e store-v2-route também correspondem ao mesmo caminho /*, então são mesclados ao caminho.
  4. Mesclagem de cabeçalho: store-v2-route tem um conjunto mais específico de correspondências de cabeçalho HTTP do que store-v1-route e, portanto, não são combinados.
  5. Conflito: como as rotas podem ser mescladas no nome do host, no caminho e nos cabeçalhos, não há conflitos, e todas as regras de roteamento serão aplicadas ao tráfego.

O único HTTPRoute usado no exemplo anterior é equivalente a estas três rotas separadas:

kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: store-v1-route
  labels:
    gateway: internal-http
spec:
  hostnames:
  - "store.example.com"
  rules:
  - backendRefs:
    - kind: Service
      name: store-v1
      port: 8080
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: store-v2-route
  labels:
    gateway: internal-http
spec:
  hostnames:
  - "store.example.com"
  rules:
  - matches:
    - headers:
      - type: Exact
        name: env
        value: canary
    backendRefs:
    - kind: Service
      name: store-v2
      port: 8080
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: store-german-route
  labels:
    gateway: internal-http
spec:
  hostnames:
  - "store.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /de
    backendRefs:
    - kind: Service
      name: store-german
      port: 8080

Back-end padrão de gateway

Todas os GatewayClasses gke-l7 têm um back-end padrão implícito que retorna um HTTP 404 para tráfego sem correspondência. É possível personalizar o back-end padrão com uma rota padrão explícita que envia tráfego sem correspondência a um serviço fornecido pelo usuário. O HTTPRoute a seguir é um exemplo de como personalizar o back-end padrão. Se aplicado, ele terá precedência sobre o back-end padrão implícito:

kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
metadata:
  name: custom-default-backend
  labels:
    gateway: my-gateway
spec:
  rules:
  - backendRefs:
    - name: my-custom-default-backend-service
      port: 8080

Esse HTTPRoute corresponde a todo o tráfego de um gateway específico. Só pode haver um HTTPRoute por gateway. Caso contrário, eles entrarão em conflito, e a ordem de precedência será aplicada.

Um back-end padrão explícito também é uma estratégia eficaz para evitar que alguém crie acidentalmente uma rota padrão que descarta o tráfego para um gateway. Como um HTTPRoute padrão explícito é o recurso mais antigo, ele sempre terá precedência sobre novos HTTPRoutes que tiverem regras de roteamento conflitantes.

Gateways do Kubernetes e gateways do Istio

Observe que a API Gateway do Kubernetes e a API do Istio têm um recurso chamado Gateway. Eles executam funções semelhantes, mas não são a mesma funcionalidade. Se você estiver usando o Istio e a API Gateway no mesmo cluster do Kubernetes, esses nomes se sobreporão ao usar o kubectl na linha de comando. kubectl get gateway pode retornar os recursos do gateway do Kubernetes, e não os recursos do gateway do Istio, ou vice-versa.

$ kubectl api-resources
NAME       SHORTNAMES   APIGROUP                       NAMESPACED   KIND
gateways   gw           networking.istio.io/v1beta1            true         Gateway
gateways   gtw          networking.k8s.io/v1alpha2           true         Gateway

Para clusters do GKE 1.20 e posteriores, o controlador de gateway do GKE instala automaticamente o recurso gateway.networking.k8s.io/v1alpha2 nos clusters. Se estiver usando o Istio e fizer upgrade para o GKE 1.20 e posterior, é recomendável começar a usar o nome curto do recurso do gateway ou especificar o grupo da API. A abreviação de um gateway do Kubernetes é gtw e a abreviação de um gateway do Istio é gw. Os comandos a seguir retornam os recursos do gateway do Kubernetes e do Istio, respectivamente.

# Kubernetes Gateway
$ kubectl get gtw
NAME                        CLASS
multi-cluster-gateway       gke-l7-gxlb-mc

$ kubectl get gateway.networking.x-k8s.io
NAME                        CLASS
multi-cluster-gateway       gke-l7-gxlb-mc

# Istio Gateway
$ kubectl get gw
NAME               AGE
bookinfo-gateway   64m

$ kubectl get gateway.networking.istio.io
NAME               AGE
bookinfo-gateway   64m

A seguir