BLOG | NGINX

Balanceamento de carga de serviços Kubernetes com NGINX Plus

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Miniatura de Michael Pleshakov
Michael Pleshakov
Publicado em 17 de novembro de 2015

Kubernetes é um sistema de código aberto desenvolvido pelo Google para executar e gerenciar aplicativos baseados em microsserviços em contêineres em um cluster. Pessoas que usam o Kubernetes geralmente precisam tornar os serviços que criam no Kubernetes acessíveis de fora do cluster do Kubernetes.

Embora o Kubernetes forneça soluções integradas para expor serviços, descritas em Expondo serviços do Kubernetes com soluções integradas abaixo, essas soluções limitam você ao balanceamento de carga da Camada 4 ou ao balanceamento de carga HTTP round-robin.

Esta postagem mostra como usar o NGINX Plus como uma solução avançada de balanceamento de carga da Camada 7 para expor serviços do Kubernetes à Internet, esteja você executando o Kubernetes na nuvem ou em sua própria infraestrutura.

Vamos supor que você tenha um conhecimento básico do Kubernetes (pods, serviços, controladores de replicação e rótulos) e um cluster do Kubernetes em execução. Para saber mais sobre o Kubernetes, consulte o guia do usuário oficial do Kubernetes .

Expondo serviços do Kubernetes com soluções integradas

O Kubernetes oferece diversas opções para expor serviços . Dois deles – NodePort e LoadBalancer – correspondem a um tipo específico de serviço. Uma terceira opção, a Ingress API, ficou disponível como beta na versão 1.1 do Kubernetes.

Porta do nó

Especificar o tipo de serviço como NodePort torna o serviço disponível na mesma porta em cada nó do Kubernetes. Para expor o serviço à Internet, você expõe um ou mais nós nessa porta. Para alta disponibilidade, você pode expor vários nós e usar o balanceamento de carga baseado em DNS para distribuir o tráfego entre eles, ou pode colocar os nós atrás de um balanceador de carga de sua escolha.

Quando o tráfego de entrada atinge um nó na porta, sua carga é balanceada entre os pods do serviço. O balanceamento de carga feito pelo proxy de rede do Kubernetes ( kube-proxy ) em execução em cada nó é limitado ao balanceamento de carga TCP/UDP.

Balanceador de carga

Especificar o tipo de serviço como LoadBalancer aloca um balanceador de carga na nuvem que distribui o tráfego de entrada entre os pods do serviço.

A solução LoadBalancer é suportada apenas por determinados provedores de nuvem e pelo Google Container Engine e não está disponível se você estiver executando o Kubernetes em sua própria infraestrutura. Além disso, o Kubernetes só permite que você configure o balanceamento de carga TCP round-robin, mesmo que o balanceador de carga na nuvem tenha recursos avançados, como persistência de sessão ou mapeamento de solicitações.

API de entrada

A criação de um recurso do Ingress permite que você exponha serviços à Internet em URLs personalizadas (por exemplo, serviço A na URL /foo e serviço B na URL /bar ) e vários nomes de host virtual (por exemplo, foo.example.com para um grupo de serviços e bar.example.com para outro grupo). Um controlador Ingress consome um recurso Ingress e configura um balanceador de carga externo.

Um controlador Ingress não faz parte de uma implantação padrão do Kubernetes: você precisa escolher o controlador que melhor atende às suas necessidades ou implementar um você mesmo e adicioná-lo ao seu cluster Kubernetes. Muitas implementações de controladores devem aparecer em breve, mas por enquanto a única implementação disponível é o controlador para o Google Compute Engine HTTP Load Balancer , que funciona somente se você estiver executando o Kubernetes no Google Compute Engine ou no Google Container Engine . A API do Ingress oferece suporte apenas ao balanceamento de carga HTTP round-robin, mesmo que o balanceador de carga real ofereça suporte a recursos avançados.

No momento em que este artigo foi escrito, tanto a API Ingress quanto o controlador do balanceador de carga HTTP do Google Compute Engine estavam em beta.

Atualização – O NGINX Ingress Controller para NGINX e NGINX Plus agora está disponível em nosso repositório GitHub . Para obter detalhes do produto, consulte NGINX Ingress Controller .

Embora as soluções mencionadas acima sejam simples de configurar e funcionem imediatamente, elas não fornecem nenhum recurso avançado, especialmente recursos relacionados ao balanceamento de carga da Camada 7.

Expondo serviços do Kubernetes com NGINX Plus

