Este documento explica uma implementação azul-verde de uma aplicação de exemplo em dois clusters do GKE.store As implementações azul-verde são uma estratégia eficaz para migrar as suas aplicações para novos clusters do GKE com um risco mínimo. Ao mudar gradualmente o tráfego do cluster atual (azul) para o novo cluster (verde), pode validar o novo ambiente em produção antes de se comprometer com uma mudança completa.
Neste tutorial, vai usar uma aplicação de exemplo store para simular um cenário real
em que um serviço de compras online é detido e operado por equipas
separadas e implementado numa frota de
clusters do GKE partilhados.
Antes de começar
Os gateways de vários clusters requerem alguma preparação ambiental antes de poderem ser implementados. Antes de continuar, siga os passos em Prepare o seu ambiente para gateways multicluster:
Implemente clusters do GKE.
Registe os seus clusters numa frota (se ainda não o tiverem feito).
Ative os controladores de serviço em vários clusters e de gateway em vários clusters.
Por último, reveja as limitações e os problemas conhecidos do controlador do GKE Gateway antes de usar o controlador no seu ambiente.
Encaminhamento azul-verde de vários clusters com o Gateway
As GatewayClasses gke-l7-global-external-managed-*, gke-l7-regional-external-managed-* e gke-l7-rilb-* têm muitas capacidades avançadas de encaminhamento de tráfego, incluindo divisão de tráfego, correspondência de cabeçalhos, manipulação de cabeçalhos, espelhamento de tráfego e muito mais. Neste exemplo, vai demonstrar como usar a divisão de tráfego baseada em ponderação para controlar explicitamente a proporção de tráfego em dois clusters do GKE.
Este exemplo aborda alguns passos realistas que um proprietário de um serviço daria para mover ou expandir a respetiva aplicação para um novo cluster do GKE. O objetivo das implementações azul-verde é reduzir o risco através de vários passos de validação que confirmam que o novo cluster está a funcionar corretamente. Este exemplo explica quatro fases de implementação:
- 100%-Canário baseado em cabeçalhos: Use o encaminhamento de cabeçalhos HTTP para enviar apenas tráfego de teste ou sintético para o novo cluster.
- 100%: refletir tráfego: refletir tráfego de utilizadores para o cluster de teste. Este teste testa a capacidade do cluster de teste preliminar copiando 100% do tráfego de utilizadores para este cluster.
- 90%-10%: Teste canário de uma divisão de tráfego de 10% para expor lentamente o novo cluster ao tráfego em direto.
- 0%-100%: Transição total para o novo cluster com a opção de reverter se forem observados erros.
Este exemplo é semelhante ao anterior, exceto que implementa um gateway interno de vários clusters. Isto implementa um Application Load Balancer interno que só é acessível de forma privada a partir da VPC. Vai usar os clusters e a mesma aplicação que implementou nos passos anteriores, exceto que vai implementá-los através de um gateway diferente.
Pré-requisitos
O exemplo seguinte baseia-se em alguns dos passos em Implementar um gateway externo de vários clusters. Certifique-se de que concluiu os seguintes passos antes de avançar com este exemplo:
Implementar uma aplicação de demonstração
Este exemplo usa os clusters
gke-west-1egke-west-2que já configurou. Estes clusters estão na mesma região porque agke-l7-rilb-mcGatewayClass é regional e só suporta back-ends de cluster na mesma região.Implemente o serviço e os ServiceExports necessários em cada cluster. Se implementou Services e ServiceExports do exemplo anterior, já implementou alguns destes.
kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store-west-1-service.yaml kubectl apply --context gke-west-2 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store-west-2-service.yamlImplementa um conjunto semelhante de recursos em cada cluster:
service/store created serviceexport.net.gke.io/store created service/store-west-2 created serviceexport.net.gke.io/store-west-2 created
Configurar uma sub-rede só de proxy
Se ainda não o fez, configure uma sub-rede
apenas de proxy para
cada região na qual está a implementar gateways internos. Esta sub-rede é usada para fornecer endereços IP internos aos proxies do equilibrador de carga e tem de ser configurada com um --purpose definido apenas como REGIONAL_MANAGED_PROXY.
Tem de criar uma sub-rede apenas de proxy antes de criar gateways que gerem equilibradores de carga de aplicações internos. Cada região de uma rede de nuvem virtual privada (VPC) na qual usa equilibradores de carga de aplicações internos tem de ter uma sub-rede apenas de proxy.
O comando gcloud compute networks subnets create
cria uma sub-rede só de proxy.
gcloud compute networks subnets create SUBNET_NAME \
--purpose=REGIONAL_MANAGED_PROXY \
--role=ACTIVE \
--region=REGION \
--network=VPC_NETWORK_NAME \
--range=CIDR_RANGE
Substitua o seguinte:
SUBNET_NAME: o nome da sub-rede só de proxy.REGION: a região da sub-rede só de 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. Tem de usar uma máscara de sub-rede não superior a/26para que estejam disponíveis, pelo menos, 64 endereços IP para proxies na região. A máscara de sub-rede recomendada é/23.
Implementar o gateway
O Gateway seguinte é criado a partir da gke-l7-rilb-mc GatewayClass, que é um Gateway interno regional que só pode segmentar clusters do GKE na mesma região.
Aplique o manifesto
Gatewayseguinte ao cluster de configuração,gke-west-1neste exemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-http namespace: store spec: gatewayClassName: gke-l7-rilb-mc listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute EOFValide se o gateway foi iniciado com êxito. Pode filtrar apenas os eventos desta entrada com o seguinte comando:
kubectl get events --field-selector involvedObject.kind=Gateway,involvedObject.name=internal-http --context=gke-west-1 --namespace storeA implementação do gateway foi bem-sucedida se o resultado for semelhante ao seguinte:
LAST SEEN TYPE REASON OBJECT MESSAGE 5m18s Normal ADD gateway/internal-http store/internal-http 3m44s Normal UPDATE gateway/internal-http store/internal-http 3m9s Normal SYNC gateway/internal-http SYNC on store/internal-http was a success
Teste com base no cabeçalho
O teste canário baseado em cabeçalhos permite ao proprietário do serviço fazer corresponder o tráfego de teste sintético que não é proveniente de utilizadores reais. Esta é uma forma fácil de validar se o funcionamento em rede básico da aplicação está a funcionar sem expor os utilizadores diretamente.
Aplique o manifesto
HTTPRouteseguinte ao cluster de configuração,gke-west-1neste exemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: # Matches for env=canary and sends it to store-west-2 ServiceImport - matches: - headers: - name: env value: canary backendRefs: - group: net.gke.io kind: ServiceImport name: store-west-2 port: 8080 # All other traffic goes to store-west-1 ServiceImport - backendRefs: - group: net.gke.io kind: ServiceImport name: store-west-1 port: 8080 EOFUma vez implementado, este HTTPRoute configura o seguinte comportamento de encaminhamento:
- Os pedidos internos para
store.example.internalsem o cabeçalho HTTPenv: canarysão encaminhados para os podsstoreno clustergke-west-1 - Os pedidos internos para
store.example.internalcom o cabeçalho HTTPenv: canarysão encaminhados para os podsstoreno clustergke-west-2
Valide se o HTTPRoute está a funcionar corretamente enviando tráfego para o endereço IP do gateway.
- Os pedidos internos para
Recupere o endereço IP interno de
internal-http.kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}" --context gke-west-1 --namespace storeSubstitua VIP nos passos seguintes pelo endereço IP que recebe como resultado.
Envie um pedido ao gateway através do cabeçalho HTTP
env: canary. Esta ação confirma que o tráfego está a ser encaminhado paragke-west-2. Use um cliente privado na mesma VPC que os clusters do GKE para confirmar que os pedidos estão a ser encaminhados corretamente. O seguinte comando tem de ser executado numa máquina que tenha acesso privado ao endereço IP do gateway. Caso contrário, não funciona.curl -H "host: store.example.internal" -H "env: canary" http://VIPO resultado confirma que o pedido foi publicado por um pod do cluster
gke-west-2:{ "cluster_name": "gke-west-2", "host_header": "store.example.internal", "node_name": "gke-gke-west-2-default-pool-4cde1f72-m82p.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-9kdb5", "pod_name_emoji": "😂", "project_id": "agmsb-k8s", "timestamp": "2021-05-31T01:21:55", "zone": "us-west1-a" }
Espelho de trânsito
Esta fase envia tráfego para o cluster pretendido, mas também reflete esse tráfego no cluster de teste.
A utilização da replicação é útil para determinar como a carga de tráfego vai afetar o desempenho da aplicação sem afetar as respostas aos seus clientes de forma alguma. Pode não ser necessário para todos os tipos de implementações, mas pode ser útil quando implementa grandes alterações que podem afetar o desempenho ou o carregamento.
Aplique o manifesto
HTTPRouteseguinte ao cluster de configuração,gke-west-1neste exemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: # Sends all traffic to store-west-1 ServiceImport - backendRefs: - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 # Also mirrors all traffic to store-west-2 ServiceImport filters: - type: RequestMirror requestMirror: backendRef: group: net.gke.io kind: ServiceImport name: store-west-2 port: 8080 EOFUsando o seu cliente privado, envie um pedido para o
internal-httpgateway. Use o caminho/mirrorpara poder identificar exclusivamente este pedido nos registos da aplicação num passo posterior.curl -H "host: store.example.internal" http://VIP/mirrorO resultado confirma que o cliente recebeu uma resposta de um pod no cluster
gke-west-1:{ "cluster_name": "gke-west-1", "host_header": "store.example.internal", "node_name": "gke-gke-west-1-default-pool-65059399-ssfq.c.agmsb-k8s.internal", "pod_name": "store-5f5b954888-brg5w", "pod_name_emoji": "🎖", "project_id": "agmsb-k8s", "timestamp": "2021-05-31T01:24:51", "zone": "us-west1-a" }Isto confirma que o cluster principal está a responder ao tráfego. Ainda tem de confirmar que o cluster para o qual está a migrar está a receber tráfego espelhado.
Verifique os registos de aplicações de um
storepod no clustergke-west-2. Os registos devem confirmar que o pod recebeu tráfego espelhado do equilibrador de carga.kubectl logs deployment/store --context gke-west-2 -n store | grep /mirrorEste resultado confirma que os pods no cluster
gke-west-2também estão a receber os mesmos pedidos. No entanto, as respetivas respostas a estes pedidos não são enviadas de volta ao cliente. Os endereços IP vistos nos registos são os endereços IP internos do balanceador de carga que estão a comunicar com os seus pods.Found 2 pods, using pod/store-5c65bdf74f-vpqbs [2023-10-12 21:05:20,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:20] "GET /mirror HTTP/1.1" 200 - [2023-10-12 21:05:27,158] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 - [2023-10-12 21:05:27,805] INFO in _internal: 192.168.21.3 - - [12/Oct/2023 21:05:27] "GET /mirror HTTP/1.1" 200 -
Divisão de tráfego
A divisão do tráfego é um dos métodos mais comuns de implementação de novo código ou implementação em novos ambientes de forma segura. O proprietário do serviço define uma percentagem explícita do tráfego que é enviado para os back-ends de teste beta, que é normalmente uma quantidade muito pequena do tráfego geral, para que o sucesso da implementação possa ser determinado com uma quantidade aceitável de risco para os pedidos de utilizadores reais.
A divisão do tráfego com uma minoria do tráfego permite ao proprietário do serviço inspecionar o estado de funcionamento da aplicação e as respostas. Se todos os sinais parecerem em bom estado, podem avançar para a mudança completa.
Aplique o manifesto
HTTPRouteseguinte ao cluster de configuração,gke-west-1neste exemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: - backendRefs: # 90% of traffic to store-west-1 ServiceImport - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 weight: 90 # 10% of traffic to store-west-2 ServiceImport - name: store-west-2 group: net.gke.io kind: ServiceImport port: 8080 weight: 10 EOFUsando o seu cliente privado, envie um pedido curl contínuo para o gateway
internal- http.while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; doneO resultado será semelhante a este, indicando que está a ocorrer uma divisão de tráfego de 90/10.
"cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", "cluster_name": "gke-west-2", "cluster_name": "gke-west-1", "cluster_name": "gke-west-1", ...
Transferência de tráfego
A última fase da migração azul-verde consiste em mudar totalmente para o novo cluster e remover o cluster antigo. Se o proprietário do serviço estivesse a integrar
um segundo cluster num cluster existente, este último passo seria diferente,
uma vez que o passo final teria tráfego a direcionar-se para ambos os clusters. Nesse cenário, recomenda-se uma única storeServiceImportgke-west-1 que tenha pods dos clusters gke-west-1 e gke-west-2. Isto permite que o balanceador de carga tome a decisão de para onde o tráfego deve ir para uma aplicação ativa-ativa, com base na proximidade, no estado e na capacidade.
Aplique o manifesto
HTTPRouteseguinte ao cluster de configuração,gke-west-1neste exemplo:cat << EOF | kubectl apply --context gke-west-1 -f - kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-store-route namespace: store labels: gateway: internal-http spec: parentRefs: - kind: Gateway namespace: store name: internal-http hostnames: - "store.example.internal" rules: - backendRefs: # No traffic to the store-west-1 ServiceImport - name: store-west-1 group: net.gke.io kind: ServiceImport port: 8080 weight: 0 # All traffic to the store-west-2 ServiceImport - name: store-west-2 group: net.gke.io kind: ServiceImport port: 8080 weight: 100 EOFUsando o seu cliente privado, envie um pedido curl contínuo para o gateway
internal- http.while true; do curl -H "host: store.example.internal" -s VIP | grep "cluster_name"; sleep 1; doneO resultado será semelhante a este, indicando que todo o tráfego está agora a ser direcionado para
gke-west-2."cluster_name": "gke-west-2", "cluster_name": "gke-west-2", "cluster_name": "gke-west-2", "cluster_name": "gke-west-2", ...
Este passo final conclui uma migração de aplicações azul-verde completa de um cluster do GKE para outro cluster do GKE.
Limpar
Depois de concluir os exercícios neste documento, siga estes passos para remover recursos e evitar a incorrência de cobranças indesejadas na sua conta:
Anule o registo dos clusters da frota se não precisarem de ser registados para outro fim.
Desative a funcionalidade
multiclusterservicediscovery:gcloud container fleet multi-cluster-services disableDesative a entrada em vários clusters:
gcloud container fleet ingress disableDesative as APIs:
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
Resolução de problemas
Não existe um upstream em bom estado
Sintoma:
O seguinte problema pode ocorrer quando cria um gateway, mas não consegue aceder aos serviços de back-end (código de resposta 503):
no healthy upstream
Motivo:
Esta mensagem de erro indica que o verificador de estado de funcionamento não consegue encontrar serviços de back-end em bom estado. É possível que os seus serviços de back-end estejam em bom estado, mas pode ter de personalizar as verificações de funcionamento.
Solução alternativa:
Para resolver este problema, personalize a verificação de estado com base nos requisitos da sua aplicação (por exemplo, /health) através de um HealthCheckPolicy.
O que se segue?
- Saiba mais sobre o controlador de gateway.