BLOG | NGINX

Melhores práticas para configurar aplicativos de microsserviços

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Javier Evans Miniatura
Javier Evans
Publicado em 02 de março de 2023

As diretrizes conhecidas como aplicativo dos doze fatores foram publicadas pela primeira vez há mais de dez anos. Desde então, quase todas as suas práticas obrigatórias se tornaram o padrão de fato para escrever e implantar aplicativos web. E embora elas tenham permanecido aplicáveis diante de mudanças na maneira como os aplicativos são organizados e implantados, em alguns casos são necessárias nuances adicionais para entender como as práticas se aplicam aos padrões de microsserviços para desenvolver e implantar aplicativos.

Este blog se concentra no Fator 3, Configuração da loja no ambiente , que afirma:

  • Configuração é tudo o que varia entre ambientes de implantação (que o aplicativo de doze fatores chama de implantações ).
  • A configuração deve ser estritamente separada do código do aplicativo – caso contrário, como ela pode variar entre as implantações?
  • Os dados de configuração são armazenados em variáveis de ambiente.

À medida que você avança para microsserviços, você ainda pode honrar essas diretrizes, mas nem sempre de uma forma que mapeie exatamente para uma interpretação literal do aplicativo de doze fatores. Algumas diretrizes, como fornecer dados de configuração como variáveis de ambiente, são transferidas muito bem. Outras práticas comuns de microsserviços, embora respeitem os princípios básicos do aplicativo de doze fatores, são mais como extensões dele. Nesta postagem, veremos três conceitos principais de gerenciamento de configuração para microsserviços pela lente do Fator 3:

Principais terminologias e conceitos de microsserviços

Antes de entrar na discussão sobre a adaptação do Fator 3 para microsserviços, é útil entender alguns termos e conceitos importantes.

  • Arquitetura de aplicativo monolítico – Um modelo arquitetônico tradicional que separa as funções do aplicativo em módulos de componentes, mas inclui todos os módulos em uma única base de código.
  • Arquitetura de aplicativo de microsserviços – Um modelo de arquitetura que cria um aplicativo grande e complexo a partir de vários componentes pequenos, cada um dos quais executa um conjunto bem definido de operações (como autenticação, notificação ou processamento de pagamento). “Microserviço” também é o nome dado aos próprios pequenos componentes. Na prática, alguns “microsserviços” podem ser realmente muito grandes.
  • Serviço – Um termo geral para um único aplicativo ou microsserviço em um sistema.
  • Sistema – No contexto deste blog, o conjunto completo de microsserviços e infraestrutura de suporte que se reúnem para criar a funcionalidade completa fornecida pela organização.
  • Artefato – Um objeto criado por um pipeline de teste e construção. Ele pode assumir muitas formas, como uma imagem do Docker contendo o código de um aplicativo.
  • Implantação – Uma “instância” em execução de um artefato, que é executada em um ambiente como preparação, integração ou produção.

Microsserviços versus monólitos

Com um aplicativo monolítico, todas as equipes da organização trabalham no mesmo aplicativo e na infraestrutura ao redor. Embora aplicativos monolíticos geralmente pareçam mais simples do que microsserviços no papel, há vários motivos comuns pelos quais as organizações decidem migrar para microsserviços:

  • Autonomia da equipe – Pode ser complicado definir a propriedade da funcionalidade e dos subsistemas em um monólito. À medida que as organizações crescem e amadurecem, a responsabilidade pela funcionalidade do aplicativo geralmente é distribuída entre mais e mais equipes. Isso cria dependências entre as equipes porque a equipe que possui uma parte da funcionalidade não possui todos os subsistemas relacionados no monólito.
  • Diminuindo o “raio de explosão” – Quando um aplicativo grande é desenvolvido e implantado como uma única unidade, um erro em um subsistema pode degradar a funcionalidade de todo o aplicativo.
  • Escalonamento de funcionalidade independente – Mesmo que apenas um único módulo em um aplicativo monolítico esteja sob carga pesada, a organização deve implantar muitas instâncias de todo o aplicativo para evitar falha ou degradação do sistema.

É claro que os microsserviços apresentam seus próprios desafios – incluindo maior complexidade, menos observabilidade e a necessidade de novos modelos de segurança – mas muitas organizações, especialmente as grandes ou de rápido crescimento, decidem que os desafios valem a pena para dar às suas equipes mais autonomia e flexibilidade na criação de bases confiáveis e estáveis para as experiências que fornecem aos seus clientes.

Mudanças necessárias para arquiteturas de microsserviços

Ao refatorar um aplicativo monolítico em microsserviços, seus serviços devem:

  • Aceite mudanças de configuração de forma previsível
  • Dar-se a conhecer ao sistema mais amplo de uma forma previsível
  • Esteja bem documentado