[Editor – Esta seção foi atualizada para se referir à API NGINX Plus , que substitui e desaprova o módulo de configuração dinâmica separado originalmente discutido aqui.]

Para integrar o NGINX Plus com o Kubernetes, precisamos garantir que a configuração do NGINX Plus permaneça sincronizada com o Kubernetes, refletindo alterações nos serviços do Kubernetes, como adição ou exclusão de pods. Com o NGINX Open Source, você modifica manualmente o arquivo de configuração do NGINX e faz um recarregamento da configuração. Com o NGINX Plus, há duas maneiras de atualizar a configuração dinamicamente:

  • Com APIs – Este método usa a API do NGINX Plus para adicionar e remover entradas para pods do Kubernetes na configuração do NGINX Plus e a API do Kubernetes para recuperar os endereços IP dos pods. Esse método exige que escrevamos algum código e não o discutiremos em detalhes aqui. Para mais detalhes, assista ao webinar de Kelsey Hightower, Bringing Kubernetes to the Edge with NGINX Plus , no qual ele explora as APIs e cria um aplicativo que as utiliza.
  • Reresolvendo nomes DNS – Este método requer apenas uma configuração única adequada do NGINX Plus, conforme descrito na seção a seguir.

Utilizando a reconfiguração baseada em DNS

Presumimos que você já tenha um cluster Kubernetes em execução e um host com o utilitário kubectl disponível para gerenciar o cluster; para obter instruções, consulte o guia de primeiros passos do Kubernetes para seu tipo de cluster. Você também precisa ter criado uma imagem Docker do NGINX Plus, e as instruções estão disponíveis em Implantando o NGINX e o NGINX Plus com o Docker em nosso blog.

Aqui está um esboço do que faremos:

  1. Configure um pod NGINX Plus para expor e balancear a carga do serviço que estamos criando na Etapa 2.
  2. Crie um aplicativo web simples como nosso serviço.
  3. Aumente ou diminua o serviço e observe como o NGINX Plus é reconfigurado automaticamente.

Notas: Testamos a solução descrita neste blog com o Kubernetes 1.0.6 em execução no Google Compute Engine e uma configuração local do Vagrant , que é o que estamos usando abaixo.

Nos comandos, valores que podem ser diferentes para sua configuração do Kubernetes aparecem em itálico.

Configurando o NGINX Plus Pod

Estamos colocando o NGINX Plus em um pod do Kubernetes em um nó que expomos à Internet. Nosso pod é criado por um controlador de replicação, que também estamos configurando. Nosso arquivo de configuração NGINX Plus específico do Kubernetes reside em uma pasta compartilhada entre o pod NGINX Plus e o nó, o que o torna mais simples de manter.

Escolhendo um nó para hospedar o NGINX Plus Pod

Para designar o nó onde o pod NGINX Plus é executado, adicionamos um rótulo a esse nó. Obtemos a lista de todos os nós executando:

$ kubectl get nodes NOME RÓTULOS STATUS 10.245.1.3 Kubernetes.io/hostname=10.245.1.3 Pronto 10.245.1.4 Kubernetes.io/hostname=10.245.1.4 Pronto 10.245.1.5 Kubernetes.io/hostname=10.245.1.5 Pronto

Escolhemos o primeiro nó e adicionamos um rótulo a ele executando:

$ kubectl rótulo nó10.245.1.3 função=nginxplus

Configurando o controlador de replicação para o pod NGINX Plus

Não estamos criando um pod NGINX Plus diretamente, mas sim por meio de um controlador de replicação. Configuramos o controlador de replicação para o pod NGINX Plus em um arquivo de declaração do Kubernetes chamado nginxplus-rc.yaml .

  • Definimos o número de réplicas como um, o que significa que o Kubernetes garante que um pod NGINX Plus esteja sempre em execução: se o pod falhar, ele será substituído por um novo pod.
  • No campo nodeSelector , especificamos que o pod NGINX Plus é criado em um nó rotulado com a função: nginxplus .
  • Nosso contêiner NGINX Plus expõe duas portas, 80 e 8080, e configuramos um mapeamento entre elas e as portas 80 e 8080 no nó.
  • Nosso contêiner NGINX Plus também compartilha a pasta /etc/nginx/conf.d que reside no nó. Conforme explicado mais adiante em Configurando o NGINX Plus , compartilhar a pasta nos permite reconfigurar o NGINX Plus sem reconstruir a imagem do contêiner.
