Voltar aos microsserviços com Istio. Parte 1



Nota perev. : Malhas de serviço definitivamente se tornaram uma solução relevante na infraestrutura moderna para aplicativos que seguem a arquitetura de microsserviço. Embora o Istio possa ser ouvido por muitos engenheiros do DevOps, é um produto relativamente novo, que, sendo abrangente em termos dos recursos fornecidos, pode exigir um tempo considerável para se conhecer. O engenheiro alemão Rinor Maloku, responsável pela computação em nuvem para grandes clientes da empresa de telecomunicações Orange Networks, escreveu uma maravilhosa série de materiais que permitem que você mergulhe rápida e profundamente no Istio. Ele começa sua história com o que Istio pode fazer e como você pode vê-la rapidamente com seus próprios olhos.

Istio é um projeto de código aberto desenvolvido em colaboração com equipes do Google, IBM e Lyft. Ele resolve as dificuldades que surgem em aplicativos baseados em microsserviços, por exemplo, como:

  • Gerenciamento de tráfego : tempos limite, novas tentativas, balanceamento de carga;
  • Segurança : autenticação e autorização do usuário final;
  • Observabilidade : rastreamento, monitoramento, registro.

Todos eles podem ser resolvidos no nível do aplicativo, mas depois disso seus serviços deixarão de ser "micro". Todos os esforços adicionais para resolver esses problemas são um desperdício extra de recursos da empresa que podem ser usados ​​diretamente para os valores de negócios. Considere um exemplo:
Gerente de projeto: quanto tempo adicionar feedback?
Desenvolvedor: Dois sprints.

MP: O quê? .. É apenas CRUD!
R: Criar CRUD é uma parte simples da tarefa, mas ainda precisamos autenticar e autorizar usuários e serviços. Como a rede não é confiável, você precisará implementar solicitações repetidas, bem como o padrão do disjuntor nos clientes. Ainda assim, para garantir que todo o sistema não caia, você precisará de tempos limites e anteparas (para obter mais detalhes sobre os dois padrões mencionados, veja mais no artigo - aprox. Transl.) E para detectar problemas, será necessário monitorar, rastrear, [...]

MP: Ah, então vamos apenas inserir esse recurso no serviço do produto.
Penso que a ideia é clara: o volume de etapas e esforços necessários para adicionar um serviço é enorme. Neste artigo, veremos como o Istio remove todas as dificuldades mencionadas acima (que não são direcionadas para a lógica de negócios) dos serviços.



Nota : Este artigo pressupõe que você tenha conhecimento prático do Kubernetes. Caso contrário, recomendo a leitura da minha introdução ao Kubernetes e só depois continuarei a ler este material.

Idea Istio


Em um mundo sem o Istio, um serviço faz solicitações diretas a outro e, em caso de falha, o serviço deve processá-lo: faça uma nova tentativa, forneça um tempo limite, abra um disjuntor, etc.


Tráfego de rede em Kubernetes

O Istio também oferece uma solução especializada, completamente separada dos serviços e funcionando, interferindo na interação da rede. E assim implementa:

  • Tolerância a falhas : com base no código de status na resposta, ele entende se a solicitação falhou e a executa novamente.
  • Lançamentos das Canárias : redireciona para a nova versão do serviço apenas uma porcentagem fixa do número de solicitações.
  • Monitoramento e métricas : por quanto tempo o serviço respondeu?
  • Rastreamento e observabilidade : adiciona cabeçalhos especiais a cada solicitação e os rastreia no cluster.
  • Segurança : extrai o token JWT, autentica e autoriza usuários.

Estas são apenas algumas das possibilidades (realmente apenas algumas!) Para intrigá-lo. Agora vamos mergulhar nos detalhes técnicos!

Arquitetura Istio


O Istio intercepta todo o tráfego de rede e aplica um conjunto de regras, inserindo um proxy inteligente em cada pod na forma de um contêiner lateral. Os proxies que ativam todos os recursos formam um Data Plane e podem ser configurados dinamicamente usando o Control Plane .