Para um aplicativo monolítico, pequenas inconsistências nos processos e dependência de suposições compartilhadas não são críticas. No entanto, com muitos microsserviços separados, essas inconsistências e suposições podem gerar muita dor e caos. Muitas das mudanças que você precisa fazer com microsserviços são necessidades técnicas, mas um número surpreendente diz respeito à forma como as equipes trabalham internamente e interagem com outras equipes.

Mudanças organizacionais notáveis com uma arquitetura de microsserviços incluem:

  • Em vez de trabalhar juntas na mesma base de código, as equipes se tornam totalmente separadas, com cada equipe totalmente responsável por um ou mais serviços. Na implementação mais comum de microsserviços, as equipes também são reorganizadas para serem “multifuncionais”, o que significa que elas têm membros com todas as competências necessárias para concluir as metas da equipe com dependências mínimas de outras equipes.
  • As equipes da plataforma (responsáveis pela integridade geral do sistema) agora precisam coordenar vários serviços de propriedade de equipes diferentes, em vez de lidar com um único aplicativo.
  • As equipes de ferramentas devem continuar a fornecer ferramentas e orientação às diversas equipes de proprietários de serviços para ajudá-las a atingir seus objetivos rapidamente, mantendo o sistema estável.

Diagrama comparando a organização de equipes de desenvolvedores para aplicativos monolíticos e de microsserviços

Definindo claramente a configuração do seu serviço

Uma área da arquitetura de microsserviços onde precisamos estender o Fator 3 diz respeito à necessidade de definir claramente certas informações vitais sobre um serviço, incluindo sua configuração, e assumir um mínimo de contexto compartilhado com outros serviços. O fator 3 não aborda isso diretamente, mas é especialmente importante com um grande número de microsserviços separados contribuindo para a funcionalidade do aplicativo.

Como proprietário de serviço em uma arquitetura de microsserviços, sua equipe possui serviços que desempenham funções específicas no sistema como um todo. Outras equipes cujos serviços interagem com os seus precisam acessar o repositório do seu serviço para ler código e documentação, bem como fazer contribuições.

Além disso, é uma realidade infeliz no campo do desenvolvimento de software que a composição da equipe muda frequentemente, não apenas porque os desenvolvedores entram e saem da empresa, mas também por causa da reorganização interna. Além disso, a responsabilidade por um determinado serviço também é frequentemente transferida entre equipes.

Em vista dessas realidades, sua base de código e documentação precisam ser extremamente claras e consistentes, o que é alcançado por:

  • Definir claramente o propósito de cada opção de configuração
  • Definir claramente o formato esperado do valor de configuração
  • Definir claramente como o aplicativo espera que os valores de configuração sejam fornecidos
  • Registrar essas informações em um número limitado de arquivos

Muitas estruturas de aplicativos fornecem um meio para definir a configuração necessária. Por exemplo, o pacote NPM convict para aplicativos Node.js usa um “esquema” de configuração completo armazenado em um único arquivo. Ele atua como a fonte da verdade para toda a configuração que um aplicativo Node.js precisa para ser executado.

Um esquema robusto e facilmente detectável facilita a interação confiante dos membros da sua equipe e de outras pessoas com seu serviço.

Como a configuração é fornecida a um serviço

Depois de definir claramente quais valores de configuração seu aplicativo precisa, você também precisa honrar a importante distinção entre as duas fontes principais das quais um aplicativo de microsserviços implantado extrai sua configuração:

  • Scripts de implantação que definem explicitamente as configurações e acompanham o código-fonte do aplicativo
  • Fontes externas consultadas no momento da implantação

Scripts de implantação são um padrão comum de organização de código em arquiteturas de microsserviços. Como são novidades desde a publicação original do aplicativo dos doze fatores, eles necessariamente representam uma extensão dele.

Padrão: Implantação e configuração de infraestrutura junto ao aplicativo

Nos últimos anos, tornou-se comum ter uma pasta chamada infraestrutura (ou alguma variante desse nome) no mesmo repositório do código do seu aplicativo. Geralmente contém:

  • Infraestrutura como código ( Terraform é um exemplo comum) que descreve a infraestrutura da qual o serviço depende, como um banco de dados
  • Configuração para seu sistema de orquestração de contêineres, como gráficos Helm e manifestos Kubernetes
  • Quaisquer outros arquivos relacionados à implantação do aplicativo

À primeira vista, isso pode parecer uma violação da prescrição do Fator 3 de que a configuração é estritamente separada do código.

Na verdade, sua colocação ao lado do seu aplicativo significa que uma pasta de infraestrutura realmente respeita a regra, ao mesmo tempo em que permite melhorias valiosas no processo, essenciais para equipes que trabalham em ambientes de microsserviços.

