Salve galera! Tudo certo?

Hoje vamos ver rapidamente uma das novidades do ASP.NET Core 2.2, que é a disponibilização de um mecanismo de Health Check com um endpoint para acessarmos o status dessas verificações e como podemos construir um Check customizado. Vamos ver também, no detalhe, como utilizar isto em conjunto com o Kubernetes, configurando um cluster, fazendo deployment e atualizando este para que possa avaliar a saúde dos containers em execução e fazer a reciclagem deles quando necessário.

A demonstração está sendo feita no Azure com o serviço AKS, mas nada impede de executarem em uma instalação local do Kubernetes.

Motivação

Antes de colocar a mão na massa, por que fazer este tipo de verificação?

Já não estamos mais na época que verificávamos logs e status da aplicação manualmente, quando recebíamos algum chamado do usuário questionando a disponibilidade ou reportando erros. Hoje, quem ainda faz desta forma, simplesmente perde usuários, pois estamos vivendo uma fase onde nossas aplicações / ambientes devem ser inteligentes o suficiente para nos alertar de falhas antes mesmo dos usuários reportarem estas, e até mesmo, se recuperarem se a necessidade de intervenção manual.

Avaliando a situação da aplicação ao receber um chamado do usuário… Bom, pode ser um pouco tarde…

Habilitando o Health Check

Vamos criar um novo projeto Web MVC com o ASP.NET Core 2.2. Para isto, vamos utilizar o comando “dotnet new mvc -n DemoHealthCheck”. Para isto, devemos ter instalado o SDK do .NET Core 2.2. Para verificar a versão do CLI, basta executar o comando “dotnet — version”, conforme também mostro na tela abaixo:

Criando um novo projeto ASP.NET MVC onde vamos habilitar o Health Check.

Vamos abrir o diretório / projeto no Visual Studio Code e acessar a classe Startup.

Visual Studio Code com a classe Startup aberta.

Agora iremos adicionar no método ConfigureServices a chamada para adicionar o serviço de Health Check ao ServiceProvider do ASP.NET Core, adicionando a linha conforme destaque na imagem abaixo.

Habilitando o serviço de Health Check nos serviços do ASP.NET Core, com o método de extensão AddHealthChecks();

Por enquanto estamos apenas habilitando o serviço, logo vamos ver como adicionar verificações específicas que dirão se nossa aplicação está saudável ou não. Para habilitar o Middleware que irá responder pelo serviço de Health Check, devemos editar o método Configure da classe Startup, adicionando a linha em destaque na imagem a seguir.

Adicionando a rota que irá utilizar o serviço de Health Check ao builder da Aplicação.

Notem que este método recebe uma string com o endereço a ser utilizado e, opcionalmente, um objeto de opções para configurar detalhes da rota e visualização dos dados, como mapear códigos de resposta HTTP para determinados estados de saúde retornados, se vamos utilizar cache, entre outras opções. Para esta demonstração, vamos informar apenas a string com a rota “/health”.

Ao executar a aplicação, ela será carregada normalmente.

Aplicação em execução.

Acessando a rota /health, por acessar diretamente no Browser, teremos uma resposta de texto indicando que a aplicação encontra-se saudável, visto que ainda não configuramos nenhuma verificação extra.

Retorno do endpoint de verificação de “saúde” de nossa aplicação.

Neste momento temos o serviço de Health Check ativo, mas ele não está efetivamente verificando nada além da aplicação estar em execução sem nenhum erro interno.

Vamos agora adicionar a verificação que irá acessar um MockRest do site mockable.io. Após se cadastrar no site, vamos criar um endpoint que responde com HTTP 200.

Copy Live URL

Vamos criar uma nova classe implementando a interface de IHealthCheck na raiz de nossa aplicação.

.

Vamos editar o método CheckHealthAsync para realizar um HTTP GET para nossa API Mock e, caso o resultado seja OK (200), vamos retornar o resultado como saudável, ou caso contrário, como não saudável. Para isto, precisamos implementar o código a seguir. Note que adicionei o async no método CheckHealthAsync.

Agora, precisamos registrar nossa classe MockHealthCheck no serviço de monitoração. Para isto, vamos editar o método ConfigureServices da classe Startup, adicionando os métodos a seguir como sequência do método AddHealthChecks (temos uma DSL, onde vamos configurando diferentes itens um após o outro), conforme a imagem em destaque a seguir.

Adicionando nossa classe de Health Check a lista de verificações do serviço.

Notem que é um método genérico onde informamos o Tipo da classe de verificação e um parâmetro string que é a chave de identificação daquele Check.

Agora, ao executar novamente nossa aplicação e acessar o endpoint /health, temos o resultado a seguir.

