Fomos francos com nossos objetivos de design quando revelamos a Arquitetura de Referência de Aplicativos Modernos (MARA) do NGINX na Sprint 2.0 em agosto de 2021. Queríamos criar um exemplo de uma arquitetura de aplicativo moderna em execução no Kubernetes e projetada para oferecer suporte à segurança, escalabilidade, confiabilidade, monitoramento e introspecção. Este projeto precisava ser implantável em diferentes infraestruturas com uma abordagem “plug and play” para combinar componentes funcionais sem esforços de integração demorados.
Nos meses desde a Sprint, avançamos em nosso roteiro. Como qualquer projeto, tivemos nossa cota de sucessos e fracassos e incorporamos nossos sucessos ao MARA, mantendo uma lista crescente de lições aprendidas. Esperamos evitar que outros enfrentem os mesmos problemas documentando essas questões e projetando com essas lições em mente.
Recentemente atingimos um marco com o MARA versão 1.0.0 , que reorganiza o diretório do projeto e altera o processo de instanciação e destruição do ambiente. Eliminamos código duplicado, criamos uma estrutura de diretório que acomoda facilmente adições futuras e padronizamos scripts de gerenciamento. Como esta versão marca um ponto importante na história do MARA, gostaríamos de parar e relatar à comunidade sobre nosso progresso, observar o que consideramos algumas das lições aprendidas mais importantes e fornecer algumas informações sobre nosso roteiro para o futuro.
Os principais colaboradores do MARA têm experiência na execução de software em escala e entendem o que é necessário para fornecer serviços das perspectivas operacional, de engenharia e de gerenciamento. Eles sabem a sensação desagradável que você tem quando um aplicativo não funciona bem e você não tem uma maneira fácil de determinar exatamente qual é o problema. Uma citação que circula no mundo do DevOps resume a questão sucintamente: “Depurar microsserviços é como resolver uma série de mistérios de assassinato”.
Com isso em mente, fizemos da adição de observabilidade uma prioridade máxima em nosso roteiro de curto prazo. Observabilidade neste contexto inclui gerenciamento de logs, métricas e dados de rastreamento. No entanto, apenas coletar dados não é suficiente: você deve ser capaz de analisar os dados e tomar decisões significativas sobre o que está acontecendo no ambiente.
Nossa exploração de opções de rastreamento nos levou ao OpenTelemetry (OTEL) porque ele oferece suporte a todo o escopo de dados de telemetria, registros, métricas e rastreamentos. Imaginamos uma implementação em que o agente OTEL coleta, processa e desduplica todos os dados de rastreamento antes de passá-los ao coletor OTEL para agregação e exportação, com um sistema de visualização no final do fluxo de trabalho para tornar os dados utilizáveis. Essa abordagem oferece aos usuários a mais ampla gama de opções para exibir e analisar dados, ao mesmo tempo em que aproveita o padrão OTEL para simplificar os estágios iniciais (coleta, agregação e assim por diante).
Construímos a implementação em duas etapas:
Implantar o OpenTelemetry Operator for Kubernetes para gerenciar um coletor OTEL no ambiente
Instrumentar o aplicativo Banco de Sirius para emitir rastros e métricas
A versão original do MARA usava Elasticsearch com Filebeat para registro e, embora tenhamos considerado substituí-los pelo Grafana Loki , decidimos manter a escolha original por enquanto. Em relação às métricas, percebemos que precisávamos revisar a implantação original com base no Prometheus e no Grafana , substituindo a configuração personalizada do Prometheus que usamos inicialmente pelo gráfico Helm kube-prometheus-stack mantido pela comunidade, que cria um ambiente Prometheus completo, incluindo Grafana, exportadores de nós e uma série de painéis pré-configurados e alvos de coleta adequados para gerenciar um ambiente Kubernetes. A isso adicionamos alguns painéis adicionais para o F5 NGINX Ingress Controller e o aplicativo Bank of Sirius.
Este é apenas um breve resumo da imensa quantidade de trabalho necessária para implementar o OTEL. Para poupar outros do esforço de escalar a mesma curva de aprendizado íngreme, documentamos todo o processo em Integrando o OpenTelemetry na Arquitetura de Referência de Aplicativos Modernos – Um Relatório de Progresso em nosso blog.
Na versão inicial do MARA, escolhemos o Amazon Elastic Kubernetes Service (EKS) como ambiente de implantação. Muitos usuários nos disseram que, por questões de custo, desejam executar o MARA em ambientes “locais” que exigem menos recursos, como um laboratório ou estação de trabalho. Portabilidade era um objetivo fundamental do projeto original (e continua sendo), então esta era nossa chance de provar que poderíamos alcançá-lo. Para facilitar a tarefa, decidimos projetar um procedimento de implantação que pudesse ser executado em qualquer cluster Kubernetes que atendesse a alguns requisitos mínimos.
Como primeiro passo, adicionamos um novo projeto Pulumi ao MARA que lê um arquivo kubeconfig para se comunicar com o cluster Kubernetes. Este projeto fica entre os projetos Pulumi Kubernetes e os projetos de infraestrutura (exemplos destes últimos são projetos para AWS e Digital Ocean). Em termos práticos, a criação do projeto kubeconfig reduz a barreira para integrar um novo projeto de infraestrutura. Se um projeto de infraestrutura puder passar um arquivo kubeconfig, um nome de cluster e um contexto de cluster para o projeto kubeconfig, o restante do procedimento de implantação MARA funcionará perfeitamente.
Para nossos testes, usamos várias distribuições Kubernetes fáceis de instalar com pequenos requisitos de CPU e memória, incluindo K3s , Canonical MicroK8s e minikube . Todas as distribuições foram implantadas em uma máquina virtual (VM) executando o Ubuntu 21.10 com 2 CPUs e 16 GB de RAM . Além disso, todas as distribuições foram configuradas para fornecer volumes persistentes e suporte ao Kubernetes LoadBalancer.
A parte mais difícil desse processo foi trabalhar com o registro privado usado para o NGINX Ingress Controller personalizado que faz parte do projeto. (Observe que ao implantar o MARA, você pode usar o NGINX Ingress Controller padrão baseado no NGINX Open Source ou NGINX Plus, bem como este NGINX Ingress Controller personalizado.) Descobrimos que precisávamos desacoplar nossa lógica de registro do Amazon Elastic Container Registry (ECR) em favor de uma abordagem mais independente de plataforma, uma tarefa que está em andamento. Também percebemos que nossa lógica para extrair o nome do host do endereço de saída era muito específica do AWS Elastic Load Balancing (ELB) e precisava ser reescrita para ser aplicada a outros casos de uso.
Os scripts de gerenciamento MARA e os projetos Pulumi atualmente usam alguma lógica específica para contornar os problemas descritos acima. Por enquanto, as implantações baseadas na configuração do Kubernetes devem usar o NGINX Ingress Controller (com base no NGINX Open Source ou no NGINX Plus) dos registros oficiais do NGINX.
Adicionamos vários parâmetros de ajuste aos arquivos de configuração MARA para acomodar implantações locais que não oferecem os recursos necessários para implantação baseada em nuvem. A maioria dos parâmetros está relacionada ao número de réplicas solicitadas para os vários componentes do Elastic Stack . À medida que os testes avançam, haverá parâmetros adicionais para ajuste fino do MARA com base nas restrições de recursos do ambiente de implantação.
Com essas mudanças em vigor, podemos implantar com sucesso em K3s, MicroK8s e Minikube, e testamos com sucesso a lógica no Azure Kubernetes Service (AKS), Digital Ocean , Google Kubernetes Engine , Linode e Rancher's Harvester . Para obter mais informações, consulte a página Status do provedor MARA e MARA: Agora em execução em uma estação de trabalho perto de você em nosso blog.
Nossos parceiros têm sido muito receptivos e apoiam nosso trabalho com a MARA, com muitos deles entrando em contato para saber mais sobre o projeto, perguntar como podem aproveitá-lo com seus produtos ou até mesmo adicionar recursos.
Escolhemos Pulumi como parte central do MARA por sua facilidade de uso e suporte ao Python, sendo este último uma linguagem tão popular que torna o código MARA facilmente compreendido por uma grande comunidade. Além disso, a comunidade vibrante de Pulumi e o envolvimento no projeto foram um modelo do envolvimento comunitário que esperamos alcançar com o MARA.
No final de 2021, trabalhamos com a Sumo Logic para tornar o MARA parte de sua solução de monitoramento em nuvem com o NGINX Ingress Controller. Esta foi uma oportunidade de testar nossa afirmação de que o MARA é plugável. O desafio era substituir a solução Sumo Logic para Grafana, Prometheus e Elastic no MARA. Ficamos satisfeitos por termos criado a solução com sucesso usando a mesma lógica que usamos para outras implantações e a configuramos não apenas para se conectar ao Sumo Logic SaaS, mas também para extrair métricas do nosso ambiente.
Como parte do nosso trabalho com a OpenTelemetry, colaboramos com a Lightstep e reconfiguramos facilmente nosso coletor OTEL para exportar rastros e métricas para a oferta SaaS da Lightstep. Esta é uma área que estamos interessados em investigar mais a fundo, pois acreditamos firmemente que o OTEL é o futuro da observabilidade.
A maior lição que aprendemos até agora é a sabedoria de uma abordagem modular. O trabalho com a Sumo Logic mostra que podemos misturar e combinar componentes MARA com sucesso. Esperamos mais confirmações à medida que integramos mais completamente o OTEL ao ambiente. Mencionamos anteriormente que estamos considerando substituir o Elasticsearch pelo Grafana Loki como ambiente de gerenciamento de log, porque ele reduz a pegada de recursos da pilha. Dito isso, defendemos a “modularidade pragmática” em vez de ir a extremos e tornar tudo um microsserviço. Por exemplo, embora faça sentido ter um serviço especializado que possa processar logs para muitos aplicativos, é menos óbvio que você precise de microsserviços separados para coleta, armazenamento e visualização de logs.
Também aprendemos que é útil definir padrões incluindo-os explicitamente na configuração em vez de apenas omitir o parâmetro relevante. Isso é conveniente para os administradores de duas maneiras: eles não precisam se lembrar dos padrões e podem alterá-los facilmente apenas modificando um parâmetro que já aparece com a sintaxe correta no lugar certo na configuração.
Outra lição dolorosa que aprendemos é que algumas soluções são populares não porque são as melhores, mas porque são as mais fáceis de instalar ou têm o melhor tutorial. É por isso que é tão importante questionar suas suposições e consultar colegas durante o processo de design – uma cultura de comunicação aberta ajuda muito a identificar e remediar problemas desde o início.
Dito isso, em diversas ocasiões implementamos uma lógica que funcionou, mas que nos encurralou ou causou outros problemas. Por exemplo, quando começamos a implantar aplicativos via Pulumi, usamos manifestos YAML para ConfigMaps , contando com transformações Pulumi para atualizar variáveis. Isso funcionou, mas não era o ideal por vários motivos, entre eles a manutenibilidade. Na próxima iteração, melhoramos a legibilidade e a manutenibilidade do código usando o kube2pulumi para transformar os manifestos em código Pulumi, que poderíamos então usar para construir os ConfigMaps.
Outra lição começou quando uma mesclagem inseriu configurações inválidas no YAML de implantação. Fomos forçados a reescrever e revisar cuidadosamente grandes partes do YAML para garantir que o código estivesse sintaticamente correto e fizesse o que queríamos, um processo frustrante e demorado. Para evitar problemas futuros, agora automatizamos o linting e a validação genéricos do YAML e específicos do Kubernetes durante o processo de push do GitHub.
Por fim, nosso objetivo desde o início é garantir que nossa ramificação principal esteja sempre executável. É frustrante quando você verifica um novo projeto e tem que resolver um problema que os mantenedores introduziram na versão principal. Infelizmente, falhamos nisso algumas vezes, incluindo estes exemplos com o submódulo Bank of Sirius:
ssh
para conectar ao GitHub. No entanto, usuários que não tinham uma chave SSH para o GitHub foram inundados com mensagens de erro quando tentaram inicializar o submódulo.Temos grandes planos para os próximos meses de desenvolvimento, incluindo a refatoração da compilação do NGINX Ingress Controller, o push do registro e a lógica do nome do host/endereço IP de entrada.
Uma coisa que notamos em cada standup do MARA é a rapidez com que começamos a ver varreduras e ataques no NGINX Ingress Controller. Isso nos levou a começar a integrar o NGINX Ingress Controller com o NGINX App Protect WAF no MARA. Isso traz consigo o desafio e a oportunidade de determinar a melhor forma de gerenciar o registro produzido pelo App Protect.
Outra mudança que planejamos fazer nos próximos meses é fazer com que todos os módulos extraiam segredos do Kubernetes em vez de Pulumi e Kubernetes. Isso significa que todos os módulos usam um repositório de segredos comum e dá ao administrador controle sobre como os segredos são preenchidos. Estamos escrevendo um novo módulo para ler segredos de um repositório escolhido pelo usuário e criar os segredos do Kubernetes correspondentes.
Atualmente, o MARA inclui uma ferramenta para gerar carga que é uma versão atualizada e ligeiramente modificada da ferramenta baseada no Locust que vem com o aplicativo original do Bank of Anthos, do qual bifurcamos o Bank of Sirius. A nova ferramenta de teste que estamos escrevendo, o Cicada Swarm, não apenas gera carga, mas também rastreia e relata quando as métricas ultrapassam os limites definidos, tornando-a uma estrutura para testes rápidos de desempenho de produtos de software na nuvem. Ele usa técnicas de paralelização para fornecer resultados de teste com o nível de confiança necessário, maior precisão e análise de regressão personalizável para determinar o sucesso ou a falha de compilações em seus pipelines de CI/CD.
Por fim, não podemos mencionar os testes de carga sem falar sobre como vamos medir o impacto desses testes de carga, o que nos leva de volta à telemetria. Estamos entusiasmados com o potencial do OpenTelemetry e esperamos ter uma implementação mais abrangente em breve. Mesmo sem uma implementação completa, nosso objetivo é poder executar um teste, medir seu impacto e tomar decisões operacionais sobre o que os dados nos dizem.
Como sempre, agradecemos suas solicitações de pull , problemas e comentários . Nosso objetivo com o MARA é inspirar a comunidade a trabalhar em conjunto para discutir, experimentar, testar e iterar por meio de diferentes soluções potenciais, a fim de aumentar nossa compreensão sobre a melhor forma de implantar e gerenciar um aplicativo moderno.
Esta postagem faz parte de uma série. À medida que adicionamos recursos ao MARA ao longo do tempo, publicamos os detalhes no blog:
"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."