Os benefícios desse padrão incluem:

  • A equipe proprietária do serviço também é proprietária da implantação do serviço e da implantação da infraestrutura específica do serviço (como bancos de dados).
  • A equipe proprietária pode garantir que as alterações em qualquer um desses elementos passem pelo seu processo de desenvolvimento (revisão de código, CI).
  • A equipe pode facilmente mudar a forma como seu serviço e infraestrutura de suporte são implantados sem depender de equipes externas para trabalhar para eles.

Observe que os benefícios fornecidos por esse padrão reforçam a autonomia individual da equipe, ao mesmo tempo em que garantem que rigor adicional seja aplicado ao processo de implantação e configuração.

Que tipo de configuração vai para onde?

Na prática, você usa os scripts de implantação armazenados na sua pasta de infraestrutura para gerenciar tanto a configuração definida explicitamente nos próprios scripts quanto a recuperação da configuração de fontes externas no momento da implantação, tendo o script de implantação para um serviço:

  1. Defina certos valores de configuração diretamente
  2. Defina onde o processo que executa o script de implantação pode procurar os valores de configuração desejados em fontes externas

Valores de configuração que são específicos para uma determinada implantação do seu serviço e totalmente sob o controle da sua equipe podem ser especificados diretamente nos arquivos na pasta de infraestrutura. Um exemplo pode ser algo como um limite no tempo que uma consulta de banco de dados iniciada pelo aplicativo pode ser executada. Este valor pode ser alterado modificando o arquivo de implantação e reimplantando o aplicativo.

Um benefício desse esquema é que as alterações nessa configuração necessariamente passam por revisão de código e testes automatizados, diminuindo a probabilidade de que um valor mal configurado cause uma interrupção. Alterações nos valores que passam pela revisão de código e nos valores das chaves de configuração a qualquer momento podem ser descobertas no histórico das suas ferramentas de controle de origem.

Os valores necessários para a execução do aplicativo, mas que não estão sob o controle da sua equipe, devem ser fornecidos pelo ambiente no qual o aplicativo é implantado. Um exemplo é o nome do host e a porta na qual o serviço se conecta a outro microsserviço do qual depende.

Como esse serviço não é de propriedade da sua equipe, você não pode fazer suposições sobre valores como o número da porta. Esses valores podem mudar a qualquer momento e precisam ser registrados em algum armazenamento de configuração central quando são alterados, seja essa alteração feita manualmente ou por algum processo automático. Eles podem então ser consultados por aplicativos que dependem deles.

Podemos resumir essas diretrizes em duas práticas recomendadas para configuração de microsserviços.

Uma configuração de microsserviços não: Confie em valores codificados ou mutuamente acordados

Pode parecer mais simples codificar determinados valores em seus scripts de implantação, por exemplo, a localização de um serviço com o qual seu serviço interage. Na prática, a codificação desse tipo de configuração é perigosa, especialmente em ambientes modernos, onde os locais de serviço mudam com frequência. E é particularmente perigoso se você não possui o segundo serviço.

Você pode pensar que pode confiar em sua própria diligência para manter um local de serviço atualizado em seus scripts ou, pior, que pode confiar na equipe proprietária para informá-lo quando o local mudar. A diligência muitas vezes falha em momentos de estresse e, dependendo do rigor humano, seu sistema corre o risco de falhar sem aviso prévio.

Uma configuração de microsserviços faz: Faça com que o serviço pergunte “Onde está meu banco de dados?”

Independentemente de as informações de localização serem codificadas ou não, seu aplicativo não deve depender de infraestrutura crítica estar em um determinado local. Em vez disso, um serviço recém-implantado precisa fazer algumas perguntas comuns dentro do sistema, como "onde está meu banco de dados?" e receber uma resposta precisa sobre a localização atual desse recurso externo. Fazer com que cada serviço se registre no sistema à medida que é implantado torna as coisas muito mais simples.

Disponibilizando um serviço como configuração

Assim como o sistema precisa fornecer respostas às perguntas "onde está meu banco de dados?" e "onde está o 'serviço X' do qual estou dependendo?", um serviço deve ser exposto ao sistema de tal forma que outros serviços possam facilmente encontrá-lo e falar com ele sem saber nada sobre como ele é implantado.

Uma prática de configuração fundamental em arquiteturas de microsserviços é a descoberta de serviços: o registro de novas informações de serviço e a atualização dinâmica dessas informações conforme acessadas por outros serviços. Depois de explicar por que a descoberta de serviços é necessária para microsserviços, vamos explorar um exemplo de como realizá-la com NGINX Open Source e Consul.