Aplicação retornando status de saudável, visto que o Mock está respondendo com OK (200).

Agora, se alterarmos no mockable.io para retornar um status diferente de 2xx, conforme a imagem a seguir e verificarmos novamente a página de Health Check, teremos o status informado como não saudável, ou seja, nossa aplicação encontra-se com problemas, mas não completamente indisponível, visto que ela ainda está em execução. Isto já é o suficiente para disparar um mecanismo de alerta no Kubernetes, como veremos a seguir.

Retornando um HTTP 503 do mockable.io para forçar um status não saudável.
Aplicação retornando status não saudável.

Antes de continuar, vamos voltar o mockable.io para retornar um status 200, assim podemos prosseguir com o uso do Kubernetes para deploy da apliação.

Integrando nossa aplicação ao Kubernetes

Antes de colocar nossa aplicação em um cluster do Kubernetes, precisamos construir a imagem Docker dela, já com os comandos de Health Check do Docker prontos na imagem.

Para isto, vamos adicionar na raiz do projeto um arquivo chamado Dockerfile, com o conteúdo a seguir.

Arquivo Dockerfile

Apenas explicando rapidamente o que faz o arquivo acima, ele utiliza a imagem base do .NET Core 2.2, realiza o restore, build e publish da aplicação Web. Ao final, ele configura o entry point como sendo a execução da DLL de nossa aplicação pelo CLI do .NET Core.

Notem que utilizamos como definição final a imagem de Runtime, gerando assim uma imagem menor para a publicação, comparado quando utilizamos apenas a imagem com o SDK.

Com o arquivo configurado, vamos executar o comando “docker build -t demo-health-check .”, onde “demo-health-check” é o nome da imagem que vamos criar. Isto pode demorar de alguns segundos até alguns minutos, dependendo da sua conexão de internet e cache de imagens do docker, pois ele irá fazer o download das imagens necessárias e realizar o build de nossa imagem.

Build em execução — Parte 1
Build em execução — Parte 2

Agora temos a imagem pronta, podendo confirmar com o comando “docker images”.

Imagem pronta disponível em nosso repositório local.

Configurando o Contêiner Registry

Vamos criar um repositório para nossas imagens Docker no Azure. Para isto, vamos acessar o Portal do Azure, clicar no menu de Adicionar recursos, navegar até a opção Contêineres se escolher o item Container Registry.

Acessando a opção para criar um Container Registry

Vamos dar um nome para nosso contêiner, escolher a assinatura em uso, um grupo de recursos, sendo que criei um novo para agrupar os recursos deste artigo, facilitando a remoção posteriormente. Escolhi região Sul do Brasil por questões de menor latência de rede, habilitamos o Admin para poder publicar e alterei a camada de preços para a camada mais básica, por se tratar de uma demonstração. Após isto, basta clicar em Criar e aguardar a criação do recurso ser concluída.

Configurando as opções do novo registro de contêiner.

Agora que temos nosso registro de contêiners criado, vamos publicar nossa imagem nele. Para isto, precisamos gerar uma tag de nossa imagem com a referência para publicação no registro de contêiners e fazer a publicação, com os comandos apresentados nas imagens a seguir. Onde estiver gbbigardi.azurecr.io, troque pelo nome de registro que você utilizou em sua conta, ok?

Gerando a tag para publicação da imagem.

Para fazer o push da imagem, precisamos fazer login no registro de contêiner. Para obter o usuário e senha, acesse o item no portal do Azure. Os dados, encontram-se no menu “Access Keys” do recurso.

Tela de chaves de acesso, onde podemos obter o usuário e senha para login e publicação de nossa imagem.
Realizando login, com o usuário e senha obtidos no portal do Azure.
Executando o push da imagem para o registro de contêiners.

Agora que temos a imagem pronta e disponível em nosso registro de contêiners, vamos criar um cluster Kubernetes para podermos fazer o deployment.

Criando um cluster Kubernetes no Azure

Para criar nosso cluster, vamos utilizar o terminal de linha de comando do portal do Azure. Para isto basta clicar no ícone da barra de ferramentas como indicado na imagem a seguir, e em seguida escolher o bash. Este último é minha preferência, podem utilizar o Powershell se quiserem.

Acessando o terminal de comandos no Portal do Azure.

Caso seja a primeira vez acessando este recurso, será solicitada a criação de um recurso de Storage, pois é necessário para uso do terminal. O custo é em torno de centavos.

Vamos executar primeiro o comando a seguir para carregar o provedor que permite criar e gerenciar o Kubernetes via CLI.

Regsitrando o provider Microsoft.ContainerService para trabalharmos com o AKS via CLI.