apiVersão: v1
tipo: ReplicationController
metadados:
nome: nginxplus-rc
especificação:
réplicas: 1
seletor:
aplicativo: nginxplus
modelo:
metadados:
rótulos:
aplicativo: nginxplus
especificação:
nodeSelector:
função: nginxplus
contêineres:
- nome: nginxplus
imagePullPolicy: IfNotPresent
imagem: nginxplus
portas:
- nome: http
containerPort: 80
porta do host: 80
- nome: http-alt
containerPort: 8080
porta do host: 8080
volumeMounts:
- mountPath: "/etc/nginx/conf.d"
nome: etc-nginx-confd
volumes:
- hostPath:
caminho: "/etc/nginx/conf.d"
nome: etc-nginx-confd

Tornando a imagem do Docker do NGINX Plus disponível no nó

Como dissemos acima, já construímos uma imagem Docker do NGINX Plus. Agora o disponibilizamos no nó. Para simplificar, não usamos um repositório privado do Docker e apenas carregamos manualmente a imagem no nó.

No host onde criamos a imagem do Docker, executamos o seguinte comando para salvar a imagem em um arquivo:

$ docker save -o nginxplus.tar nginxplus

Transferimos nginxplus.tar para o nó e executamos o seguinte comando no nó para carregar a imagem do arquivo:

$ docker load -i nginxplus.tar

Configurando o NGINX Plus

Na pasta /etc/nginx do contêiner NGINX Plus, estamos mantendo o arquivo de configuração principal padrão nginx.conf que vem com os pacotes NGINX Plus. A diretiva include no arquivo padrão lê outros arquivos de configuração da pasta /etc/nginx/conf.d . Conforme especificado no arquivo de declaração do controlador de replicação NGINX Plus ( nginxplus-rc.yaml ), estamos compartilhando a pasta /etc/nginx/conf.d no nó NGINX Plus com o contêiner. O compartilhamento significa que podemos fazer alterações nos arquivos de configuração armazenados na pasta (no nó) sem precisar reconstruir a imagem do Docker do NGINX Plus, o que teríamos que fazer se criássemos a pasta diretamente no contêiner. Colocamos nosso arquivo de configuração específico do Kubernetes ( backend.conf ) na pasta compartilhada.

Primeiro, vamos criar a pasta /etc/nginx/conf.d no nó.

$ sudo mkdir -p /etc/nginx/conf.d

Então criamos o arquivo backend.conf e incluímos estas diretivas:

  • resolver – Define o servidor DNS que o NGINX Plus usa para resolver periodicamente o nome de domínio que usamos para identificar nossos servidores upstream (na diretiva server dentro do bloco upstream , discutido no próximo tópico). Identificamos este servidor DNS pelo seu nome de domínio, kube-dns.kube-system.svc.cluster.local . O parâmetro válido informa ao NGINX Plus para enviar a solicitação de nova resolução a cada cinco segundos.

    (Observe que o processo de resolução para esta diretiva difere daquele para servidores upstream: este nome de domínio é resolvido somente quando o NGINX inicia ou recarrega, e o NGINX Plus usa o servidor DNS do sistema ou servidores definidos no arquivo /etc/resolv.conf para resolvê-lo.)

  • upstream – Cria um grupo upstream chamado backend para conter os servidores que fornecem o serviço Kubernetes que estamos expondo. Em vez de listar os servidores individualmente, nós os identificamos com um nome de host totalmente qualificado em uma única diretiva de servidor . O parâmetro resolve informa ao NGINX Plus para resolver novamente o nome do host em tempo de execução, de acordo com as configurações especificadas com a diretiva resolver .

    Como o Kubernetes DNS e o NGINX Plus (R10 e posteriores) oferecem suporte a registros de serviço DNS ( SRV ), o NGINX Plus pode obter os números de porta dos servidores upstream via DNS. Incluímos o parâmetro de serviço para que o NGINX Plus solicite registros SRV , especificando o nome ( _http ) e o protocolo ( _tcp ) para as portas expostas pelo nosso serviço. Declaramos esses valores no arquivo webapp-svc.yaml discutido em Criando o Controlador de Replicação para o Serviço abaixo.

    Para obter mais informações sobre descoberta de serviços com DNS, consulte Usando DNS para descoberta de serviços com NGINX e NGINX Plus em nosso blog.

  • servidor (duas vezes) – Defina dois servidores virtuais:

    • O primeiro servidor escuta na porta 80 e balanceia a carga das solicitações recebidas para /webapp (nosso serviço) entre os pods que executam instâncias de serviço. Também realizamos verificações de saúde ativas .

    • O segundo servidor escuta na porta 8080. Aqui configuramos o monitoramento de atividade ao vivo do NGINX Plus. Mais tarde, usaremos isso para verificar se o NGINX Plus foi reconfigurado corretamente.

      [Editor – A configuração deste segundo servidor foi atualizada para usar a API NGINX Plus , que substitui e descontinua o módulo de status separado usado originalmente.]

