Esta página explica como usar o equilíbrio de carga nativo de contentores no Google Kubernetes Engine (GKE). O balanceamento de carga nativa do contentor permite que os balanceadores de carga segmentem diretamente os pods do Kubernetes e distribuam o tráfego uniformemente para os pods.
Para mais informações sobre as vantagens, os requisitos e as limitações do balanceamento de carga nativa do contentor, consulte o artigo Balanceamento de carga nativa do contentor.
Antes de começar
Antes de começar, certifique-se de que realizou as seguintes tarefas:
- Ative a API Google Kubernetes Engine. Ative a API Google Kubernetes Engine
- Se quiser usar a CLI gcloud para esta tarefa,
instale-a e, em seguida,
inicialize-a. Se instalou anteriormente a CLI gcloud, execute
gcloud components update
para obter a versão mais recente.
Use o balanceamento de carga nativa do contentor
As secções seguintes explicam uma configuração de balanceamento de carga nativa do contentor no GKE.
Crie um cluster nativo de VPC
Para usar o equilíbrio de carga nativo do contentor, o cluster do GKE tem de ter os IPs de alias ativados.
Por exemplo, o comando seguinte cria um cluster do GKE,
neg-demo-cluster
, com uma sub-rede aprovisionada automaticamente:
Para o modo de piloto automático, as moradas IP de alias estão ativadas por predefinição:
gcloud container clusters create-auto neg-demo-cluster \ --location=COMPUTE_LOCATION
Substitua
COMPUTE_LOCATION
pela localização do Compute Engine para o cluster.Para o modo Standard, ative os endereços IP de alias quando criar o cluster:
gcloud container clusters create neg-demo-cluster \ --enable-ip-alias \ --create-subnetwork="" \ --network=default \ --location=us-central1-a
Crie uma implementação
A seguinte amostra de
implementação,
neg-demo-app
, executa uma única instância de um servidor HTTP em contentor. Recomendamos que use cargas de trabalho que usem o feedback de prontidão do pod.
Usar o feedback de disponibilidade de pods
apiVersion: apps/v1 kind: Deployment metadata: labels: run: neg-demo-app # Label for the Deployment name: neg-demo-app # Name of Deployment spec: selector: matchLabels: run: neg-demo-app template: # Pod template metadata: labels: run: neg-demo-app # Labels Pods from this Deployment spec: # Pod specification; each Pod created by this Deployment has this specification containers: - image: registry.k8s.io/serve_hostname:v1.4 # Application to run in Deployment's Pods name: hostname # Container name ports: - containerPort: 9376 protocol: TCP
Usar um atraso codificado
apiVersion: apps/v1 kind: Deployment metadata: labels: run: neg-demo-app # Label for the Deployment name: neg-demo-app # Name of Deployment spec: minReadySeconds: 60 # Number of seconds to wait after a Pod is created and its status is Ready selector: matchLabels: run: neg-demo-app template: # Pod template metadata: labels: run: neg-demo-app # Labels Pods from this Deployment spec: # Pod specification; each Pod created by this Deployment has this specification containers: - image: registry.k8s.io/serve_hostname:v1.4 # Application to run in Deployment's Pods name: hostname # Container name # Note: The following line is necessary only on clusters running GKE v1.11 and lower. # For details, see https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing#align_rollouts ports: - containerPort: 9376 protocol: TCP terminationGracePeriodSeconds: 60 # Number of seconds to wait for connections to terminate before shutting down Pods
Nesta implementação, cada contentor executa um servidor HTTP. O servidor HTTP devolve o nome de anfitrião do servidor de aplicações (o nome do pod no qual o servidor é executado) como resposta.
Guarde este manifesto como neg-demo-app.yaml
e, em seguida, crie a implementação:
kubectl apply -f neg-demo-app.yaml
Crie um serviço para um balanceador de carga nativa do contentor
Depois de criar uma implementação, tem de agrupar os respetivos pods num serviço.
O seguinte serviço de exemplo, neg-demo-svc
, segmenta a implementação de exemplo que criou na secção anterior:
apiVersion: v1
kind: Service
metadata:
name: neg-demo-svc # Name of Service
spec: # Service's specification
type: ClusterIP
selector:
run: neg-demo-app # Selects Pods labelled run: neg-demo-app
ports:
- name: http
port: 80 # Service's port
protocol: TCP
targetPort: 9376
O balanceador de carga não é criado até criar um Ingress para o serviço.
Guarde este manifesto como neg-demo-svc.yaml
e, em seguida, crie o serviço:
kubectl apply -f neg-demo-svc.yaml
Crie um Ingress para o serviço
O seguinte exemplo de
Ingress,
neg-demo-ing
, segmenta o serviço que criou:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: neg-demo-ing
spec:
defaultBackend:
service:
name: neg-demo-svc # Name of the Service targeted by the Ingress
port:
number: 80 # Should match the port used by the Service
Guarde este manifesto como neg-demo-ing.yaml
e, em seguida, crie a entrada:
kubectl apply -f neg-demo-ing.yaml
Após a criação do Ingress, é criado um Application Load Balancer no projeto e são criados grupos de pontos finais de rede(NEGs) em cada zona em que o cluster é executado. Os pontos finais no NEG e os pontos finais do serviço são mantidos sincronizados.
Valide a entrada
Depois de implementar uma carga de trabalho, agrupar os respetivos pods num serviço e criar um Ingress para o serviço, deve verificar se o balanceador de carga nativo de contentores foi aprovisionado com êxito.
Obtenha o estado do Ingress:
kubectl describe ingress neg-demo-ing
A saída inclui eventos ADD
e CREATE
:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 16m loadbalancer-controller default/neg-demo-ing
Normal Service 4s loadbalancer-controller default backend set to neg-demo-svc:32524
Normal CREATE 2s loadbalancer-controller ip: 192.0.2.0
Teste o balanceador de carga
As secções seguintes explicam como pode testar a funcionalidade de um balanceador de carga nativo de contentores.
Endereço IP de entrada de visitas
Aguarde vários minutos até que o Application Load Balancer seja configurado.
Pode verificar se o balanceador de carga nativo do contentor está a funcionar visitando o endereço IP do Ingress.
Para obter o endereço IP de entrada, execute o seguinte comando:
kubectl get ingress neg-demo-ing
Na saída do comando, o endereço IP do Ingress é apresentado na coluna ADDRESS
. Visite o endereço IP num navegador de Internet.
Verifique o estado de funcionamento do serviço de back-end
Também pode obter o estado de funcionamento do serviço de back-end do balanceador de carga.
Obtenha uma lista dos serviços de back-end em execução no seu projeto:
gcloud compute backend-services list
Registe o nome do serviço de back-end que inclui o nome do serviço, como
neg-demo-svc
.Obtenha o estado de saúde do serviço de back-end:
gcloud compute backend-services get-health BACKEND_SERVICE_NAME --global
Substitua
BACKEND_SERVICE_NAME
pelo nome do serviço de back-end.
Teste a entrada
Outra forma de testar se o balanceador de carga funciona como esperado é dimensionar a implementação de amostra, enviar pedidos de teste para o Ingress e verificar se o número correto de réplicas responde.
Dimensione a implementação
neg-demo-app
de uma instância para duas instâncias:kubectl scale deployment neg-demo-app --replicas 2
Este comando pode demorar alguns minutos a ser concluído.
Verifique se a implementação está concluída:
kubectl get deployment neg-demo-app
A saída deve incluir duas réplicas disponíveis:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE neg-demo-app 2 2 2 2 26m
Obtenha o endereço IP de entrada:
kubectl describe ingress neg-demo-ing
Se este comando devolver um erro 404, aguarde alguns minutos para que o balanceador de carga seja iniciado e, em seguida, tente novamente.
Conte o número de respostas distintas do equilibrador de carga:
for i in `seq 1 100`; do \ curl --connect-timeout 1 -s IP_ADDRESS && echo; \ done | sort | uniq -c
Substitua
IP_ADDRESS
pelo endereço IP de entrada.O resultado é semelhante ao seguinte:
44 neg-demo-app-7f7dfd7bc6-dcn95 56 neg-demo-app-7f7dfd7bc6-jrmzf
Neste resultado, o número de respostas distintas é igual ao número de réplicas, o que indica que todos os pods de back-end estão a publicar tráfego.
Limpar
Depois de concluir as tarefas nesta página, siga estes passos para remover os recursos e evitar a incorrência de encargos indesejados na sua conta:
Elimine o cluster
gcloud
gcloud container clusters delete neg-demo-cluster
Consola
Aceda à página do Google Kubernetes Engine na Trusted Cloud consola.
Selecione neg-demo-cluster e clique em delete Eliminar.
Quando lhe for pedido que confirme, clique em Eliminar.
Resolução de problemas
Use as técnicas abaixo para validar a configuração de rede. As secções seguintes explicam como resolver problemas específicos relacionados com o balanceamento de carga nativo do contentor.
Consulte a documentação sobre o equilíbrio de carga para saber como listar os grupos de pontos finais de rede.
Pode encontrar o nome e as zonas do NEG que correspondem a um serviço na anotação
neg-status
do serviço. Obtenha a especificação do serviço com:kubectl get svc SVC_NAME -o yaml
A anotação
metadata:annotations:cloud.google.com/neg-status
indica o nome do NEG correspondente do serviço e as zonas do NEG.Pode verificar o estado do serviço de back-end que corresponde a um NEG com o seguinte comando:
gcloud compute backend-services --project PROJECT_NAME \ get-health BACKEND_SERVICE_NAME --global
O serviço de back-end tem o mesmo nome que o respetivo NEG.
Para imprimir os registos de eventos de um serviço:
kubectl describe svc SERVICE_NAME
A string do nome do serviço inclui o nome e o espaço de nomes do serviço do GKE correspondente.
Não é possível criar um cluster com IPs de alias
- Sintomas
Quando tenta criar um cluster com IPs de alias, pode encontrar o seguinte erro:
ResponseError: code=400, message=IP aliases cannot be used with a legacy network.
- Potenciais causas
Encontra este erro se tentar criar um cluster com IPs de alias que também use uma rede antiga.
- Resolução
Certifique-se de que não cria um cluster com IPs de alias e uma rede antiga ativada em simultâneo. Para mais informações sobre a utilização de IPs de alias, consulte o artigo Crie um cluster nativo da VPC.
O tráfego não chega aos pontos finais
- Sintomas
- Erros 502/503 ou ligações rejeitadas.
- Potenciais causas
Geralmente, os novos pontos finais ficam acessíveis depois de os associar ao equilibrador de carga, desde que respondam às verificações de estado. Pode encontrar erros 502 ou ligações rejeitadas se o tráfego não conseguir alcançar os pontos finais.
Os erros 502 e as ligações rejeitadas também podem ser causados por um contentor que não processa
SIGTERM
. Se um contentor não processar explicitamenteSIGTERM
, termina imediatamente e deixa de processar pedidos. O balanceador de carga continua a enviar tráfego de entrada para o contentor terminado, o que gera erros.O balanceador de carga nativa do contentor só tem um ponto final de back-end. Durante uma atualização gradual, o ponto final antigo é desprogramado antes de o novo ponto final ser programado.
Os pods de back-end são implementados numa nova zona pela primeira vez após o aprovisionamento de um equilibrador de carga nativo do contentor. A infraestrutura do balanceador de carga é programada numa zona quando existe, pelo menos, um ponto final na zona. Quando um novo ponto final é adicionado a uma zona, a infraestrutura do balanceador de carga é programada e causa interrupções do serviço.
- Resolução
Configure os contentores para processarem
SIGTERM
e continuarem a responder a pedidos durante o período de tolerância de encerramento (30 segundos por predefinição). Configure os pods para começarem a falhar nas verificações de funcionamento quando receberemSIGTERM
. Isto indica ao balanceador de carga que pare de enviar tráfego para o pod enquanto a desprogramação do ponto final está em curso.Se a sua aplicação não for encerrada corretamente e deixar de responder a pedidos quando receber um
SIGTERM
, pode usar o preStop hook para processar oSIGTERM
e continuar a publicar tráfego enquanto a desprogramação do ponto final está em curso.lifecycle: preStop: exec: # if SIGTERM triggers a quick exit; keep serving traffic instead command: ["sleep","60"]
Consulte a documentação sobre a terminação de pods.
Se o back-end do equilibrador de carga tiver apenas uma instância, configure a estratégia de implementação para evitar a desativação da única instância antes de a nova instância estar totalmente programada. Para pods de aplicações geridos pela carga de trabalho
Deployment
, isto pode ser conseguido configurando a estratégia de implementação com o parâmetromaxUnavailable
igual a0
.strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0
Para resolver problemas relacionados com o tráfego que não chega aos pontos finais, verifique se as regras da firewall permitem o tráfego TCP de entrada para os seus pontos finais nos intervalos
130.211.0.0/22
e35.191.0.0/16
. Para saber mais, consulte o artigo Adicionar verificações de funcionamento na documentação do Cloud Load Balancing.Veja os serviços de back-end no seu projeto. A string de nome do serviço de back-end relevante inclui o nome e o espaço de nomes do serviço do GKE correspondente:
gcloud compute backend-services list
Obtenha o estado de funcionamento do back-end do serviço de back-end:
gcloud compute backend-services get-health BACKEND_SERVICE_NAME
Se todos os back-ends estiverem em mau estado, a sua firewall, Ingress ou serviço podem estar incorretamente configurados.
Se alguns back-ends estiverem em mau estado durante um curto período, a latência de programação de rede pode ser a causa.
Se alguns back-ends não aparecerem na lista de serviços de back-end, a latência de programação pode ser a causa. Pode verificar isto executando o seguinte comando, em que
NEG_NAME
é o nome do serviço de back-end. (Os NEGs e os serviços de back-end partilham o mesmo nome):gcloud compute network-endpoint-groups list-network-endpoints NEG_NAME
Verifique se todos os pontos finais esperados estão no NEG.
Se tiver um pequeno número de back-ends (por exemplo, 1 pod) selecionados por um balanceador de carga nativo de contentores, pondere aumentar o número de réplicas e distribuir os pods de back-end por todas as zonas abrangidas pelo cluster do GKE. Isto garante que a infraestrutura do balanceador de carga subjacente está totalmente programada. Caso contrário, considere restringir os pods de back-end a uma única zona.
Se configurar uma política de rede para o ponto final, certifique-se de que a entrada da sub-rede só de proxy é permitida.
Implementação interrompida
- Sintomas
- A implementação de uma atualização é interrompida e o número de réplicas atualizadas não corresponde ao número desejado de réplicas.
- Potenciais causas
As verificações de funcionamento da implementação estão a falhar. A imagem do contentor pode estar danificada ou a verificação de estado pode estar configurada incorretamente. A substituição progressiva de Pods aguarda até que o Pod iniciado recentemente passe o respetivo indicador de disponibilidade do Pod. Isto só ocorre se o pod estiver a responder às verificações de funcionamento do balanceador de carga. Se o pod não responder ou se a verificação do estado estiver configurada incorretamente, as condições do gate de prontidão não podem ser cumpridas e a implementação não pode continuar.
Se estiver a usar a versão
kubectl
1.13 ou superior, pode verificar o estado das readiness gates de um pod com o seguinte comando:kubectl get pod POD_NAME -o wide
Verifique a coluna
READINESS GATES
.Esta coluna não existe no
kubectl
1.12 e inferior. Um pod marcado como estando no estadoREADY
pode ter um portão de prontidão com falhas. Para verificar esta situação, use o seguinte comando:kubectl get pod POD_NAME -o yaml
As portas de prontidão e o respetivo estado são apresentados no resultado.
- Resolução
Verifique se a imagem do contentor na especificação do pod da sua implementação está a funcionar corretamente e se consegue responder às verificações de estado. Verifique se as verificações de estado estão configuradas corretamente.
Erros do modo degradado
- Sintomas
A partir da versão 1.29.2-gke.1643000 do GKE, pode receber os seguintes avisos no seu serviço no Explorador de registos quando os NEGs são atualizados:
Entering degraded mode for NEG <service-namespace>/<service-name>-<neg-name>... due to sync err: endpoint has missing nodeName field
- Potenciais causas
Estes avisos indicam que o GKE detetou configurações incorretas de pontos finais durante uma atualização do NEG com base em objetos
EndpointSlice
, o que aciona um processo de cálculo mais detalhado denominado modo degradado. O GKE continua a atualizar os NEGs com base no melhor esforço, corrigindo a configuração incorreta ou excluindo os pontos finais inválidos das atualizações do NEG.Seguem-se alguns erros comuns:
endpoint has missing pod/nodeName field
endpoint corresponds to an non-existing pod/node
endpoint information for attach/detach operation is incorrect
- Resolução
Normalmente, os estados transitórios causam estes eventos e são corrigidos automaticamente. No entanto, os eventos causados por configurações incorretas em objetos
EndpointSlice
personalizados permanecem não resolvidos. Para compreender a configuração incorreta, examine os objetosEndpointSlice
correspondentes ao serviço:kubectl get endpointslice -l kubernetes.io/service-name=<service-name>
Valide cada ponto final com base no erro no evento.
Para resolver o problema, tem de modificar manualmente os objetos
EndpointSlice
. A atualização aciona novamente a atualização dos NEGs. Assim que o erro de configuração deixar de existir, o resultado é semelhante ao seguinte:NEG <service-namespace>/<service-name>-<neg-name>... is no longer in degraded mode
Problemas conhecidos
O balanceamento de carga nativa do contentor no GKE tem os seguintes problemas conhecidos:
Condição de corrida do portão de prontidão do NEG
Em determinadas condições, os gates de prontidão podem devolver um "falso positivo" de estado pronto antes de a verificação de estado de entrada comunicar um estado saudável, gerando eventos de erro como os seguintes no objeto de entrada:
NEG is not attached to any BackendService with health checking. Marking condition "cloud.google.com/load-balancer-neg-ready" to True.
Sintomas
Este problema faz com que o balanceador de carga comunique um erro 503
(failed_to_pick_backend
) ao tráfego enquanto o GKE está a realizar a atualização contínua na carga de trabalho de implementação.
Causas
Embora o controlador NEG do GKE se baseie nas informações de verificação de funcionamento do NEG do Compute Engine para comunicar se o ponto final está em bom estado, considere a seguinte sequência de eventos:
- É criado um novo pod a partir de uma atualização contínua.
- O controlador NEG do GKE adiciona este novo endereço IP do pod ao grupo de pontos finais da rede.
- O controlador NEG do GKE pede o estado de funcionamento no ponto final adicionado recentemente.
- O serviço NEG do Compute Engine ainda não tem informações de estado de funcionamento e devolve um estado vazio.
- O controlador NEG do GKE assume que um estado vazio significa que não está configurada nenhuma verificação de estado e marca o pod como pronto.
- O GKE remove o pod antigo, pensando que o novo está pronto para servir tráfego.
- Se o novo pod for o único back-end restante para o balanceador de carga, o balanceador de carga devolve uma resposta
503 Service Unavailable
. - Assim que o pod começar a passar na respetiva verificação de estado, o equilibrador de carga começa a devolver respostas
200 OK
conforme esperado.
O controlador NEG do GKE não consegue distinguir entre dois estados de verificação de funcionamento diferentes: missing-health-check-because-not-attached-to-backend e missing-health-check-because-health-check-is-not-yet-programmed.
Uma vez que o controlador do NEG não consegue fazer esta distinção, o controlador do NEG do GKE tem de presumir que, se nenhum dos pontos finais do NEG tiver informações de verificação de estado, este NEG não pertence a nenhum BackendService.
Embora este cenário seja improvável, ter um número relativamente pequeno de pods (por exemplo, 2) em comparação com o número de NEGs aumenta o risco desta condição de corrida. Lembre-se de que os GNEs são criados para cada região, com um GNE por zona, o que normalmente resulta em três GNEs.
O corolário é que, se existir um número relativamente maior de agrupamentos, de modo que cada NEG tenha sempre vários agrupamentos antes do início da atualização contínua, é muito improvável que esta condição de concorrência seja acionada.
Resoluções:
A melhor forma de evitar esta condição de corrida (e, em última análise, evitar respostas 503 Service Unavailable
durante as atualizações contínuas) é ter mais back-ends no grupo de pontos finais de rede.
Certifique-se de que a estratégia de atualização contínua está configurada para garantir que, pelo menos, 1 Pod está sempre em execução.
Por exemplo, se apenas 2 pods forem executados normalmente, uma configuração de exemplo pode ter o seguinte aspeto:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
O exemplo anterior é uma sugestão. Tem de atualizar a estratégia com base em vários fatores, como o número de réplicas.
Recolha de lixo incompleta
O GKE recolhe o lixo dos balanceadores de carga nativos do contentor a cada dois minutos. Se um cluster for eliminado antes de os equilibradores de carga serem totalmente removidos, tem de eliminar manualmente os NEGs do equilibrador de carga.
Veja os NEGs no seu projeto executando o seguinte comando:
gcloud compute network-endpoint-groups list
No resultado do comando, procure os NEGs relevantes.
Para eliminar um NEG, execute o seguinte comando, substituindo NEG_NAME
pelo nome do NEG:
gcloud compute network-endpoint-groups delete NEG_NAME
Alinhe as implementações de cargas de trabalho com a propagação de pontos finais
Quando implementa uma carga de trabalho no cluster ou quando atualiza uma carga de trabalho existente, o balanceador de carga nativo de contentores pode demorar mais tempo a propagar novos pontos finais do que a concluir a implementação da carga de trabalho. A implementação de exemplo que implementar neste guia usa dois campos para alinhar a respetiva implementação com a propagação de pontos finais: terminationGracePeriodSeconds
e minReadySeconds
.
terminationGracePeriodSeconds
permite que o pod seja
desligado corretamente, aguardando que as ligações terminem depois de um pod ser
agendado para eliminação.
minReadySeconds
adiciona um período de latência após a criação de um Pod. Especifica um número mínimo de segundos durante os quais um novo Pod deve estar no estado Ready
, sem que nenhum dos respetivos contentores falhe, para que o Pod seja considerado disponível.
Deve configurar os valores minReadySeconds
e terminationGracePeriodSeconds
das suas cargas de trabalho para 60 segundos ou mais para garantir que o serviço não é interrompido devido a implementações de cargas de trabalho.
terminationGracePeriodSeconds
está disponível em todas as especificações de agrupamentos e minReadySeconds
está disponível para implementações e DaemonSets.
Para saber mais acerca do ajuste preciso das implementações, consulte a RollingUpdateStrategy.
initialDelaySeconds
no grupo de anúncios readinessProbe
não respeitado
Pode esperar que a configuração initialDelaySeconds
no readinessProbe
do pod seja respeitada pelo balanceador de carga nativo do contentor. No entanto, o readinessProbe
é implementado pelo kubelet, e a configuração initialDelaySeconds
controla a verificação de estado do kubelet e não o balanceador de carga nativo do contentor. O balanceamento de carga nativa do contentor tem a sua própria verificação do estado de funcionamento do balanceamento de carga.
O que se segue?
- Saiba mais sobre os NEGs.
- Saiba mais sobre os clusters nativos de VPC.