Vamos criar um novo grupo de recursos, visto que o serviço AKS ainda não está disponível no Sul do Brasil, impossibilitando de utilizar o grupo que criei para o registro de contêiners. Para isto, basta executr o comando da imagem a seguir, trocando o valor do parâmetro name conforme desejar.

Criando um grupo de recursos no Azure, com uma região onde o AKS encontra-se disponível.

Agora iremos gerar um recurso do AKS, o nosso cluster Kubernetes, tendo este dois nodes, vinculado ao grupo que criamos no passo anterior. Para isto basta executar o comando conforme a imagem a seguir. O valor do parâmetro name pode ser trocado conforme preferência de vocês, ok?

Criando um novo cluster do AKS com 2 nós.

Finalizados os procedimentos, podemos verificar que foram criados dois grupos de recursos, um com o serviço do AKS, TesteKubernetes, e outro com todos os recursos que compõem nosso cluster, MC_TesteKubernetes_HealthCheckService_eastus, com as máquinas virtuais dos nós, rotas de rede, storage, etc.

Grupos de recursos criados durante a construção do cluster AKS.

Realizando deploy da aplicação

Agora que temos nosso cluster criado, precisamos fazer o deployment de nossa aplicação. Vamos primeira cofigurar o deployment e em seguida alterar o mesmo para habilitar o Health Check.

Para poder fazer deployment da aplicação, precisamos do CLI kubectl do Kubernetes. Se você tem o Docker instalado localmente e habilitou o Kubernetes, ele já vai estar disponível no prompt de comando. Caso contrário, pode encontrar como instalar o CLI no link a seguir.

https://kubernetes.io/docs/tasks/tools/install-kubectl

Para quem não quiser instalar e, como vou fazer aqui no artigo, vamos mais uma vez ao terminal no Portal do Azure para configurar obter as credenciais de acesso ao nosso cluster AKS. Para isto, executaremos o comando a seguir.

Configurando o acesso ao Kubernetes

O comando acima, conforme visto na resposta dele, gerou um arquivo de configuração para acesso. Vamos agora habilitar o acesso ao registro de contêiners com o comando a seguir.

kubectl create secret docker-registry healthcheck-registrykey — docker-server=https://gbbigardi.azurecr.io — docker-username=<username> — docker-password=”<chave_acesso>” — docker-email=”<email>”
Executando comando para criação de chave de acesso ao registro de contêiners pelo AKS.

Agora, precisamos criar o arquivo com as definições de deployment da aplicação. Vamos chamar este de healthcheck.yml e adicionar o conteúdo a seguir.

Podemos observar neste arquivo que a propriedade replicas está configurada para 2, ou seja, 2 pods e que estou indicando o uso da porta 80 como saída, além da imagem gbbigardi.azurecr.io/demo-health-check:latest, já disponível no registro de contêiners que criamos.

Agora vamos executar o comando a seguir para realizar o deployment com a configuração que criamos.

Executando o comando kubectl create com o arquivo de configuração para configurar o deploy da aplicação.

Se executarmos o comando “kubectl get pods” no terminal, vamos ver que temos agora dois pods (containers) em execução.

Verificando nossos pods em execução.

Se executarmos o comando “kubectl get services”, vamos ver que temos apenas o serviço de cluster em execução e sem nenhum IP externo. Ou seja, temos nossos pods em execução, mas não temos como acessá-los.

Verificando os serviços em execução no Kubernetes.

Precisamos criar um endpoint de entrada, e dado que temos dois pods em execução, nada mais justo que criarmos um load-balancer. Vamos criar agora um arquivo loadbalancer.yml com as configurações para deploy de um load-balancer no Kubernetes, direcionando o tráfego para nossos pods.

Podemos verificar de especial neste arquivo o nó spec / selector / app com o nome de nossa aplicação nos pods. Em seguida a porta em uso e o tipo (type) de serviço, que é um LoadBalancer.

Após criar o arquivo, vamos executar o comando a seguir para carregar o load-balancer.

Criando um load-balancer no Kubernetes com o arquivo de configuração.

Executando novamente o comando “kubectl get services”, podemos agora verificar nosso load-balancer com um IP externo. Pode demorar algum tempo para que o IP externo apareça, enquanto o AKS configura o roteador virtual.

Verificando o serviço de load-balancer criado, já com IP externo disponível.

Vamos fazer um teste acessando o endereço http://157.56.179.189 (utilizando o IP fornecido em seu ambiente) no navegador.

Aplicação em execução.
API de Health Check respondendo como saudável, visto que no mackable.io ainda está retornando HTTP 200.

Vamos habilitar o Dashboard do Kubernetes para ter um “visual” melhor para ver nossa aplicação em execução, status e também validarmos o controle de Health Check.