resolver kube-dns.kube-system.svc.cluster.local valid=5s;

backend upstream {
zona backend upstream 64k;
servidor webapp-svc.default.svc.cluster.local service=_http._tcp resolve;
}

servidor {
ouvir 80;
zona_de_status servidores-backend;

localização /webapp {
proxy_pass http://backend;
verificação_de_saúde;
}
}

servidor {
ouvir 8080;
raiz /usr/share/nginx/html;

localização = /dashboard.html { }

localização = / {
retornar 302 /dashboard.html;
}

localização /api {
api write=on;
}
}

Criando o Controlador de Replicação

Agora estamos prontos para criar o controlador de replicação executando este comando:

$ kubectl criar -f nginxplus-rc.yaml

Para verificar se o pod NGINX Plus foi criado, executamos:

$ kubectl get pods NOME PRONTO STATUS REINÍCIOS IDADE nginxplus-rc-0ts5t 1/1 Em execução 0 17s

Estamos executando o Kubernetes em uma configuração local do Vagrant, então sabemos que o endereço IP externo do nosso nó é 10.245.1.3 e usaremos esse endereço para o restante deste exemplo. Se você estiver executando o Kubernetes em um provedor de nuvem, poderá obter o endereço IP externo do seu nó executando:

$ kubectl obter nós nome-do-nó -o json | grep -i IPExterno -A 1 "tipo": "IP externo", "endereço": XXX.XXX.XXX.XXX

Se você estiver executando em uma nuvem, não se esqueça de configurar uma regra de firewall para permitir que o nó NGINX Plus aceite tráfego de entrada. Consulte a documentação do seu provedor de nuvem.

