Como usar o Istio para balancear a carga de serviços do gRPC internos

Este tutorial mostra como configurar o Balanceamento de carga TCP/UDP interno usando o Istio para serviços do gRPC sendo executados no Google Kubernetes Engine (GKE). Essa configuração permite que outros recursos em sua rede VPC se comuniquem com serviços do gRPC usando, um endereço IP interno privado (RFC 1918), enquanto o Istio cuida das solicitações de encaminhamento e balanceamento de carga entre os pods do Kubernetes que executam os serviços do gRPC.

Para este tutorial, presumimos pressupõe um conhecimento básico de gRPC e GKE ou Kubernetes.

Introdução

O Istio fornece gateways para gerenciar o tráfego que entra e sai da malha de serviço. O gateway do Balanceador de Carga Interno (ILB) do Istio direciona o tráfego de entrada das fontes na rede interna do VPC para os pods do Kubernetes na malha de serviço. Nesta arquitetura, o balanceamento de carga TCP/UDP interno do Google Cloud executa o balanceamento de carga da camada 4 (camada de transporte) nos nós do cluster do GKE. O gateway do ILB do Istio recebe o tráfego e executa o balanceamento de carga da camada 7 (camada de aplicativo), distribuindo tráfego para serviços na malha de serviços do Istio usando regras definidas em serviços virtuais e regras de destino.

O serviço de gRPC de amostra usado neste tutorial retorna um cabeçalho de resposta que contém o nome do pod do Kubernetes que manipulou a solicitação. Ao usar essas informações, é possível ver que o balanceamento de carga pelo gateway de ILB do Istio distribui as solicitações feitas por um cliente através de uma única conexão com vários pods do Kubernetes no cluster do GKE.

Objetivos

  • Criar um cluster do GKE com o Istio e o gateway do ILB do Istio.
  • Implantar um serviço do gRPC de amostra.
  • Verificar a conectividade interna.

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

  1. Faça login na Conta do Google ou, se não tiver uma, inscreva-se em uma nova conta.
  2. No Console do Cloud, acesse a página do seletor de projetos.

    Acessar a página do seletor de projetos

  3. Selecione ou crie um projeto do Cloud.

  4. Verifique se a cobrança está ativada para o seu projeto do Google Cloud. Saiba como confirmar se a cobrança está ativada para o seu projeto.

Como inicializar o ambiente

  1. No Console do Cloud, na lista suspensa Selecione um projeto, selecione o projeto que você quer usar.

  2. Abra o Cloud Shell:

    Acesse o Cloud Shell

    Use o Cloud Shell para executar todos os comandos neste tutorial.

  3. Ative a API Cloud Build, a API Google Kubernetes Engine, a API Container Analysis e as APIs do Cloud:

    gcloud services enable \
        cloudapis.googleapis.com \
        cloudbuild.googleapis.com \
        container.googleapis.com \
        containeranalysis.googleapis.com
    
  4. Defina o padrão gcloud para a zona do Compute Engine que você quer usar neste tutorial:

    gcloud config set compute/zone us-central1-b
    

    Este tutorial usa a zona us-central1-b. É possível mudar a zona para atender às suas necessidades.

  5. Clone o repositório do Git que contém o serviço do gRPC de amostra e alterne para o diretório de trabalho:

    git clone https://github.com/GoogleCloudPlatform/istio-samples.git
    cd istio-samples/sample-apps/grpc-greeter-go
    