Antes, precisamos configurar o usuário de acesso ao Dashboard. Vamos executar o comando a seguir no terminal do Azure para isto.

Habilitando o acesso de admin para podermos carregar e acessar o Dashboard do Kubernetes.

Então vamos executar o comando a seguir para carregar o Dashboard.

Carregando o Dashboard do Kubernetes.

Neste momento, ele carregou a aplicação de Dashboard e já criou uma rota para expor ela externamente. Para acessar, basta abrir a URL apresentada pelo CLI em uma janela do Browser.

Dashboard do Kubernetes carregado no browser.
Visualizando nossos dois pods em execução pelo Dashboard.

Vamos agora configurar o Kubernetes para monitorar nosso endpoint, fazendo com que o pod seja reciclado caso nossa API reporte que não está saudável. Poderemos ver nos logs do Kubernetes que os pods foram finalizados e substituídos por novas instâncias, quando alterarmos o retorno no mockable.io.

Para configurar o Kubernetes, vamos alterar o arquivo de deploy de nossa aplicação, o arquivo healthcheck.yml

Notem que adicionamos entre os nós ports e imagePullSecrets o nó livenessProbe, onde temos a configuração de validação da aplicação. Informamos que vamos utilizar um httpGet, no path /health, porta 80 a cada 5 segundos, com um delay de 5 segundos para a primeira verificação.

Feito isso, salvar o arquivo e atualizar nosso deployment com o comando a seguir.

.

Feito isto, vamos carregar novamente o dashboard.

Iniciando novamente o proxy para o serviço de Dashboard.

No dashboard, no menu a esquerda, vamos clicar em Pods, e clicar em um de nossos pods ver os detalhes do mesmo. Na tela do Pod, vamos navegar até o painel de Events. Podemos ver que nosso contêiner foi iniciado e está em execução normalmente. Nenhum evento de erro sendo reportado.

Log de eventos de um dos Pods.

Vamos agora alterar o retorno do mockable.io para que nossa aplicação comece a retornar o status de não saudável no endpoint health, através do Health Check do ASP.NET Core.

Configurando o mockable.io para retornar falha, simulando um serviço que nossa aplicação depende com problemas.

Como nosso Health Check está reportando Unhealthy (HTTP 503, alguns serviços indisponíveis), já temos nos logs do Kubernetes o alerta.

Evento de falha na verificação de saúde da aplicação.

Como a alteração no mockable.io reflete em todos os pods, podemos ver que todos estão com alertas. E verificando no detalhe, podemos notar que eles tiveram uma quantidade de restarts aplicados.

Pods com alertas de problemas reportados pelo serviço de verificação do Kubernetes.
Verificando que nossos pods reiniciaram em tentativa de recuperar a aplicação.

Vamos agora voltar ao mockable.io e voltar a resposta para 200, para que o Health Check do ASP.NET volte a reportar que a aplicação está saudável. Após alguns segundos, vamos ver a quantidade final de restarts que ocorreram na aplicação, mas que a mesma já encontra-se disponível novamente.

Alicação novamente disponível após recuperação do serviço.

Notem que no arquivo .yml de deployment, utilizamos o nó liveness para configurar a verificação de saúde da aplicação que gerou restarts de nossos pods. E se por acaso, fosse apenas report de um serviço indisponível, como foi nesta situação, em que nossos pods apenas deveriam aguardar seu retorno, sendo isolados do ambiente? Basta trocar o nó liveness por readiness. Este nó irá ter o mesmo comportamento, exceto que os pods não serão reiniciados, apenas isolados do load-balancer até que se recuperem e reportem estarem saudáveis novamente.

Concluindo

Para finalizar a demonstração, caso queira, pode remover todo o ambiente que criamos com o comando a seguir, evitando surpresas com a cobrança no final do mês ou esgotamento de seus créditos de avaliação.

Removendo o ambiente de cluster do Kubernetes.

Hoje aprendemos mais sobre uma novidade que chegou na versão 2.2 do ASP.NET Core e vimos no detalhe como configurar e realizar o deploy de uma aplicação em um cluster AKS no Azure.

O código font da aplicaçao com o Custom Health Check encontra-se disponível no meu GitHub. Os arquivos de deployment estão no GIST, exibidos no conteúdo do artigo.

gustavobigardi/demo-aspnet-core-2_2-health-check-kubernetes
Demo de aplicação em ASP.NET Core 2.2 com Health Check, integrada ao Kubernetes - gustavobigardi/demo-aspnet-core-2_2-health-check-kubernetes

Espero que tenham gostado do artigo e caso tenham dúvidas ou queiram deixar um feedback, podem entrar em contato comigo aqui pelo Medium ou nas redes sociais.

Um abraço a todos e até a próxima.