Plano de dados


Os proxies inseridos nos pods permitem que o Istio atenda facilmente aos requisitos de que precisamos. Por exemplo, verifique as funções de repetição e disjuntor.


Como tentativas e interrupção de circuito são implementadas no Envoy

Para resumir:

  1. Enviado (falando sobre um proxy em um contêiner lateral que é distribuído como um produto separado - aprox. Transl.) Envia uma solicitação para a primeira instância do serviço B e ocorre uma falha.
  2. O enviado Sidecar tenta novamente . (1)
  3. A solicitação com falha é retornada ao proxy que a chamou.
  4. Isso abre o disjuntor e chama o próximo serviço para solicitações subsequentes. 2)

Isso significa que você não precisa usar a próxima biblioteca Repetir, não precisa executar sua própria implementação de Descoberta de circuitos e descoberta de serviços na linguagem de programação X, Y ou Z. Tudo isso e muito mais está disponível imediatamente no Istio e não requer alterações no código.

Ótimo! Agora você pode querer fazer uma viagem com o Istio, mas ainda há algumas dúvidas, perguntas em aberto. Se essa é uma solução universal para todas as ocasiões da vida, você tem uma suspeita legítima: afinal, todas essas decisões na realidade acabam sendo inadequadas para qualquer ocasião.

E, finalmente, você pergunta: "É personalizável?"

Agora você está pronto para uma viagem marítima - e vamos nos familiarizar com o Plano de Controle.

Plano de controle


Ele consiste em três componentes: Pilot , Mixer e Citadel , que trabalham juntos para configurar Envoys para rotear tráfego, aplicar políticas e coletar dados de telemetria. Esquematicamente, tudo se parece com isso:


Interação do plano de controle com o plano de dados

Os enviados (ou seja, plano de dados) são configurados usando o Kubernetes CRD (Definições de Recursos Personalizados) definido pelo Istio e projetado especificamente para essa finalidade. Para você, isso significa que eles parecem ser o próximo recurso no Kubernetes com sintaxe familiar. Após a criação, esse recurso será capturado pelo plano de controle e aplicado aos enviados.

Relação de serviço para Istio


Descrevemos a atitude do Istio em relação aos serviços, mas não o oposto: como os serviços se relacionam com o Istio?

Honestamente, o Istio conhece a presença de serviços e peixes - sobre a água, quando se perguntam: “O que é a água em geral?”.


Ilustração de Victoria Dimitrakopoulos : - Como você gosta da água? - O que é água em geral?

Assim, você pode pegar o cluster de trabalho e, após a implantação dos componentes do Istio, os serviços localizados nele continuarão funcionando e, após a remoção desses componentes, tudo ficará bem novamente. É claro que, ao fazer isso, você perderá as oportunidades oferecidas pelo Istio.

Teoria suficiente - vamos colocar esse conhecimento em prática!

Istio na prática


O Istio requer um cluster Kubernetes no qual estão disponíveis pelo menos 4 vCPUs e 8 GB de RAM. Para aumentar rapidamente o cluster e seguir as instruções do artigo, recomendo usar o Google Cloud Platform, que oferece aos novos usuários US $ 300 grátis .

Depois de criar um cluster e configurar o acesso ao Kubernetes através do utilitário do console, você pode instalar o Istio através do gerenciador de pacotes Helm.

Instalação do leme


Instale o cliente Helm no seu computador, como eles dizem na documentação oficial . Nós o usaremos para gerar modelos para instalar o Istio na próxima seção.

Instale o Istio


Faça o download dos recursos do Istio da versão mais recente (o link do autor original para a versão 1.0.5 é alterado para o atual, ou seja, 1.0.6 - aprox. Transl.) , Extraia o conteúdo para um diretório, que chamarei no futuro [istio-resources] .

