Este artigo descreve as práticas recomendadas para monitorar um aplicativo de microsserviços executado no Serviço Kubernetes do Azure (AKS). Os tópicos específicos incluem coleta de telemetria, monitoramento do status de um cluster, métricas, registro, log estruturado e rastreamento distribuído. Este último é ilustrado neste diagrama:
Transfira um ficheiro do Visio desta arquitetura.
Recolha de telemetria
Em qualquer aplicação complexa, em algum momento algo vai dar errado. Em um aplicativo de microsserviços, você precisa acompanhar o que está acontecendo em dezenas ou até centenas de serviços. Para entender o que está acontecendo, você precisa coletar telemetria do aplicativo. A telemetria pode ser dividida nestas categorias: logs, rastreamentos e métricas.
Os logs são registros baseados em texto de eventos que ocorrem durante a execução de um aplicativo. Eles incluem coisas como logs de aplicativos (instruções de rastreamento) e logs do servidor Web. Os logs são úteis principalmente para perícia forense e análise de causa raiz.
Os rastreamentos, também chamados de operações, conectam as etapas de uma única solicitação em várias chamadas dentro e entre microsserviços. Eles podem fornecer observabilidade estruturada nas interações dos componentes do sistema. Os rastreamentos podem começar no início do processo de solicitação, como na interface do usuário de um aplicativo, e podem se propagar por serviços de rede em uma rede de microsserviços que lidam com a solicitação.
- Spans são unidades de trabalho dentro de um traço. Cada span é conectado com um único traço e pode ser aninhado com outros vãos. Eles geralmente correspondem a solicitações individuais em uma operação entre serviços, mas também podem definir o trabalho em componentes individuais dentro de um serviço. Os Spans também rastreiam chamadas de saída de um serviço para outro. (Às vezes, as extensões são chamadas de registros de dependência.)
As métricas são valores numéricos que podem ser analisados. Você pode usá-los para observar um sistema em tempo real (ou quase em tempo real) ou para analisar tendências de desempenho ao longo do tempo. Para entender um sistema de forma holística, você precisa coletar métricas em vários níveis da arquitetura, desde a infraestrutura física até o aplicativo, incluindo:
Métricas no nível do nó, incluindo uso de CPU, memória, rede, disco e sistema de arquivos. As métricas do sistema ajudam a entender a alocação de recursos para cada nó no cluster e a solucionar problemas de valores atípicos.
Métricas de contêiner . Para aplicativos em contêineres, você precisa coletar métricas no nível do contêiner, não apenas no nível da VM.
Métricas de aplicação . Essas métricas são relevantes para entender o comportamento de um serviço. Os exemplos incluem o número de solicitações HTTP de entrada enfileiradas, latência de solicitação e comprimento da fila de mensagens. Os aplicativos também podem usar métricas personalizadas específicas do domínio, como o número de transações comerciais processadas por minuto.
Métricas de serviço dependentes. Às vezes, os serviços chamam serviços externos ou pontos de extremidade, como serviços de PaaS ou SaaS gerenciados. Os serviços de terceiros podem não fornecer métricas. Se isso não acontecer, você precisará confiar em suas próprias métricas de aplicativo para acompanhar as estatísticas de latência e taxa de erro.
Monitorando o status do cluster
Use o Azure Monitor para monitorar a integridade de seus clusters. A captura de tela a seguir mostra um cluster com erros críticos em pods implantados pelo usuário:
A partir daqui, você pode aprofundar ainda mais para encontrar o problema. Por exemplo, se o status do pod for ImagePullBackoff
, o Kubernetes não pôde extrair a imagem do contêiner do registro. Esse problema pode ser causado por uma marca de contêiner inválida ou um erro de autenticação durante um pull do registro.
Se um contêiner falhar, o contêiner State
se tornará Waiting
, com um Reason
de CrashLoopBackOff
. Para um cenário típico, em que um pod faz parte de um conjunto de réplicas e a política de repetição é Always
, esse problema não aparece como um erro no status do cluster. No entanto, você pode executar consultas ou configurar alertas para essa condição. Para obter mais informações, consulte Compreender o desempenho do cluster AKS com o Azure Monitor Container insights.
Há várias pastas de trabalho específicas do contêiner disponíveis no painel pastas de trabalho de um recurso AKS. Você pode usar essas pastas de trabalho para uma visão geral rápida, solução de problemas, gerenciamento e insights. A captura de tela a seguir mostra uma lista de pastas de trabalho que estão disponíveis por padrão para cargas de trabalho do AKS.
Métricas do
Recomendamos que você use o Monitor para coletar e exibir métricas para seus clusters AKS e quaisquer outros serviços dependentes do Azure.
Para métricas de cluster e contêiner, habilite o Azure Monitor Container insights. Quando esse recurso está habilitado, o Monitor coleta métricas de memória e processador de controladores, nós e contêineres por meio da API de métricas do Kubernetes. Para obter mais informações sobre as métricas disponíveis no Container insights, consulte Compreender o desempenho do cluster AKS com o Azure Monitor Container insights.
Use o Application Insights para coletar métricas de aplicativos. O Application Insights é um serviço extensível de gerenciamento de desempenho de aplicativos (APM). Para usá-lo, instale um pacote de instrumentação em seu aplicativo. Este pacote monitora o aplicativo e envia dados de telemetria para o Application Insights. Ele também pode extrair dados de telemetria do ambiente host. Os dados são então enviados para o Monitor. O Application Insights também fornece correlação interna e rastreamento de dependência. (Ver Rastreamento distribuído, mais adiante neste artigo.)
O Application Insights tem uma taxa de transferência máxima medida em eventos por segundo e limita a telemetria se a taxa de dados exceder o limite. Para obter detalhes, consulte Limites do Application Insights. Crie instâncias diferentes do Application Insights para cada ambiente, para que os ambientes de desenvolvimento/teste não compitam com a telemetria de produção para a cota.
Uma única operação pode gerar muitos eventos de telemetria, portanto, se um aplicativo tiver um alto volume de tráfego, sua captura de telemetria provavelmente será limitada. Para atenuar esse problema, você pode executar a amostragem para reduzir o tráfego de telemetria. A contrapartida é que suas métricas serão menos precisas, a menos que a instrumentação suporte a pré-agregação. Nesse caso, haverá menos amostras de rastreamento para solução de problemas, mas as métricas mantêm a precisão. Para obter mais informações, consulte Amostragem no Application Insights. Você também pode reduzir o volume de dados pré-agregando métricas. Ou seja, você pode calcular valores estatísticos, como a média e o desvio padrão, e enviar esses valores em vez da telemetria bruta. Esta postagem de blog descreve uma abordagem para usar o Application Insights em escala: Azure Monitoring and Analytics at Scale.
Se sua taxa de dados for alta o suficiente para acionar a limitação e a amostragem ou agregação não for aceitável, considere exportar métricas para um banco de dados de séries temporais, como o Azure Data Explorer, Prometheus ou InfluxDB, em execução no cluster.
O Azure Data Explorer é um serviço de exploração de dados nativo do Azure e altamente escalável para dados de log e telemetria. Ele possui suporte para vários formatos de dados, uma linguagem de consulta rica e conexões para consumir dados em ferramentas populares como Jupyter Notebooks e Grafana. O Azure Data Explorer tem conectores internos para ingerir dados de log e métricas por meio dos Hubs de Eventos do Azure. Para obter mais informações, consulte Ingerir e consultar dados de monitoramento no Azure Data Explorer.
O InfluxDB é um sistema baseado em push. Um agente precisa empurrar as métricas. Você pode usar a pilha TICK para configurar o monitoramento do Kubernetes. Em seguida, você pode enviar métricas para o InfluxDB usando o Telegraf, que é um agente para coletar e relatar métricas. Você pode usar o InfluxDB para eventos irregulares e tipos de dados de cadeia de caracteres.
Prometheus é um sistema baseado em pull. Ele periodicamente raspa métricas de locais configurados. O Prometheus pode coletar métricas geradas pelo Azure Monitor ou kube-state-metrics. kube-state-metrics é um serviço que coleta métricas do servidor de API do Kubernetes e as disponibiliza para o Prometheus (ou um scraper compatível com um endpoint do cliente Prometheus). Para métricas de sistema, use o exportador de nós, que é um exportador de Prometheus para métricas de sistema. O Prometheus suporta dados de ponto flutuante, mas não dados de cadeia de caracteres, por isso é apropriado para métricas do sistema, mas não logs. O Kubernetes Metrics Server é um agregador de dados de uso de recursos em todo o cluster.
Registo
Aqui estão alguns dos desafios gerais de fazer login em um aplicativo de microsserviços:
- Compreender o processamento de ponta a ponta de uma solicitação de cliente, onde vários serviços podem ser invocados para lidar com uma única solicitação.
- Consolidação de logs de vários serviços em uma única exibição agregada.
- Análise de logs que vêm de várias fontes que usam seus próprios esquemas de log ou não têm nenhum esquema específico. Os logs podem ser gerados por componentes de terceiros que você não controla.
- As arquiteturas de microsserviços geralmente geram um volume maior de logs do que os monólitos tradicionais porque há mais serviços, chamadas de rede e etapas em uma transação. Isso significa que o próprio registro em log pode ser um gargalo de desempenho ou de recursos para o aplicativo.
Existem alguns desafios adicionais para arquiteturas baseadas em Kubernetes:
- Os contentores podem mover-se e ser reagendados.
- O Kubernetes tem uma abstração de rede que usa endereços IP virtuais e mapeamentos de portas.
No Kubernetes, a abordagem padrão para o registro em log é que um contêiner grave logs em stdout e stderr. O mecanismo de contêiner redireciona esses fluxos para um driver de registro. Para facilitar a consulta e evitar a possível perda de dados de log se um nó parar de responder, a abordagem usual é coletar os logs de cada nó e enviá-los para um local de armazenamento central.
O Azure Monitor integra-se com o AKS para dar suporte a essa abordagem. O Monitor coleta logs de contêiner e os envia para um espaço de trabalho do Log Analytics. A partir daí, você pode usar a linguagem de consulta Kusto para escrever consultas nos logs agregados. Por exemplo, aqui está uma consulta Kusto para mostrar os logs de contêiner para um pod especificado:
ContainerLogV2
| where PodName == "podName" //update with target pod
| project TimeGenerated, Computer, ContainerId, LogMessage, LogSource
O Azure Monitor é um serviço gerenciado e configurar um cluster AKS para usar o Monitor é uma alteração de configuração simples no modelo CLI ou Azure Resource Manager. (Para obter mais informações, consulte Como habilitar o Azure Monitor Container insights.) Outra vantagem de usar o Azure Monitor é que ele consolida seus logs AKS com outros logs da plataforma Azure para fornecer uma experiência de monitoramento unificada.
O Azure Monitor é cobrado por gigabyte (GB) de dados ingeridos no serviço. (Ver Preços do Azure Monitor.) Em volumes elevados, o custo pode tornar-se uma consideração. Existem muitas alternativas de código aberto disponíveis para o ecossistema Kubernetes. Por exemplo, muitas organizações usam o Fluentd com o Elasticsearch. O Fluentd é um coletor de dados de código aberto e o Elasticsearch é um banco de dados de documentos usado para pesquisa. Um desafio com essas opções é que elas exigem configuração e gerenciamento adicionais do cluster. Para uma carga de trabalho de produção, talvez seja necessário experimentar definições de configuração. Você também precisará monitorar o desempenho da infraestrutura de registro.
OpenTelemetry
O OpenTelemetry é um esforço intersetorial para melhorar o rastreamento, padronizando a interface entre aplicativos, bibliotecas, telemetria e coletores de dados. Quando você usa uma biblioteca e uma estrutura que são instrumentadas com OpenTelemetry, a maior parte do trabalho de operações de rastreamento que são tradicionalmente operações do sistema é manipulada pelas bibliotecas subjacentes, o que inclui os seguintes cenários comuns:
- Registro de operações básicas de solicitação, como hora de início, hora de saída e duração
- Exceções lançadas
- Propagação de contexto (como o envio de um ID de correlação através dos limites da chamada HTTP)
Em vez disso, as bibliotecas e estruturas de base que lidam com essas operações criam estruturas de dados de span e rastreamento inter-relacionadas e as propagam entre contextos. Antes do OpenTelemetry, eles geralmente eram apenas injetados como mensagens de log especiais ou como estruturas de dados proprietárias que eram específicas para o fornecedor que construiu as ferramentas de monitoramento. O OpenTelemetry também incentiva um modelo de dados de instrumentação mais avançado do que uma abordagem tradicional de registro inicial, e os logs são mais úteis porque as mensagens de log são vinculadas aos rastreamentos e extensões onde foram geradas. Isso geralmente facilita a localização de logs associados a uma operação ou solicitação específica.
Muitos dos SDKs do Azure foram instrumentados com OpenTelemetry ou estão no processo de implementá-lo.
Um desenvolvedor de aplicativos pode adicionar instrumentação manual usando os SDKs OpenTelemetry para realizar as seguintes atividades:
- Adicione instrumentação onde uma biblioteca subjacente não a forneça.
- Enriqueça o contexto de rastreamento adicionando extensões para expor unidades de trabalho específicas do aplicativo (como um loop de ordem que cria uma extensão para o processamento de cada linha de ordem).
- Enriqueça as extensões existentes com chaves de entidade para permitir um rastreamento mais fácil. (Por exemplo, adicione uma chave/valor OrderID à solicitação que processa essa ordem.) Essas chaves são exibidas pelas ferramentas de monitoramento como valores estruturados para consulta, filtragem e agregação (sem analisar cadeias de caracteres de mensagens de log ou procurar combinações de sequências de mensagens de log, como era comum com uma abordagem de registro inicial).
- Propagar o contexto de rastreamento acessando atributos de rastreamento e span, injetando traceIds em respostas e cargas úteis e/ou lendo traceIds de mensagens recebidas, para criar solicitações e extensão.
Leia mais sobre instrumentação e os SDKs do OpenTelemetry na documentação do OpenTelemetry .
Application Insights
O Application Insights coleta dados avançados do OpenTelemetry e suas bibliotecas de instrumentação e os captura em um armazenamento de dados eficiente para fornecer visualização avançada e suporte a consultas. As bibliotecas de instrumentação baseadas em OpenTelemetry do Application Insights, para linguagens como .NET, Java, Node.js e Python, facilitam o envio de dados de telemetria para o Application Insights.
Se você estiver usando o .NET Core, recomendamos que considere também a biblioteca Application Insights for Kubernetes . Essa biblioteca enriquece os rastreamentos do Application Insights com informações adicionais, como contêiner, nó, pod, rótulos e conjunto de réplicas.
O Application Insights mapeia o contexto OpenTelemetry para seu modelo de dados interno:
- Trace -> Operação
- ID de rastreamento -> ID da operação
- Span -> Solicitação ou dependência
Tenha em conta as seguintes considerações:
- O Application Insights limita a telemetria se a taxa de dados exceder um limite máximo. Para obter detalhes, consulte Limites do Application Insights. Uma única operação pode gerar vários eventos de telemetria, portanto, se um aplicativo tiver um grande volume de tráfego, é provável que ele seja limitado.
- Como o Application Insights envia dados em lotes, você pode perder um lote se um processo falhar com uma exceção não tratada.
- A cobrança do Application Insights é baseada no volume de dados. Para obter mais informações, consulte Gerenciar preços e volume de dados no Application Insights.
Registo estruturado
Para facilitar a análise de logs, use o log estruturado sempre que possível. Quando você usa o log estruturado, o aplicativo grava logs em um formato estruturado, como JSON, em vez de enviar cadeias de texto não estruturadas. Há muitas bibliotecas de log estruturadas disponíveis. Por exemplo, aqui está uma instrução de log que usa a biblioteca Serilog para .NET Core:
public async Task<IActionResult> Put([FromBody]Delivery delivery, string id)
{
logger.LogInformation("In Put action with delivery {Id}: {@DeliveryInfo}", id, delivery.ToLogInfo());
...
}
Aqui, a chamada para LogInformation
inclui um parâmetro e DeliveryInfo
um Id
parâmetro. Quando você usa o log estruturado, esses valores não são interpolados na cadeia de caracteres da mensagem. Em vez disso, a saída do log tem a seguinte aparência:
{"@t":"2019-06-13T00:57:09.9932697Z","@mt":"In Put action with delivery {Id}: {@DeliveryInfo}","Id":"36585f2d-c1fa-4a3d-9e06-a7f40b7d04ef","DeliveryInfo":{...
Esta é uma cadeia de caracteres JSON, onde o campo é um carimbo @t
de data/hora, @mt
é a cadeia de caracteres de mensagem e os pares chave/valor restantes são os parâmetros. O formato JSON de saída facilita a consulta dos dados de forma estruturada. Por exemplo, a seguinte consulta do Log Analytics, escrita na linguagem de consulta Kusto, procura instâncias dessa mensagem específica de todos os contêineres chamados fabrikam-delivery
:
traces
| where customDimensions.["Kubernetes.Container.Name"] == "fabrikam-delivery"
| where customDimensions.["{OriginalFormat}"] == "In Put action with delivery {Id}: {@DeliveryInfo}"
| project message, customDimensions["Id"], customDimensions["@DeliveryInfo"]
Se você exibir o resultado no portal do Azure, poderá ver que é um registro estruturado que DeliveryInfo
contém a representação serializada do DeliveryInfo
modelo:
Aqui está o JSON deste exemplo:
{
"Id": "36585f2d-c1fa-4a3d-9e06-a7f40b7d04ef",
"Owner": {
"UserId": "user id for logging",
"AccountId": "52dadf0c-0067-43e7-af76-86e32b48bc5e"
},
"Pickup": {
"Altitude": 0.29295161612934972,
"Latitude": 0.26815900219052985,
"Longitude": 0.79841844309047727
},
"Dropoff": {
"Altitude": 0.31507750848078986,
"Latitude": 0.753494655598651,
"Longitude": 0.89352830773849423
},
"Deadline": "string",
"Expedited": true,
"ConfirmationRequired": 0,
"DroneId": "AssignedDroneId01ba4d0b-c01a-4369-ba75-51bde0e76cc9"
}
Muitas mensagens de log marcam o início ou o fim de uma unidade de trabalho ou conectam uma entidade comercial a um conjunto de mensagens e operações para rastreabilidade. Em muitos casos, enriquecer objetos de extensão e solicitação do OpenTelemetry é uma abordagem melhor do que apenas registrar o início e o fim da operação. Isso adiciona esse contexto a todos os rastreamentos conectados e operações filhas, e coloca essas informações no escopo da operação completa. Os SDKs OpenTelemetry para vários idiomas suportam a criação de extensões ou a adição de atributos personalizados em vãos. Por exemplo, o código a seguir usa o Java OpenTelemetry SDK, que é suportado pelo Application Insights. Uma extensão pai existente (por exemplo, uma extensão de solicitação associada a uma chamada de controlador REST e criada pela estrutura da Web que está sendo usada) pode ser enriquecida com um ID de entidade associado a ela, conforme mostrado aqui:
import io.opentelemetry.api.trace.Span;
// ...
Span.current().setAttribute("A1234", deliveryId);
Esse código define uma chave ou valor na extensão atual, que é conectada a operações e mensagens de log que ocorrem nessa extensão. O valor aparece no objeto de solicitação do Application Insights, conforme mostrado aqui:
requests
| extend deliveryId = tostring(customDimensions.deliveryId) // promote to column value (optional)
| where deliveryId == "A1234"
| project timestamp, name, url, success, resultCode, duration, operation_Id, deliveryId
Essa técnica se torna mais poderosa quando usada com logs, filtragem e anotação de rastreamentos de log com contexto de extensão, conforme mostrado aqui:
requests
| extend deliveryId = tostring(customDimensions.deliveryId) // promote to column value (optional)
| where deliveryId == "A1234"
| project deliveryId, operation_Id, requestTimestamp = timestamp, requestDuration = duration // keep some request info
| join kind=inner traces on operation_Id // join logs only for this deliveryId
| project requestTimestamp, requestDuration, logTimestamp = timestamp, deliveryId, message
Se você usar uma biblioteca ou estrutura que já esteja instrumentada com OpenTelemetry, ela lida com a criação de extensões e solicitações, mas o código do aplicativo também pode criar unidades de trabalho. Por exemplo, um método que percorre uma matriz de entidades que executa trabalho em cada uma delas pode criar uma extensão para cada iteração do loop de processamento. Para obter informações sobre como adicionar instrumentação ao código do aplicativo e da biblioteca, consulte a documentação da instrumentação OpenTelemery.
Rastreio distribuído
Um dos desafios quando você usa microsserviços é entender o fluxo de eventos entre serviços. Uma única transação pode envolver chamadas para vários serviços.
Exemplo de rastreio distribuído
Este exemplo descreve o caminho de uma transação distribuída por meio de um conjunto de microsserviços. O exemplo é baseado em um aplicativo de entrega por drone.
Nesse cenário, a transação distribuída inclui estas etapas:
- O serviço Ingestão coloca uma mensagem em uma fila do Barramento de Serviço do Azure.
- O serviço de fluxo de trabalho extrai a mensagem da fila.
- O serviço de fluxo de trabalho chama três serviços de back-end para processar a solicitação (Agendador de drones, Pacote e Entrega).
A captura de tela a seguir mostra o mapa do aplicativo de entrega do drone. Este mapa mostra chamadas para o ponto de extremidade da API pública que resultam em um fluxo de trabalho que envolve cinco microsserviços.
As setas de e para uma fila do fabrikam-workflow
Service Bus mostram onde as mensagens são enviadas e fabrikam-ingestion
recebidas. Você não pode dizer a partir do diagrama qual serviço está enviando mensagens e qual está recebendo. As setas mostram apenas que ambos os serviços estão chamando o Service Bus. Mas as informações sobre qual serviço está enviando e qual está recebendo estão disponíveis nos detalhes:
Como cada chamada inclui um ID de operação, você também pode visualizar as etapas de ponta a ponta de uma única transação, incluindo informações de tempo e as chamadas HTTP em cada etapa. Aqui está a visualização de uma dessas transações:
Esta visualização mostra as etapas do serviço de ingestão para a fila, da fila para o serviço de fluxo de trabalho e do serviço de fluxo de trabalho para os outros serviços de back-end. A última etapa é o serviço de fluxo de trabalho marcando a mensagem do Service Bus como concluída.
Este exemplo mostra chamadas para um serviço back-end que estão falhando:
Este mapa mostra que uma grande fração (36%) das chamadas para o serviço Drone Scheduler falhou durante o período da consulta. A exibição de transação de ponta a ponta revela que uma exceção ocorre quando uma solicitação HTTP PUT é enviada ao serviço:
Se você aprofundar ainda mais, poderá ver que a exceção é uma exceção de soquete: "Nenhum dispositivo ou endereço desse tipo".
Fabrikam.Workflow.Service.Services.BackendServiceCallFailedException:
No such device or address
---u003e System.Net.Http.HttpRequestException: No such device or address
---u003e System.Net.Sockets.SocketException: No such device or address
Essa exceção sugere que o serviço de back-end não está acessível. Neste ponto, você pode usar kubectl para exibir a configuração de implantação. Neste exemplo, o nome do host de serviço não está resolvendo devido a um erro nos arquivos de configuração do Kubernetes. O artigo Debug Services na documentação do Kubernetes tem dicas para diagnosticar esse tipo de erro.
Aqui estão algumas causas comuns de erros:
- Bugs de código. Esses bugs podem aparecer como:
- Exceções. Procure nos logs do Application Insights para exibir os detalhes da exceção.
- Um processo falhando. Observe o status do contêiner e do pod e visualize os logs do contêiner ou os rastreamentos do Application Insights.
- HTTP 5xx erros.
- Esgotamento de recursos:
- Procure por limitação (HTTP 429) ou tempo limite de solicitação.
- Examine as métricas do contêiner para CPU, memória e disco.
- Observe as configurações para limites de recursos de contêiner e pod.
- Descoberta de serviços. Examine a configuração do serviço Kubernetes e os mapeamentos de porta.
- Incompatibilidade de API. Procure erros HTTP 400. Se as APIs tiverem versão, observe a versão que está sendo chamada.
- Erro ao puxar uma imagem de contêiner. Olhe para a especificação do pod. Certifique-se também de que o cluster está autorizado a extrair do registro do contêiner.
- Problemas RBAC.
Próximos passos
Saiba mais sobre os recursos do Azure Monitor que dão suporte ao monitoramento de aplicativos no AKS:
- Visão geral dos insights de contêiner do Azure Monitor
- Compreender o desempenho do cluster AKS com as informações do Azure Monitor Container