Criar um cluster do GKE com o Istio

  1. No Cloud Shell, crie um cluster do GKE:

    gcloud beta container clusters create grpc-istio-ilb-tutorial \
        --machine-type n1-standard-2 \
        --enable-ip-alias
    
  2. Conceda a si mesmo os direitos de administrador do cluster:

    kubectl create clusterrolebinding cluster-admin-binding \
        --clusterrole cluster-admin \
        --user $(gcloud config get-value account)
    

    Você precisa ter as permissões definidas no papel de cluster do Kubernetes do cluster-admin para instalar o Istio.

  3. Crie um namespace do Kubernetes chamado istio-system:

    kubectl create namespace istio-system
    
  4. Faça o download e extraia o Istio:

    ISTIO_VERSION=1.2.7
    curl -L https://github.com/istio/istio/releases/download/$ISTIO_VERSION/istio-$ISTIO_VERSION-linux.tar.gz | tar -zxf -
    
  5. Use a renderização de modelo local do Helm para instalar as definições de recurso personalizado (CRDs) do Istio:

    helm template \
        istio-$ISTIO_VERSION/install/kubernetes/helm/istio-init \
        --namespace istio-system | kubectl apply -f -
    
  6. Use o Helm para instalar o Istio com o gateway do ILB (istio-ilbgateway):

    ISTIO_PACKAGE=$ISTIO_VERSION-gke.0
    
    helm template \
        istio-$ISTIO_VERSION/install/kubernetes/helm/istio \
        --set gateways.istio-ingressgateway.enabled=false \
        --set gateways.istio-ilbgateway.enabled=true \
        --set gateways.istio-ilbgateway.ports[0].name=grpc-pilot-mtls \
        --set gateways.istio-ilbgateway.ports[0].port=15011 \
        --set gateways.istio-ilbgateway.ports[1].name=grpc \
        --set gateways.istio-ilbgateway.ports[1].port=443 \
        --set gateways.istio-ilbgateway.ports[2].name=tcp-citadel-grpc-tls \
        --set gateways.istio-ilbgateway.ports[2].port=8060 \
        --set gateways.istio-ilbgateway.ports[2].targetPort=8060 \
        --set gateways.istio-ilbgateway.ports[3].name=tcp-dns \
        --set gateways.istio-ilbgateway.ports[3].port=5353 \
        --set global.hub=gcr.io/gke-release/istio \
        --set global.tag=$ISTIO_PACKAGE \
        --namespace istio-system | kubectl apply -f -
    
  7. Verifique o status da criação de um endereço IP externo para o Serviço Kubernetes istio-ilbgateway:

    kubectl get services istio-ilbgateway -n istio-system --watch
    

    Aguarde até que o valor EXTERNAL-IP mude de <pending> para um endereço IP. Pressione Control+C se não quiser esperar.

Criar um certificado TLS para o gateway do ILB do Istio

  1. No Cloud Shell, crie um certificado TLS e uma chave privada para permitir o que o gateway do ILB do Istio cancele o TLS:

    openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
        -keyout privkey.pem -out cert.pem -subj "/CN=grpc.example.com"
    
  2. Crie um secret do Kubernetes para armazenar o certificado TLS e a chave privada:

    kubectl -n istio-system create secret tls istio-ilbgateway-certs \
        --key privkey.pem --cert cert.pem \
        --dry-run -o yaml | kubectl apply -f -
    

Instalar o aplicativo de amostra

A próxima etapa é criar uma imagem de contêiner para o serviço do gRPC de amostra e implantá-la no cluster do GKE. O serviço do gRPC de amostra consiste em um componente cliente, conhecido como gRPC cliente, e um componente de servidor, chamado de gRPC servidor.

  1. No Cloud Shell, ative a injeção automática de arquivo secundário do Istio no namespace default:

    kubectl label namespace default istio-injection=enabled
    
  2. Use o Cloud Build para criar uma imagem de contêiner para o gRPC servidor:

    gcloud builds submit server -t gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-server
    
  3. Crie os objetos de implantação e serviço do Kubernetes para o gRPC servidor:

    envsubst < manifests/greeter-k8s.template.yaml | kubectl apply -f -
    
  4. Verifique se o serviço ClusterIP do Kubernetes foi criado e se os pods estão em execução:

    kubectl get services,pods
    

    A saída é semelhante a:

    NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    service/greeter      ClusterIP   10.0.18.67   <none>        8080/TCP   11s
    service/kubernetes   ClusterIP   10.0.16.1    <none>        443/TCP    1h
    NAME READY STATUS RESTARTS AGE pod/greeter-844cffd75-7hpcb 2/2 Running 0 56s pod/greeter-844cffd75-ffccl 2/2 Running 0 56s pod/greeter-844cffd75-zww6h 2/2 Running 0 56s

    Os pods mostram 2/2 na coluna READY. Isso significa que, para cada pod, o contêiner do gRPC servidor e o contêiner de arquivo secundário do Envoy estão em execução.

  5. Crie os objetos de gateway, serviço virtual e regra de designação do Istio para o gRPC servidor:

    kubectl apply -f manifests/greeter-istio-ilbgateway.yaml \
        -f manifests/greeter-istio-virtualservice.yaml \
        -f manifests/greeter-istio-destinationrule.yaml
    
  6. Verifique se os três objetos foram criados com sucesso:

    kubectl get gateway,virtualservice,destinationrule
    

    A saída é semelhante a:

    NAME                                  AGE
    gateway.networking.istio.io/greeter   1m
    NAME GATEWAYS HOSTS AGE virtualservice.networking.istio.io/greeter [greeter] [*] 1m
    NAME HOST AGE destinationrule.networking.istio.io/greeter greeter 1m

Verificar a conectividade interna