Para facilitar a identificação dos recursos do Istio, crie o namespace istio-system no cluster K8s:

 $ kubectl create namespace istio-system 

Conclua a instalação indo para o [istio-resources] e executando o comando:

 $ helm template install/kubernetes/helm/istio \ --set global.mtls.enabled=false \ --set tracing.enabled=true \ --set kiali.enabled=true \ --set grafana.enabled=true \ --namespace istio-system > istio.yaml 

Este comando produzirá os principais componentes do Istio no arquivo istio.yaml . Alteramos o modelo padrão para nós mesmos, especificando os seguintes parâmetros:

  • global.mtls.enabled definido como false (ou seja, a autenticação mTLS está desativada - aprox. transl.) para simplificar nosso processo de namoro;
  • tracing.enabled ativa o rastreamento de consultas usando o Jaeger;
  • kiali.enabled instala o Kiali em um cluster para visualizar serviços e tráfego;
  • grafana.enabled define o Grafana para visualizar as métricas coletadas.

Aplicamos os recursos gerados com o comando:

 $ kubectl apply -f istio.yaml 

A instalação do Istio no cluster está concluída! Aguarde até que todos os pods no espaço de nomes istio-system estejam em Running ou Completed executando o comando abaixo:

 $ kubectl get pods -n istio-system 

Agora estamos prontos para continuar na próxima seção, onde criaremos e iniciaremos o aplicativo.

Arquitetura de aplicativos de análise de sentimentos


Vamos dar um exemplo do aplicativo de microsserviço Sentiment Analysis usado no artigo de introdução já mencionado no Kubernetes . É sofisticado o suficiente para mostrar as capacidades do Istio na prática.

O aplicativo consiste em quatro microsserviços:

  1. Serviço SA-Frontend , que atende a aplicativos front-end no Reactjs;
  2. Um serviço SA-WebApp que atende solicitações de análise de sentimentos;
  3. Serviço SA-Logic , que realiza análise sentimental ;
  4. Serviço SA-Feedback , que recebe feedback dos usuários sobre a precisão da análise.



Neste diagrama, além dos serviços, também vemos o Controlador de ingresso, que no Kubernetes roteia solicitações de entrada para os serviços correspondentes. O Istio usa um conceito semelhante no Ingress Gateway, cujos detalhes serão apresentados a seguir.

Iniciando um aplicativo com um proxy do Istio


Para as operações adicionais mencionadas no artigo, clone o repositório istio-mastery . Ele contém o aplicativo e se manifesta para Kubernetes e Istio.

Inserção lateral


A inserção pode ser feita automática ou manualmente . Para inserir automaticamente contêineres laterais, é necessário definir o istio-injection=enabled para o istio-injection=enabled , o que é feito pelo seguinte comando:

 $ kubectl label namespace default istio-injection=enabled namespace/default labeled 

Agora, cada pod que será implantado no espaço para nome padrão receberá seu contêiner lateral. Para verificar isso, vamos instalar um aplicativo de teste acessando o diretório raiz do [istio-mastery] e executando o seguinte comando:

 $ kubectl apply -f resource-manifests/kube persistentvolumeclaim/sqlite-pvc created deployment.extensions/sa-feedback created service/sa-feedback created deployment.extensions/sa-frontend created service/sa-frontend created deployment.extensions/sa-logic created service/sa-logic created deployment.extensions/sa-web-app created service/sa-web-app created 

Após a expansão dos serviços, verificaremos se os pods têm dois contêineres (com o próprio serviço e seu side-car), executando o comando kubectl get pods e certificando-se de que o valor 2/2 indicado na coluna READY , simbolizando que os dois contêineres estão em execução:

 $ kubectl get pods NAME READY STATUS RESTARTS AGE sa-feedback-55f5dc4d9c-c9wfv 2/2 Running 0 12m sa-frontend-558f8986-hhkj9 2/2 Running 0 12m sa-logic-568498cb4d-2sjwj 2/2 Running 0 12m sa-logic-568498cb4d-p4f8c 2/2 Running 0 12m sa-web-app-599cf47c7c-s7cvd 2/2 Running 0 12m 