Podemos verificar se nosso pod NGINX Plus está instalado e funcionando observando o painel de monitoramento de atividades ao vivo do NGINX Plus, que está disponível na porta 8080 no endereço IP externo do nó (portanto, http://10.245.1.3:8080/dashboard.html no nosso caso). No entanto, se olharmos para este ponto, não vemos nenhum servidor para o nosso serviço, porque ainda não criamos o serviço.

O painel de monitoramento de atividades ao vivo do NGINX Plus antes de criarmos os serviços do Kubernetes

Criando um serviço Kubernetes simples

Agora é hora de criar um serviço Kubernetes. Nosso serviço consiste em dois servidores web, cada um servindo uma página web com informações sobre o contêiner em que estão sendo executados.

Criando o Controlador de Replicação para o Serviço

Primeiro, criamos um controlador de replicação para que o Kubernetes garanta que o número especificado de réplicas de servidor web (pods) esteja sempre em execução no cluster. Aqui está o arquivo de declaração ( webapp-rc.yaml ):

apiVersão: v1kind: ReplicationController
metadados:
nome: webapp-rc
especificação:
réplicas: 2
seletor:
aplicativo: webapp
modelo:
metadados:
rótulos:
aplicativo: webapp
especificação:
contêineres:
- nome: hello
imagem: nginxdemos/hello 
portas:
- containerPort: 80

Nosso controlador consiste em dois servidores web. Declaramos um controlador composto por pods com um único contêiner, expondo a porta 80. A imagem nginxdemos/hello será extraída do Docker Hub.

Para criar o controlador de replicação, executamos o seguinte comando:

$ kubectl criar -f webapp-rc.yaml

Para verificar se nossos pods foram criados, podemos executar o seguinte comando. Usamos o seletor de rótulos app=webapp para obter apenas os pods criados pelo controlador de replicação na etapa anterior:

$ kubectl get pods -l app=webapp NOME PRONTO STATUS REINÍCIOS IDADE webapp-rc-544f1 1/1 Em execução 0 2m webapp-rc-uk6pm 1/1 Em execução 0 2m

Criando o serviço

Em seguida, criamos um serviço para os pods criados pelo nosso controlador de replicação. Declaramos o serviço com o seguinte arquivo ( webapp-service.yaml ):

apiVersão: v1kind: Serviço
metadados:
nome: webapp-svc
especificação:
clusterIP: Nenhum
portas:
- porta: 80
Porta de destino: 80
protocolo: TCP
nome: http
seletor:
aplicativo: webapp

Aqui estamos declarando um serviço headless especial definindo o campo ClusterIP como Nenhum . Com esse tipo de serviço, um endereço IP de cluster não é alocado e o serviço não fica disponível por meio do proxy kube. Uma consulta DNS ao DNS do Kubernetes retorna vários registros A (os endereços IP dos nossos pods).

Também declaramos a porta que o NGINX Plus usará para conectar os pods. Além de especificar a porta e os números da porta de destino, especificamos o nome ( http ) e o protocolo ( TCP ). Usamos esses valores no arquivo de configuração do NGINX Plus, no qual informamos ao NGINX Plus para obter os números de porta dos pods via DNS usando registros SRV .

Ao definir o campo seletor como app: webapp , declaramos quais pods pertencem ao serviço, ou seja, os pods criados pelo nosso controlador de replicação NGINX (definido em webapp-rc.yaml ).

Executamos o seguinte comando, que cria o serviço:

$ kubectl criar -f webapp-service.yaml

Agora, se atualizarmos a página do painel e clicarmos na aba Upstreams no canto superior direito, veremos os dois servidores que adicionamos.

O painel de monitoramento de atividades ao vivo do NGINX Plus após a criação dos serviços do Kubernetes

Também podemos verificar se o NGINX Plus está balanceando o tráfego entre os pods do serviço. Se for, quando acessamos http://10.245.1.3/webapp/ em um navegador, a página nos mostra informações sobre o contêiner em que o servidor web está sendo executado, como o nome do host e o endereço IP.

Se atualizarmos esta página várias vezes e observarmos o painel de status, veremos como as solicitações são distribuídas entre os dois servidores upstream.

Escalando o serviço Kubernetes

[Editor – Esta seção foi atualizada para usar a API NGINX Plus , que substitui e descontinua o módulo de status separado usado originalmente.]

Agora vamos adicionar mais dois pods ao nosso serviço e garantir que a configuração do NGINX Plus seja atualizada automaticamente novamente. Executamos este comando para alterar o número de pods para quatro, dimensionando o controlador de replicação:

$ kubectl scale rc webapp-rc --replicas=4 dimensionado

Para verificar se o NGINX Plus foi reconfigurado, poderíamos olhar novamente o painel, mas desta vez usaríamos a API do NGINX Plus . Executamos o seguinte comando, com10.245.1.3 sendo o endereço IP externo do nosso nó NGINX Plus e3 a versão da API NGINX Plus . Para formatar ordenadamente a saída JSON, nós a canalizamos para jq .

$ curl -s10.245.1.3 :8080/api/3 /http/upstreams/backend/servidores | jq { "pares": [ { "id": 1, "servidor": "10.0.0.1:80", "backup": falso, "peso": 1, "estado": "insalubre", "ativo": 0, "solicitações": 1, "respostas": { "1xx": 0, "2xx": 0, "3xx": 0, "4xx": 0, "5xx": 0, "total": 0 }, "enviado": 0, "recebido": 0, "falha": 0, "indisponível": 0, "verificações de saúde": { "verificações": 1, "falha": 1, "insalubre": 1, "last_passed": falso }, "tempo de inatividade": 33965, "iniciante": 1445378182275, "selecionado": 1445378131000 }, { "id": 2, "servidor": "10.246.1.6:80", ... }, { "id": 3, "servidor": "10.246.3.2:80", ... { "id": 4, "servidor": "10.0.0.2:80", ... } ], "keepalive": 0 }

A matriz de pares na saída JSON tem exatamente quatro elementos, um para cada servidor web.

Agora vamos reduzir o número de pods de quatro para um e verificar o status do NGINX Plus novamente:

$ kubectl scale rc webapp-rc --replicas=1 dimensionado $ curl -s10.245.1.3 :8080/api/3 /http/upstreams/backend/servidores | jq

Agora, a matriz de pares na saída JSON contém apenas um elemento (a saída é a mesma do par com ID 1 no comando de exemplo anterior).

Agora que temos o NGINX Plus instalado e funcionando, podemos começar a aproveitar seus recursos avançados, como persistência de sessão , terminação SSL/TLS , roteamento de solicitações , monitoramento avançado e muito mais .

Resumo

As opções de reconfiguração instantânea disponíveis no NGINX Plus permitem que você o integre ao Kubernetes com facilidade: programaticamente por meio de uma API ou inteiramente por meio de DNS. Usar o NGINX Plus para expor serviços do Kubernetes à Internet fornece muitos recursos que as atuais soluções de balanceamento de carga integradas do Kubernetes não possuem.

Para explorar como o NGINX Plus funciona em conjunto com o Kubernetes, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seu caso de uso.


"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."