O balanceamento de carga TCP/UDP interno regional, portanto, é possível testar a conectividade de uma VM na mesma zona ou região.

  1. No Cloud Shell, use o Cloud Build para criar uma imagem de contêiner para o gRPC cliente:

    gcloud builds submit client \
        -t gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-client
    
  2. Crie uma instância do Compute Engine na mesma zona ou região que o cluster do GKE:

    gcloud compute instances create grpc-istio-ilb-tutorial-client-vm \
        --scopes https://www.googleapis.com/auth/devstorage.read_only \
        --image-project cos-cloud \
        --image-family cos-stable
    

    O escopo devstorage.read_only é necessário para fazer o download de imagens do Container Registry.

  3. Armazene o endereço IP do gateway do ILB do Istio em um arquivo chamado ilb-ip.txt:

    kubectl -n istio-system get services istio-ilbgateway \
        -o jsonpath='{.status.loadBalancer.ingress[0].ip}' > ilb-ip.txt
    
  4. Copie o certificado TLS autoassinado e o arquivo que contém o endereço IP do gateway do ILB do Istio para a VM:

    gcloud compute scp cert.pem ilb-ip.txt grpc-istio-ilb-tutorial-client-vm:~
    
    
  5. Use o SSH para se conectar à VM:

    gcloud compute ssh grpc-istio-ilb-tutorial-client-vm
    
  6. Na VM, consulte o servidor de metadados do Compute Engine em busca do ID do projeto e armazene-o na variável de ambiente GOOGLE_CLOUD_PROJECT.

    GOOGLE_CLOUD_PROJECT=$(curl -sH "Metadata-Flavor: Google" \
        http://metadata.google.internal/computeMetadata/v1/project/project-id)
    

    No Cloud Shell, a variável de ambiente GOOGLE_CLOUD_PROJECT é definida por padrão, mas isso não acontece nas VMs.

  7. Busque as credenciais do Container Registry para uso com o comando docker:

    docker-credential-gcr configure-docker
    
  8. Execute a imagem do contêiner do gRPC cliente:

    docker run --rm -v $(pwd)/cert.pem:/data/cert.pem \
        --add-host grpc.example.com:$(cat ilb-ip.txt) \
        gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-client \
        --address=grpc.example.com:443
    

    A saída é semelhante a:

    2019/03/27 15:12:53 Hello world from greeter-844cffd75-ffccl
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-zww6h
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-7hpcb
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-ffccl
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-zww6h
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-7hpcb
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-ffccl
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-zww6h
    2019/03/27 15:12:53 Hello world from greeter-844cffd75-7hpcb

    Essa saída mostra que as solicitações unárias do gRPC são processadas pelos pods do servidor gRPC (chamado greeter-*) de acordo com a configuração loadBalancer na regra de destino do Istio. Neste caso, ROUND_ROBIN.

  9. Saia da sessão SSH:

    exit
    

Examinar o código-fonte

Para entender melhor a configuração de balanceamento de carga, é possível examinar o código-fonte do aplicativo de amostra.

Por exemplo, para entender as mensagens impressas pelo gRPC cliente, analise o código-fonte Go do servidor e do cliente. Quando o servidor gRPC processa uma solicitação, ele pesquisa o nome do host e o adiciona como um cabeçalho de resposta chamado hostname. Como o servidor está sendo executado em um pod do Kubernetes, o nome do host é o nome do pod.

hostname, err := os.Hostname()
if err != nil {
	log.Printf("Unable to get hostname %v", err)
}
if hostname != "" {
	grpc.SendHeader(ctx, metadata.Pairs("hostname", hostname))
}

Quando o cliente gRPC recebe uma resposta do servidor, ele recebe o cabeçalho hostname e o imprime no console.

if len(header["hostname"]) > 0 {
	hostname = header["hostname"][0]
}
log.Printf("%s from %s", r.Message, hostname)

Para entender os nomes do pod do Kubernetes impressos no console pelo gRPC cliente, veja a configuração do Istio para o gRPC servidor. Observe que o objeto DestinationRule especifica ROUND_ROBIN como o algoritmo loadBalancer. Esse algoritmo é o motivo pelo qual as solicitações recebidas são rotacionadas entre os pods na Implantação do Kubernetes.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: greeter
spec:
  host: greeter
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    tls:
      mode: ISTIO_MUTUAL

Resolver problemas

Se você tiver problemas ao seguir este tutorial, recomendamos que consulte estes documentos:

Como fazer a limpeza

Para evitar cobranças dos recursos usados neste tutorial na conta do Google Cloud, siga estas etapas:

  1. No Cloud Shell, exclua o cluster do GKE:

    gcloud container clusters delete grpc-istio-ilb-tutorial --quiet --async
    
  2. Exclua as imagens no Container Registry:

    gcloud container images delete gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-client \
        --force-delete-tags --quiet
    gcloud container images delete gcr.io/$GOOGLE_CLOUD_PROJECT/grpc-greeter-go-server \
        --force-delete-tags --quiet
    
  3. Exclua a instância do Compute Engine:

    gcloud compute instances delete grpc-istio-ilb-tutorial-client-vm --quiet
    

A seguir