Visualmente, fica assim:


Enviar proxies em um dos pods

Agora que o aplicativo está em funcionamento, precisamos permitir que o tráfego recebido entre no aplicativo.

Gateway de ingresso


A melhor prática para conseguir isso (para permitir tráfego no cluster) é por meio do Gateway de ingresso no Istio, localizado na "borda" do cluster e permite ativar os recursos do Istio, como roteamento, balanceamento de carga, segurança e monitoramento do tráfego recebido.

O componente Ingress Gateway e o serviço que o encaminha para fora foram instalados no cluster durante a instalação do Istio. Para descobrir o endereço IP externo de um serviço, faça:

 $ kubectl get svc -n istio-system -l istio=ingressgateway NAME TYPE CLUSTER-IP EXTERNAL-IP istio-ingressgateway LoadBalancer 10.0.132.127 13.93.30.120 

Continuaremos a acessar o aplicativo por esse IP (vou me referir a ele como IP EXTERNO); portanto, por conveniência, escreveremos o valor em uma variável:

 $ EXTERNAL_IP=$(kubectl get svc -n istio-system \ -l app=istio-ingressgateway \ -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') 

Se você tentar acessar esse IP através de um navegador agora, receberá um erro de Serviço Indisponível, porque Por padrão, o Istio bloqueia todo o tráfego recebido até que um Gateway seja definido.

Recurso de gateway


O Gateway é um CRD (Custom Resource Definition) no Kubernetes, definido após a instalação do Istio em um cluster e ativar a capacidade de especificar as portas, protocolos e hosts para os quais queremos permitir o tráfego de entrada.

No nosso caso, queremos permitir o tráfego HTTP na porta 80 para todos os hosts. A tarefa é implementada pela seguinte definição ( http-gateway.yaml ) :

 apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: http-gateway spec: selector: istio: ingressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" 

Essa configuração não precisa de explicação, exceto pelo istio: ingressgateway . Com esse seletor, podemos indicar a qual gateway de ingresso a configuração é aplicada. No nosso caso, este é o controlador do Ingress Gateway, que foi instalado por padrão no Istio.

A configuração é aplicada chamando o seguinte comando:

 $ kubectl apply -f resource-manifests/istio/http-gateway.yaml gateway.networking.istio.io/http-gateway created 

Agora, o gateway permite acesso à porta 80, mas não tem idéia de onde rotear solicitações. Isso exigirá serviços virtuais .

Recurso VirtualService


O VirtualService informa ao Ingress Gateway como rotear solicitações permitidas no cluster.

Solicitações para nosso aplicativo enviadas via gateway http devem ser enviadas aos serviços sa-frontend, sa-web-app e sa-feedback:


Rotas para configurar com o VirtualServices

Considere os pedidos que devem ser enviados ao SA-Frontend:

  • Uma correspondência exata no caminho / deve ser enviada ao SA-Frontend para obter o index.html;
  • Os caminhos prefixados com /static/* devem ser enviados ao SA-Frontend para receber arquivos estáticos usados ​​no frontend, como CSS e JavaScript;
  • Os caminhos que correspondem à expressão regular '^.*\.(ico|png|jpg)$' devem ser enviados ao SA-Frontend, como Estas são as imagens exibidas na página.

A implementação é alcançada pela seguinte configuração ( sa-virtualservice-external.yaml ):

 kind: VirtualService metadata: name: sa-external-services spec: hosts: - "*" gateways: - http-gateway # 1 http: - match: - uri: exact: / - uri: exact: /callback - uri: prefix: /static - uri: regex: '^.*\.(ico|png|jpg)$' route: - destination: host: sa-frontend # 2 port: number: 80 

Pontos importantes:

  1. Este VirtualService refere-se a solicitações provenientes do gateway http ;
  2. destination define o serviço para o qual as solicitações são enviadas.

Nota : A configuração acima é armazenada no arquivo sa-virtualservice-external.yaml , que também contém as configurações de roteamento no SA-WebApp e no SA-Feedback, mas foi abreviado aqui no artigo por questões de brevidade.

Aplique o VirtualService chamando:

 $ kubectl apply -f resource-manifests/istio/sa-virtualservice-external.yaml virtualservice.networking.istio.io/sa-external-services created 

Nota : Quando usamos os recursos do Istio, o servidor da API do Kubernetes gera um evento que recebe o Istio Control Plane e, depois disso, a nova configuração é aplicada aos proxies Envoy de cada pod. E o controlador do Ingress Gateway parece ser o próximo enviado configurado no Control Plane. Tudo isso no diagrama é assim:


Configuração do Istio-IngressGateway para roteamento de consulta

A Análise de sentimentos ficou disponível em http://{EXTERNAL-IP}/ . Não se preocupe se você receber o status Não encontrado: às vezes leva um pouco mais para a configuração entrar em vigor e os caches do Envoy serem atualizados .

Antes de prosseguir, trabalhe um pouco com o aplicativo para gerar tráfego (sua presença é necessária para maior clareza nas próximas etapas - aprox. Transl.) .

Kiali: Observabilidade


Para acessar a interface administrativa do Kiali, execute o seguinte comando:

 $ kubectl port-forward \ $(kubectl get pod -n istio-system -l app=kiali \ -o jsonpath='{.items[0].metadata.name}') \ -n istio-system 20001 

... e abra http: // localhost: 20001 / , efetuando login como admin / admin. Aqui você encontrará muitos recursos úteis, por exemplo, para verificar a configuração dos componentes do Istio, visualizar serviços com base nas informações coletadas ao interceptar solicitações de rede e receber respostas para as perguntas "Quem está entrando em contato com quem?", "Qual versão do serviço está travando?" etc. Em geral, explore as possibilidades do Kiali antes de visualizar métricas com o Grafana.



Grafana: visualização de métricas


As métricas coletadas no Istio entram no Prometheus e visualizadas com Grafana. Para acessar a interface de administração do Grafana, execute o comando abaixo e abra http: // localhost: 3000 / :

 $ kubectl -n istio-system port-forward \ $(kubectl -n istio-system get pod -l app=grafana \ -o jsonpath={.items[0].metadata.name}) 3000 

Ao clicar no menu inicial no canto superior esquerdo e selecionar o Istio Service Dashboard no canto superior esquerdo, comece com o serviço sa-web-app para examinar as métricas coletadas:



Aqui estamos aguardando um desempenho vazio e completamente chato - a gerência nunca aprovará isso. Vamos criar uma pequena carga com o seguinte comando:

 $ while true; do \ curl -i http://$EXTERNAL_IP/sentiment \ -H "Content-type: application/json" \ -d '{"sentence": "I love yogobella"}'; \ sleep .8; done 

Agora, temos gráficos muito mais agradáveis ​​e, além deles, ferramentas maravilhosas do Prometheus para monitoramento e Grafana para visualização de métricas, o que nos permitirá aprender sobre o desempenho, status de saúde, melhorias / degradação dos serviços ao longo do tempo.

Por fim, vejamos o rastreamento de solicitações nos serviços.

Jaeger: trace


Precisamos rastrear, porque quanto mais serviços tivermos, mais difícil será chegar à causa da falha. Vejamos um caso simples da figura abaixo:


Um exemplo típico de uma solicitação com falha aleatória

O pedido vem, cai - qual é o motivo? Primeiro serviço? Ou o segundo? Há exceções em ambos - vamos examinar os logs de cada um. Quantas vezes você se encontra fazendo isso? Nosso trabalho é mais como detetives de software do que desenvolvedores ...

Esse é um problema generalizado nos microsserviços e é resolvido por sistemas de rastreamento distribuídos nos quais os serviços passam um ao outro por um cabeçalho exclusivo, após o qual essas informações são redirecionadas para o sistema de rastreamento, onde são mapeadas para os dados da solicitação. Aqui está uma ilustração:


TraceId é usado para identificar a solicitação.

O Istio usa o Jaeger Tracer, que implementa uma estrutura de API do OpenTracing independente do fornecedor. Você pode acessar a interface do usuário do Jaeger com o seguinte comando:

 $ kubectl port-forward -n istio-system \ $(kubectl get pod -n istio-system -l app=jaeger \ -o jsonpath='{.items[0].metadata.name}') 16686 

Agora vá para http: // localhost: 16686 / e selecione o serviço sa-web-app . Se o serviço não for mostrado no menu suspenso, mostre / gere atividade na página e atualize a interface. Depois disso, clique no botão Localizar rastreamentos, que mostrará os rastreamentos mais recentes - selecione qualquer - informações detalhadas sobre todos os rastreamentos serão exibidas:



Este rastreio mostra:

  1. A solicitação chega ao istio-ingressgateway (esta é a primeira interação com um dos serviços e o ID de rastreamento é gerado para a solicitação), após o qual o gateway envia a solicitação ao serviço de aplicativo da web sa .
  2. No serviço sa-web-app, a solicitação é atendida pelo envoy sidecar, um "filho" é criado no período (portanto, vemos nos rastreamentos) e redirecionado para o contêiner sa-web-app . ( Span é uma unidade lógica de trabalho em Jaeger que possui um nome, o horário em que a operação foi iniciada e sua duração. Os períodos podem ser aninhados e ordenados. Um gráfico acíclico direcionado dos períodos forma um traço. - aprox. Transl.)
  3. Aqui, a solicitação é processada pelo método sentimentAnalysis . Esses rastreamentos já são gerados pelo aplicativo, ou seja, eles exigiram alterações no código.
  4. A partir deste momento, uma solicitação POST para sa-logic é iniciada. O ID de rastreamento deve ser encaminhado a partir do sa-web-app .
  5. ...

Nota : Na etapa 4, o aplicativo deve ver os cabeçalhos gerados pelo Istio e passá-los para solicitações subsequentes, conforme mostrado na imagem abaixo:


(A) Istio é responsável por encaminhar os cabeçalhos; (B) Os serviços são responsáveis ​​pelos cabeçalhos.

Istio faz a maior parte do trabalho, como gera cabeçalhos para solicitações recebidas, cria novas extensões em cada cuidado lateral e as encaminha. No entanto, sem trabalhar com os cabeçalhos dentro dos serviços, o caminho completo de rastreamento da solicitação será perdido.

Os seguintes títulos devem ser considerados (encaminhados):

 x-request-id x-b3-traceid x-b3-spanid x-b3-parentspanid x-b3-sampled x-b3-flags x-ot-span-context 

Entretanto, para simplificar sua implementação, é uma tarefa simples, já existem muitas bibliotecas - por exemplo, no serviço sa-web-app, o cliente RestTemplate encaminha esses cabeçalhos se você adicionar as bibliotecas Jaeger e OpenTracing, dependendo dele .

Observe que o aplicativo Sentiment Analysis demonstra implementações no Flask, Spring e ASP.NET Core.

Agora que ficou claro o que estamos obtendo da caixa (ou quase “pronto para uso”), consideraremos questões de roteamento bem ajustado, gerenciamento de tráfego de rede, segurança, etc.!

Nota perev. : Leia sobre isso na próxima edição do Istio de Rinor Maloku, que estará disponível em nosso blog em um futuro próximo. ATUALIZAÇÃO (14 de março): A segunda parte já foi publicada.

PS do tradutor


Leia também em nosso blog:

Source: https://habr.com/ru/post/pt438426/


All Articles