Para serviços em execução no Kubernetes, usar uma malha de serviço como o Istio permite o rastreamento distribuído do tráfego de serviço a serviço sem a necessidade de instrumentação dedicada. No entanto, se você quer ter mais controle sobre os traces, talvez é necessário capturar os componentes internos do app nas informações de rastreamento ou rastrear o código que não está sendo executado no Kubernetes. O OpenCensus é uma biblioteca de código aberto que permite a instrumentação de aplicativos de microsserviço distribuídos para coletar traces e métricas em uma grande variedade de linguagens, plataformas e ambientes.
Este tutorial é destinado a desenvolvedores, SREs e engenheiros de DevOps que buscam entender os princípios básicos do rastreamento distribuído e aplicá-los aos serviços deles para melhorar a observabilidade do serviço.
Para este tutorial, consideramos que você esteja familiarizado com o seguinte:
- A linguagem de programação Go
- Google Kubernetes Engine (GKE)
Os relatórios State of DevOps identificaram recursos que impulsionam o desempenho da entrega de software. Este tutorial ajudará você com os seguintes recursos:
Objetivos
- Criar um cluster do GKE e implante um aplicativo de amostra.
- Revisar o código de instrumentação do OpenCensus.
- Revisar os traces e registros gerados pela instrumentação.
Arquitetura de referência
O diagrama a seguir mostra a arquitetura implantada neste tutorial.
Conforme ilustrado no diagrama anterior, você cria dois clusters do GKE e implanta um aplicativo em cada um deles. O tráfego do usuário é enviado para o aplicativo de front-end no cluster de front-end. O pod de front-end no cluster de front-end se comunica com o pod de back-end no cluster de back-end. O pod de back-end chama um endpoint de API externo.
Use o Cloud Build, uma plataforma de integração contínua, entrega e implantação totalmente gerenciada, para criar imagens de contêiner a partir do código de amostra e armazená-las no Container Registry. Os clusters do GKE extraem as imagens do Container Registry no momento da implantação.
Aplicativo de amostra
O aplicativo de amostra neste tutorial é composto por dois microsserviços escritos em Go.
O serviço de front-end aceita solicitações HTTP no URL /
e chama o serviço de back-end. O endereço do serviço de back-end é definido pela variável de ambiente BACKEND
. O valor dessa variável é definido em um objeto ConfigMap que você cria.
O serviço de back-end aceita solicitações HTTP no URL /
e faz uma chamada de saída para um URL externo, conforme definido na variável de ambiente DESTINATION_URL
. O valor da variável é definido por meio de um objeto ConfigMap
. Após a conclusão da chamada externa, o serviço backend
retorna a chamada de status HTTP, por exemplo, 200,
de volta ao autor da chamada.
Noções básicas sobre traces, períodos e contexto
O conceito de rastreamento distribuído é mais bem descrito no documento de pesquisa do Dapper (em inglês) publicado pelo Google. No artigo, o diagrama a seguir mostra cinco períodos em um trace.
O diagrama mostra uma única solicitação de front-end que faz duas solicitações de back-end. A segunda chamada de back-end requer que duas chamadas auxiliares sejam concluídas. Cada chamada é identificada com o código do período e o código do período pai.
Um trace é o total de informações que descrevem como um sistema distribuído responde a uma solicitação do usuário. Os traces são compostos por períodos, em que cada período representa uma solicitação e um par de resposta específicos envolvidos na exibição da solicitação do usuário. O período pai descreve a latência conforme observado pelo usuário final. Cada um dos períodos filhos descreve como um determinado serviço no sistema distribuído foi chamado e respondido, com informações de latência capturadas para cada um deles.
Um desafio com o rastreamento em sistemas distribuídos é que as informações sobre a solicitação de front-end original não são transportadas de forma automática ou herdada quando solicitações subsequentes são feitas para vários serviços de back-end. No Go, é possível fazer solicitações com contexto (o endereço IP e as credenciais do cluster), o que significa que informações adicionais são carregadas no cabeçalho HTTP. O conceito de contexto é estendido com o OpenCensus para incluir o contexto de período, em que é possível incluir informações sobre o período pai em cada solicitação subsequente. Em seguida, é possível anexar períodos filhos para compor o rastreamento geral. Assim, é possível ver como a solicitação do usuário passou pelo sistema e, por fim, foi atendida novamente.
O contexto não é específico do Go. Para mais informações sobre as linguagens em que o OpenCensus é compatível com o recurso SpanContext
, consulte a matriz de recursos do OpenCensus.
Custos
Neste tutorial, usamos os seguintes componentes faturáveis do Google Cloud:
Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem ser qualificados para uma avaliação gratuita.
Ao concluir este tutorial, exclua os recursos criados para evitar o faturamento contínuo. Para mais informações, consulte Como fazer a limpeza.
Antes de começar
-
Faça login na sua conta do Google.
Se você ainda não tiver uma, inscreva-se.
-
No Console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.
-
Verifique se o faturamento está ativado para seu projeto na nuvem. Saiba como confirmar se o faturamento está ativado para o projeto.
- Ative as APIs GKE, Cloud Trace, Cloud Build, Cloud Storage, and Container Registry.
Como configurar o ambiente
Nesta seção, você configurará seu ambiente com as ferramentas usadas ao longo deste tutorial. Todos os comandos de terminal neste tutorial são executados a partir do Cloud Shell.
-
No Console do Cloud, ative o Cloud Shell.
Na parte inferior do Console do Cloud, uma sessão do Cloud Shell é iniciada e exibe um prompt de linha de comando. O Cloud Shell é um ambiente com o SDK do Cloud pré-instalado com a ferramenta de linha de comando
gcloud
e os valores já definidos para seu projeto atual. A inicialização da sessão pode levar alguns segundos. - Defina as variáveis de ambiente:
export PROJECT_ID=$(gcloud config list --format 'value(core.project)' 2>/dev/null)
- Faça o download dos arquivos necessários para este tutorial clonando o seguinte repositório do GitHub:
git clone https://github.com/GoogleCloudPlatform/gke-observability-tutorials.git cd $HOME/gke-observability-tutorials/gke-opencensus-stackdriver/go/http WORKDIR=$(pwd)
A pasta do repositório torna-se sua
$WORKDIR
e, a partir dela, você realiza todas as tarefas relacionadas a este tutorial para poder excluí-la quando terminá-lo.
Instalar ferramentas
No Cloud Shell, instale
kubectx
ekubens
.git clone https://github.com/ahmetb/kubectx $WORKDIR/kubectx export PATH=$PATH:$WORKDIR/kubectx
Use essas ferramentas para trabalhar com vários clusters, contextos e namespaces do Kubernetes.
No Cloud Shell, instale o Apache Database, uma ferramenta de geração de carga de código aberto:
sudo apt-get install apache2-utils
Como criar clusters do GKE
Nesta seção, você criará dois clusters do GKE em que implantará o aplicativo de amostra. Por padrão, os clusters do GKE são criados com acesso somente gravação à API Cloud Trace. Portanto, não é necessário definir o acesso ao criar os clusters.
No Cloud Shell, crie os clusters:
gcloud container clusters create backend-cluster \ --zone=us-west1-a --enable-stackdriver-kubernetes \ --verbosity=none --async gcloud container clusters create frontend-cluster \ --zone=us-west1-a --enable-stackdriver-kubernetes \ --verbosity=none
Neste tutorial, os clusters estão na zona
us-west1-a
. Para mais informações, consulte Geografia e regiões.Consiga as credenciais do cluster e armazene-as localmente:
gcloud container clusters get-credentials backend-cluster --zone=us-west1-a gcloud container clusters get-credentials frontend-cluster --zone=us-west1-a
Renomeie os contextos dos clusters para facilitar o acesso a eles posteriormente no tutorial:
kubectx backend=gke_${PROJECT_ID}_us-west1-a_backend-cluster kubectx frontend=gke_${PROJECT_ID}_us-west1-a_frontend-cluster
Analisar a instrumentação do OpenCensus
Nas seções a seguir, revise o código do aplicativo de amostra para saber como usar a propagação de contexto para permitir que períodos de várias solicitações sejam anexados a um único rastreamento pai.
Revisar o código de front-end
Há três importações no código do serviço de front-end:
- As importações
go.opencensus.io/plugin/ochttp
ego.opencensus.io/plugin/ochttp/propagation/tracecontext
contêm o plug-inochttp
, que propaga o contexto entre as solicitações. O contexto carrega informações sobre o trace ao qual os períodos subsequentes são anexados. - A importação
contrib.go.opencensus.io/exporter/stackdriver
exporta traces para o Trace. Para ver a lista de back-ends compatíveis com o OpenCensus, consulte Exportadores (em inglês). - A importação
github.com/gorilla/mux
é a biblioteca que o app de amostra usa para processar solicitações.
- As importações
A função
main()
configura a exportação de traces para o Trace e usa um roteador mux para processar solicitações feitas ao URL/
:- O gerenciador está usando a propagação HTTP para adicionar contextos às solicitações.
- Neste tutorial, a amostragem está definida como
AlwaysSample
. Por padrão, as amostras do OpenCensus rastreiam a uma taxa predeterminada, que pode ser controlada usando esse parâmetro.
Revise a função
mainHandler()
:Essa função cria o período raiz para capturar a latência geral da solicitação. Você anexa períodos subsequentes ao período raiz.
// create root span ctx, rootspan := trace.StartSpan(context.Background(), "incoming call") defer rootspan.End()
Para cronometrar a chamada
backend
, a função cria um período filho.// create child span for backend call _, childspan := trace.StartSpan(ctx, "call to backend") defer childspan.End()
A função cria uma solicitação para o back-end.
// create request for backend call req, err := http.NewRequest("GET", backendAddr, nil) if err != nil { log.Fatalf("%v", err) } childCtx, cancel := context.WithTimeout(req.Context(), 1000*time.Millisecond) defer cancel() req = req.WithContext(childCtx)
A função adiciona o contexto do período a essa solicitação.
// add span context to backend call and make request format := &tracecontext.HTTPFormat{} format.SpanContextToRequest(rootspan.SpanContext(), req)
Revisar o código de back-end
A função
main()
para o código de back-end é idêntica à funçãomain()
do serviço de front-end. Ela configura o exportador do Trace e usa um roteador mux para processar solicitações feitas ao URL/
com a funçãomainHandler()
.A função
mainHandler()
usa a solicitação recebida para receber o contexto HTTP fornecido pelo Go e o contexto de trace fornecido pelo OpenCensus. A partir daí, a função cria um período filho e anexa ao contexto do trace. Por fim, ela chama a funçãocallRemoteEndpoint()
para fazer outra chamada com a latência que precisa ser capturada.A função
callRemoteEndpoint()
usa a biblioteca HTTP para fazer uma chamada de endpoint remoto. Como o rastreamento dessa chamada é processado na função pai, ele não precisa consumir o contexto do trace ou criar mais períodos filhos.
Implantar o aplicativo
Nesta seção, você usará o Cloud Build para criar imagens de contêiner para os serviços de back-end e front-end e implantá-los nos clusters do GKE.
Criar o serviço de back-end
No Cloud Shell, mude para o diretório
backend
:cd $WORKDIR/backend/
Envie o build:
gcloud builds submit . --tag=gcr.io/$PROJECT_ID/backend:latest
Confirme se a imagem do contêiner foi criada e está disponível no Container Registry:
gcloud container images list
A imagem do contêiner foi criada com sucesso quando a saída é semelhante a esta, em que
project-id
é o código do projeto do Cloud:NAME gcr.io/project-id/backend
Implantar o serviço de back-end
No Cloud Shell, defina o contexto
kubectx
para o clusterbackend
:kubectx backend
Implante o arquivo
configmap
:export PROJECT_ID=$(gcloud info --format='value(config.project)') envsubst < backend-configmap.yaml | kubectl apply -f -
Crie o arquivo de implantação
backend
:envsubst < backend-deployment.yaml | kubectl apply -f -
Confirme se os pods estão em execução:
kubectl get pods
A saída exibe um
Status
deRunning
:NAME READY STATUS RESTARTS AGE backend-645859d95b-7mx95 1/1 Running 0 52s backend-645859d95b-qfdnc 1/1 Running 0 52s backend-645859d95b-zsj5m 1/1 Running 0 52s
Exponha a implantação
backend
usando um balanceador de carga:kubectl expose deployment backend --type=LoadBalancer
Consiga o endereço IP do serviço
backend
:kubectl get services backend
A saída será assim:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE backend LoadBalancer 10.11.247.58 34.83.88.143 8080:30714/TCP 70s
Repita esse comando até que o campo
EXTERNAL-IP
do serviço seja alterado de<pending>
para um endereço IP.Capture o endereço IP da etapa anterior como uma variável:
export BACKEND_IP=$(kubectl get svc backend -ojson | jq -r '.status.loadBalancer.ingress[].ip')
Criar o serviço de front-end
No Cloud Shell, mude para o diretório
frontend
:cd $WORKDIR/frontend/
Envie o build:
gcloud builds submit . --tag=gcr.io/$PROJECT_ID/frontend:latest
Confirme se a imagem do contêiner foi criada e está disponível no Container Registry:
gcloud container images list
A imagem do contêiner foi criada com sucesso quando a saída é semelhante a esta:
NAME gcr.io/qwiklabs-gcp-47a7dcba55b334f7/backend gcr.io/qwiklabs-gcp-47a7dcba55b334f7/frontend
Implantar o serviço de front-end
No Cloud Shell, defina o contexto
kubectx
como o cluster de back-end:kubectx frontend
Implante o arquivo
configmap
:export PROJECT_ID=$(gcloud info --format='value(config.project)') envsubst < frontend-configmap.yaml | kubectl apply -f -
Crie o arquivo de implantação
frontend
:envsubst < frontend-deployment.yaml | kubectl apply -f -
Confirme se os pods estão em execução:
kubectl get pods
A saída exibe um
Status
deRunning
:NAME READY STATUS RESTARTS AGE frontend-747b445499-v7x2w 1/1 Running 0 57s frontend-747b445499-vwtmg 1/1 Running 0 57s frontend-747b445499-w47pf 1/1 Running 0 57s
Exponha a implantação
frontend
usando um balanceador de carga:kubectl expose deployment frontend --type=LoadBalancer
Consiga o endereço IP do serviço
frontend
:kubectl get services frontend
A saída será assim:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE frontend LoadBalancer 10.27.241.93 34.83.111.232 8081:31382/TCP 70s
Repita esse comando até que o campo
EXTERNAL-IP
do serviço seja alterado de<pending>
para um endereço IP.Capture o endereço IP da etapa anterior como uma variável:
export FRONTEND_IP=$(kubectl get svc frontend -ojson | jq -r '.status.loadBalancer.ingress[].ip')
Carregar o app e analisar os traces
Nesta seção, você usará o utilitário Apache Database para criar solicitações para o aplicativo e revisar os traces resultantes no Trace.
No Cloud Shell, use o Apache Database para gerar 1.000 solicitações com três linhas de execução simultâneas:
ab -c 3 -n 1000 http://${FRONTEND_IP}:8081/
No Console do Cloud, acesse a página Lista de traces.
Para revisar o cronograma, clique em um dos URIs marcados como
incoming call
.Esse trace contém três períodos com os seguintes nomes:
- O período
incoming call
captura a latência completa observada pelo cliente. - O período
call to backend
captura a latência da chamada de back-end observada pelo front-end. - O período
call remote endpoint
captura a latência da chamada do endpoint externo observada pelo back-end.
- O período
Como fazer a limpeza
A maneira mais fácil de eliminar o faturamento é excluir o projeto do Cloud que você criou para o tutorial. A outra opção é excluir os recursos individuais.Exclua o projeto
- No Console do Cloud, acesse a página Gerenciar recursos:
- Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
- Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.
A seguir
- Saiba mais sobre o OpenCensus.
- Saiba mais sobre o rastreamento distribuído com o OpenCensus (em inglês).
- Saiba mais sobre a propagação de contexto HTTP no Go (em inglês).
- Teste outros recursos do Google Cloud. Veja os tutoriais.
- Leia nossos recursos sobre DevOps.
- Saiba mais sobre os recursos de DevOps relacionados a este tutorial:
- Faça a verificação rápida de DevOps para entender sua posição em relação ao restante do setor.