Na parte anterior analisamos os componentes básicos do Service Mesh Istio, conhecemos o sistema e respondemos às perguntas principais que costumam surgir no início do trabalho com o Istio. Nesta parte, veremos como organizar a coleta de informações de rastreamento pela rede.

A primeira coisa que vem à mente de muitos desenvolvedores e administradores de sistemas ao ouvir as palavras Service Mesh é o rastreamento. E realmente, adicionamos um proxy especial em cada nó da rede, pelo qual passa todo o tráfego TCP. Parece que agora podemos facilmente enviar informações sobre todas as interações de rede. Infelizmente, na prática, surgem muitos detalhes que precisam ser considerados. Vamos analisá-los.
Equívoco número um: podemos obter dados sobre a navegação na rede gratuitamente
Na verdade, relativamente de graça, só podemos obter os nós do nosso sistema conectados por setas e a taxa de dados que passa entre os serviços (na essência — apenas a quantidade de bytes por unidade de tempo). No entanto, na maioria dos casos, nossos serviços se comunicam por algum protocolo de camada de aplicação, como HTTP, gRPC, Redis e assim por diante. E, claro, queremos ver informações de rastreamento exatamente por esses protocolos, queremos ver a taxa de requisições, e não a taxa de dados. Queremos entender a latência das requisições de acordo com nosso protocolo. Finalmente, queremos ver o caminho completo que a requisição percorre desde sua entrada no nosso sistema até a resposta do usuário. Esta tarefa não é tão simples de resolver.
Para começar, vamos examinar como é o envio de tracing spans do ponto de vista da arquitetura no Istio. Como lembramos da primeira parte, o Istio possui um componente separado para coletar telemetria, chamado Mixer. No entanto, na versão atual 1.0.*, o envio é feito diretamente pelos proxies, ou seja, pelo envoy proxy. O envoy proxy suporta o envio de tracing spans pelo protocolo zipkin por padrão. Outros protocolos podem ser suportados, mas apenas através de plugins. Com o Istio, recebemos um envoy proxy pronto e configurado, que suporta apenas o protocolo zipkin. Se quisermos usar, por exemplo, o protocolo Jaeger e enviar tracing spans via UDP, precisaremos criar nossa própria imagem do istio-proxy. O suporte a plugins personalizados para o istio-proxy existe, mas ainda está na versão alpha. Portanto, se quisermos evitar muitas configurações personalizadas, o leque de tecnologias disponíveis para armazenar e receber tracing spans diminui. Das principais sistemas, atualmente podemos usar o próprio Zipkin ou o Jaeger, mas enviar todos os dados via protocolo compatível com zipkin (o que é significativamente menos eficiente). O protocolo zipkin em si pressupõe o envio de todas as informações de tracing para coletores via protocolo HTTP, o que é bastante oneroso.
Como já mencionei, queremos traçar protocolos de nível de aplicativo. Isso significa que os proxies, que estão próximos a cada serviço, devem entender qual interação está ocorrendo no momento. Por padrão, o Istio configura todos os ports como tipo TCP simples, o que significa que nenhum trace será enviado. Para que os traces sejam enviados, é necessário, em primeiro lugar, habilitar esta opção na configuração principal do mesh e, o que é muito importante, nomear todas as portas das entidades de serviço Kubernetes de acordo com o protocolo que está sendo usado pelo serviço. Ou seja, por exemplo, assim:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
targetPort: 80
name: http
selector:
app: nginxVocê também pode usar nomes compostos, como http-magic (o Istio reconhecerá http e identificará essa porta como um endpoint http). O formato é assim: proto-extra.
Para não precisar modificar uma quantidade imensa de configurações para determinar o protocolo, pode-se utilizar uma solução alternativa um tanto suja: patchar o componente Pilot no momento em que ele está justamente . No final, é claro, será necessário mudar essa lógica para o padrão e adotar a convenção de nomenclatura para todas as portas.
Para entender se o protocolo está realmente definido corretamente, é preciso entrar em qualquer um dos contêineres sidecar com o proxy envoy e fazer uma solicitação na porta da interface admin do envoy com a localização /config_dump. Na configuração resultante, você deve observar o campo operation do serviço desejado. Este campo é usado no Istio como um identificador para onde a solicitação está sendo feita. Para personalizar o valor desse parâmetro no Istio (que veremos mais tarde em nosso sistema de rastreamento), é necessário especificar a flag serviceCluster na hora de iniciar o contêiner sidecar. Por exemplo, isso pode ser calculado a partir das variáveis obtidas da API downward do Kubernetes:
--serviceCluster ${POD_NAMESPACE}.$(echo ${POD_NAME} | sed -e 's\-[a-z0-9]*\-[a-z0-9]*$//g')
Um bom exemplo para entender como o rastreamento funciona no envoy é .
O endpoint para enviar spans de rastreamento também deve ser indicado nas flags de inicialização do proxy envoy, por exemplo: --zipkinAddress tracing-collector.tracing:9411
Equívoco número dois: podemos conseguir rastreamentos completos do tráfego de solicitações pelo sistema a baixo custo, diretamente.
Infelizmente, não é assim. A complexidade da implementação depende da forma como você já estabeleceu a interação entre os serviços. Por que isso?
A questão é que, para que o istio-proxy consiga entender a correspondência entre as solicitações de entrada em um serviço e as saídas desse mesmo serviço, não basta apenas interceptar todo o tráfego. É necessário ter algum identificador de conexão. No HTTP, o proxy envoy utiliza cabeçalhos especiais, que permitem ao envoy entender qual solicitação ao serviço gera solicitações específicas a outros serviços. A lista desses cabeçalhos é:
- x-request-id,
- x-b3-traceid,
- x-b3-spanid,
- x-b3-parentspanid,
- x-b3-sampled,
- x-b3-flags,
- x-ot-span-context.
Se você tiver um ponto único, como um cliente base, onde pode adicionar essa lógica, tudo é ótimo, você só precisará esperar pela atualização dessa biblioteca em todos os clientes. Mas se você tiver um sistema muito heterogêneo e não houver unificação na interação entre serviços pela rede, isso provavelmente será um grande problema. Sem a adição de tal lógica, todas as informações de rastreamento serão apenas "unidimensionais". Ou seja, teremos todas as interações entre serviços, mas não estarão reunidas em cadeias únicas através da rede.
Conclusão
O Istio oferece uma ferramenta conveniente para coletar informações de tracing pela rede, mas é necessário entender que sua implementação exigirá a adaptação do seu sistema e a consideração das particularidades da implementação do Istio. No final, precisamos resolver dois pontos principais: a definição do protocolo de aplicação (que deve ser suportado pelo proxy envoy) e a configuração da passagem de informações sobre a correlação de requisições entre serviços (por meio de headers, no caso do protocolo HTTP). Quando essas questões são resolvidas, obtemos uma ferramenta poderosa que permite coletar informações da rede de forma transparente, mesmo em sistemas muito heterogêneos, escritos em várias linguagens e frameworks diferentes.
No próximo artigo sobre Service Mesh, discutiremos um dos maiores problemas do Istio – o alto consumo de memória por cada container de proxy sidecar e como lidar com isso.
Fonte: habr.com