É uma prática comum ter várias instâncias (implantações) de um serviço em execução ao mesmo tempo. Isso permite não apenas o manuseio de tráfego adicional, mas também a atualização de um serviço sem tempo de inatividade por meio do lançamento de uma nova implantação. Atuando como proxy reverso e balanceador de carga, ferramentas como o NGINX processam o tráfego de entrada e o roteiam para a instância mais apropriada. Esse é um bom padrão, porque os serviços que dependem do seu serviço enviam solicitações somente ao NGINX e não precisam saber nada sobre suas implantações.

Por exemplo, digamos que você tenha uma única instância de um serviço chamado messenger em execução no NGINX, atuando como um proxy reverso.

Diagrama de uma única instância do microsserviço 'messenger' sendo proxy reverso pelo NGINX

E se seu aplicativo se tornar popular? Isso é considerado uma boa notícia, mas então você percebe que, devido ao aumento do tráfego, a instância do messenger está consumindo muita CPU e demorando mais para processar solicitações, enquanto o banco de dados parece estar funcionando bem. Isso indica que você pode resolver o problema implantando outra instância do serviço de mensagens .

Quando você implanta a segunda instância do serviço de mensagens , como o NGINX sabe que ela está ativa e começa a enviar tráfego para ela? Adicionar manualmente novas instâncias à sua configuração do NGINX é uma abordagem, mas rapidamente se torna incontrolável à medida que mais serviços aumentam ou diminuem.

Uma solução comum é rastrear os serviços em um sistema com um registro de serviços de alta disponibilidade, como o Consul . Novas instâncias de serviço são registradas no Consul à medida que são implantadas. O Consul monitora o status das instâncias enviando periodicamente verificações de integridade. Quando uma instância falha nas verificações de integridade, ela é removida da lista de serviços disponíveis.

Diagrama de duas instâncias do microsserviço 'messenger' sendo proxy reverso pelo NGINX, com Consul para descoberta de serviço

O NGINX pode consultar um registro como o Consul usando uma variedade de métodos e ajustar seu roteamento adequadamente. Lembre-se de que, ao atuar como um proxy reverso ou balanceador de carga, o NGINX roteia o tráfego para servidores “upstream”. Considere esta configuração simples:


# Defina um grupo upstream chamado "messenger_service"
upstream messenger_service {
server 172.18.0.7:4000;
server 172.18.0.8:4000;
}

server {
listen 80;

location /api {
# Proxy de tráfego HTTP com caminhos começando com '/api' para o
# bloco 'upstream' acima. O algoritmo de balanceamento de carga padrão, 
# Round-Robin, alterna solicitações entre os dois servidores 
# no bloco.
proxy_pass http://messenger_service;
proxy_set_header X-Forwarded-For $remote_addr;
}
}


Por padrão, o NGINX precisa saber o endereço IP e a porta precisos de cada instância do messenger para rotear o tráfego para ela. Neste caso, é a porta 4000 em 172.18.0.7 e 172.18.0.8.

É aqui que entram o Consul e o modelo Consul . O modelo do Consul é executado no mesmo contêiner que o NGINX e se comunica com o cliente do Consul que mantém o registro de serviço.

Quando as informações do registro são alteradas, o modelo do Consul gera uma nova versão do arquivo de configuração do NGINX com os endereços IP e portas corretos, grava-o no diretório de configuração do NGINX e informa ao NGINX para recarregar sua configuração. Não há tempo de inatividade quando o NGINX recarrega sua configuração , e a nova instância começa a receber tráfego assim que a recarga é concluída.

Com um proxy reverso como o NGINX nesse tipo de situação, há um único ponto de contato para registrar no sistema como o local para outros serviços acessarem. Sua equipe tem flexibilidade para gerenciar instâncias de serviço individuais sem precisar se preocupar com outros serviços perdendo acesso ao serviço como um todo.

Coloque a mão na massa com NGINX e microsserviços em março

É certo que os microsserviços aumentam a complexidade, tanto em termos técnicos para seus serviços quanto em termos organizacionais para seus relacionamentos com outras equipes. Para aproveitar os benefícios de uma arquitetura de microsserviços, é importante reexaminar criticamente as práticas projetadas para monólitos para garantir que elas ainda forneçam os mesmos benefícios quando aplicadas a um ambiente muito diferente. Neste blog, exploramos como o Fator 3 do aplicativo de doze fatores ainda fornece valor em um contexto de microsserviços, mas pode se beneficiar de pequenas mudanças em como ele é aplicado concretamente.

Para saber mais sobre como aplicar o aplicativo de doze fatores às arquiteturas de microsserviços, confira a Unidade 1 de Microsserviços de março de 2023 ( em breve no blog ). Registre-se gratuitamente para ter acesso a um webinar sobre este tópico e a um laboratório prático.


"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."