Health Checks com Kubernetes e gRPC

3Bit Technologies
6 min readApr 1, 2021

Apesar de muitas aplicações e serviços se comunicarem através de HTTP, há algum tempo é possível notar o crescimento do uso do protocolo gRPC, principalmente em casos onde a eficiência e desempenho são críticos para uma aplicação ou serviço.

Mas toda esta eficiência pode ser comprometida ao deixar de implementar corretamente um mecanismo de Health Check, principalmente utilizando Kubernetes. E é este tema que vamos abordar hoje neste post, através de um exemplo simples de serviço gRPC com tratamento correto de health check, para uso no Kubernetes.

Antes de iniciar, é importante comentar que o gRPC é um protocolo binário baseado em HTTP/2 e protobuf, foi desenvolvido pela Google em 2015, e que além do alto desempenho e leveza, tem como característica a portabilidade em diversas linguagens. Também vale citar que está sob cuidados da Cloud Native Computing Foundation, ponto positivo para uma evolução estável.

Devido a estas características, o gRPC combina com a arquitetura de micros serviços, e consequentemente, com Kubernetes. Mas, apesar desta sinergia entre as tecnologias, os métodos nativos de health check do Kubernetes não suportam o gRPC. E uma implementação incompleta deste item pode oferecer comportamentos indesejados no ambiente em execução, incluindo a indisponibilidades da aplicação.

Abaixo temos três formas possíveis, mas não ideais de health check no Kubernetes com gRPC.

Nas seções seguintes mostramos uma quarta opção mais adequada, através de um exemplo prático, e que pode ser facilmente testada localmente.

Aplicação utilizando gRPC

Para o nosso exemplo vamos criar uma aplicação simples em Golang 1.14, dividida em cliente e servidor, onde o cliente pode enviar uma requisição definida pelo contrato abaixo (proto), e em seguida receber a resposta do servidor com o texto ‘Hello’ concatenado com o nome presente na requisição.

Como resultado final em uma visão macro, vamos ter os seguintes componentes em funcionamento:

Para acompanhamento, o código fonte pode ser obtido em https://github.com/3bit-techs/k8s-grpc-health-check.

Também disponibilizamos a imagem docker no Dockerhub já contendo a aplicação servidor compilada, para facilitar o teste com o Kubernetes. Mas a imagem pode ser customizada e gerada novamente através dos targets do Makefile.

Implementação do Cliente

Abaixo temos a implementação do cliente, que conecta no servidor gRPC, definido pelo endereço localhost:8888, em seguida envia uma requisição com o nome fixo ‘John’, obtém e imprime o retorno na console.

Implementação do Health Check

Antes de criarmos o servidor, precisamos definir o serviço de Health Check que será utilizado. Para isso basta seguir o formato padrão definido pelo protocolo gRPC, que já disponibiliza uma estrutura de dados pré-definida (proto file), o que é interessante, pois permite que qualquer linguagem ou ferramenta possa obter o status de uma aplicação apenas seguindo o padrão definido pelo gRPC:

Note que temos dois serviços a serem implementados: Check e Watch, onde Check é para consultar o status em um formato de request/response, e Watch para consultar o status em formato streaming.

Outro detalhe importante é que não precisamos copiar esta definição para dentro do projeto Go, ela já está disponível na importação do pacote google.golang.org/grpc/health/grpc_health_v1.

Implementação do Health Check gRPC

Ao implementar os métodos Watch e Check acima, também adicionamos uma simulação de indisponibilidade, que ocorre quando o serviço tem mais de dois minutos de atividade, passando do status SERVING para NOT_SERVING. Essa simulação vai nos ajudar a validar a atuação do Kubernetes na aplicação.

Implementação do Servidor

Abaixo temos a codificação do servidor, que além do serviço principal HelloWorld estar registrado para atender as requisições, também é preciso registrar o serviço de Health Check implementado na seção anterior, para que responda as requisições efetuadas pelo Kubernetes e seu mecanismo de probes.

Iniciando Kubernetes localmente

Para criarmos a infraestrutura Kubernetes local vamos fazer uso do Kind, mas pode-se utilizar outra opção, como por exemplo, o Minikube, ou um servidor Kubernetes da sua nuvem preferida:

Pré-requisitos

  1. Kubernetes cli (kubectl)
  2. Docker (necessário para o funcionamento do Kind)

Para utilizar o Kind é simples, basta seguir o passo a passo de instalação para o seu sistema operacional, e criar o cluster a partir da cli com o seguinte comando:

kind create cluster — image kindest/node:v1.20.2

Em seguida, conferir a instalação:

kubectl cluster-info — context kind-kind

Efetuando deploy da Aplicação no Kubernetes

Com o cluster Kubernetes no ar, vamos provisionar a aplicação criando o manifesto com os componentes Deployment e Service.

No Deployment também vamos definir a configuração das probes utilizando a ferramenta padrão grpc-health-probe, já adicionada na imagem 3bittechs/k8s-grpc-server:1.0 através do Dockerfile. Esta ferramenta segue o padrão definido pelo gRPC, e é responsável por efetuar a chamada aos serviços de Health Check registrados na implementação do Servidor:

Em seguida aplicamos o manifesto no namespace default:

kubectl apply -f k8s-manifests/k8s-grpc-server.yaml -n default

deployment.apps/grpc-server created
service/grpc-server created

E verificamos se a aplicação grpc-server está no ar, isso pode ser feito executando o cliente. Para isso, primeiro crie a conectividade com o serviço grpc-server através do port-forward:

kubectl port-forward svc/grpc-server 8888:8888

E através do código fonte obtido, execute o cliente através do comando go run:

go run client/client.go

2021/03/30 19:40:14 message:”Hello John”
2021/03/30 19:40:14 End calling HelloWorld on the server

Verificando as probes e health check gRPC

Com a aplicação em funcionamento e validada, é o momento de verificar o comportamento do Health Check implementado. E, como comentamos anteriormente, adicionamos uma lógica que indica indisponibilidade da aplicação grpc-server após dois minutos de funcionamento, este mecanismo é apenas uma simulação de falha, mas que na sua aplicação deve ser feito de forma precisa, indicando a real situação. Por este motivo, é esperado que ocorra a reinicialização (self healing) do pod algumas vezes, efetuada pelo kublet quando identificada falha nas probes. Isso pode ser comprovado através dos seguintes comandos:

kubectl get all -l app=grpc-server

Restarts=1

kubectl describe pod -l app=grpc-server

Liveness probe e Readiness probe failed!

Veja que as falhas das probes ao consultar o serviço de Health Check indicam que a aplicação não esta saudável, e o Kubernetes atua para reinicialização do grpc-server, como forma de recuperar a aplicação.

Conclusão

Uma aplicação crítica, que faz uso de linguagem, protocolo e plataforma de orquestração de alta performance, ainda assim pode não ter o resultado esperado se alguns detalhes são deixados de lado. Um Health Check construído de forma adequada é um destes detalhes importantes a serem levados em consideração, e tem papel crucial para o funcionamento e resiliência na aplicação.

Esperamos que você tenha gostado desse post tanto quanto nós, e se você tiver alguma dúvida, não hesite em nos contactar!

Quer saber mais? Não se esqueça de nos visitar em https://3bit.com.br/

--

--

3Bit Technologies

Cloud Specialists providing professional services with DevOps, BigData, Cloud Native Applications and Security. https://www.3bit.com.br/3bit