Mateus Müller

O carinha do Linux

19 abr. 2024

Istio: Como configurar multicluster multi-primary em redes diferentes

Acabei ficando alguns dias sem postar nada aqui no blog porque essa configuração de multicluster já estava me tirando o sono!

Recentemente comecei a estudar mais sobre o Istio por N motivos, e talvez a principal feature que me interesse hoje é o uso de multicluster. Com o uso do multicluster, um leque de possibilidades é aberto para aprimoramento da infraestrutura.

Basicamente me baseei neste post da documentação oficial. Não existe um walkthrough completo simples e objetivo para quem quer testar a feature, ou algum tipo de automação rápida. Eu realmente perdi dias tentando fazer isso funcionar com o kind e falhei miseravelmente. Acabei apelando para o Minikube com VirtualBox e consegui fazer funcionar.

Aproveitando todo o processo, criei um Makefile com comandos prontos para quem quiser testar para entender mais sobre essa feature.

Requisitos

Primeiro de tudo, eu fiz todo o processo na minha máquina Linux. Se você usa outro OS, talvez tenha que adaptar uma coisa ou outra.

TL;DR

Todos os arquivos estão disponíveis no meu repositório, então você pode só clonar e mandar bala:

$ git clone https://github.com/mateusmuller/labs
$ cd labs/service-mesh/istio/multicluster-multinetwork
$ make

Se os Deuses da demo estiverem ao seu lado, você vai ter 2 clusters Kubernetes em VMs do VirtualBox com multicluster configurado e uma aplicação demo balanceando tráfego.

E sim, tudo está automatizado e resumido dentro do Makefile. Então se você quiser entender o que cada subcomando do Makefile faz, é só abrir esse arquivo que vai dar bom.

Criação do cluster

Bom, vamos começar do começo para que a gente possa ir falando sobre os passos também. Clone o repositório e crie os dois clusters.

$ git clone https://github.com/mateusmuller/labs
$ cd labs/service-mesh/istio/multicluster-multinetwork
$ make create

Este comando vai usar o minikube por trás dos panos para criar 2 VMs no VirtualBox, cada uma simulando um cluster Kubernetes diferente. Você pode ver mais informações sobre os valores default e o driver do VirtualBox em si aqui.

O hardware da VM é 2vCPUs e 3.8GB de RAM. Garanta que seu equipamento suporta isso.

O seu kubeconfig também deve ser atualizado, bem como o context atual. Rodando o comando abaixo já dá para interagir com o cluster:

└─[$] <git:(main)> kubectl get pods -A
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE
kube-system   coredns-5dd5756b68-f6gqh            1/1     Running   0          4s
kube-system   etcd-cluster-2                      1/1     Running   0          17s
kube-system   kube-apiserver-cluster-2            1/1     Running   0          17s
kube-system   kube-controller-manager-cluster-2   1/1     Running   0          17s
kube-system   kube-proxy-2lnb7                    1/1     Running   0          5s
kube-system   kube-scheduler-cluster-2            1/1     Running   0          18s
kube-system   storage-provisioner                 1/1     Running   0          15s

Bueno, temos dois clusters. Ambos estão rodando na mesma rede do VirtualBox 192.168.59.1/24.

Vamos imaginar que estão em redes diferentes, funcionaria também, desde que um consiga chegar até o outro via algum Gateway/LoadBalancer.

A sua máquina host tem rota para essa rede diretamente.

└─[$] <git:(main)> ip r | grep 192.168.59
192.168.59.0/24 dev vboxnet3 proto kernel scope link src 192.168.59.1

Isso significa que usando o MetalLB, podemos chegar diretamente nos Services do tipo LoadBalancer.

Deploy do MetalLB

Como estes são clusters on-premises, não temos LoadBalancers providos pelos Cloud Controllers. Por isso, vamos fazer o deploy do MetalLB que resolve este problema.

Basicamente ele vai fornecer IPs de um range respondendo requisições ARP.

$ make metallb

Este comando vai instalar o MetalLB e cria duas pools de IPs, uma em cada cluster. Veja os arquivos chamados address-pool.yaml dentro da pasta de manifests.

Note que definimos ranges diferentes para cada cluster para evitar conflito de IP.

Agora, quando o Gateway do Istio for deployado, ele vai receber um IP dentro desse range.

Certificados

O requisito mais básico de qualquer multicluster é: Ter uma CA em comum para assinar certificados.

Dessa forma, mTLS pode ser usado entre pods de diferentes cluters, sem quebrar a confiança, pois todos usam a mesma CA.

Isso é mencionado aqui na documentação oficial.

Vamos utilizar alguns recursos fornecidos pelo próprio repositório do Istio para criar uma CA e secrets em cada cluster. Lembrando que para um caso produtivo, é recomendado o uso de algum cofre como Hashicorp Vault, AWS Private CA, etc.

$ make certs

Isso vai clonar o repositório oficial (se não já clonado), e usar ferramentas do próprio repo para criar a CA e assinar os certificados intermediários. Após isso, um secret chamados cacerts será criado em cada cluster.

Você pode confirmar se o CA é o mesmo com este comando:

$ diff \
   <(kubectl --context="cluster-1" -n istio-system get secret cacerts -ojsonpath='{.data.root-cert\.pem}') \
   <(kubectl --context="cluster-2" -n istio-system get secret cacerts -ojsonpath='{.data.root-cert\.pem}')

Esse processo de testes é mencionado na documentação de troubleshooting aqui.

Instalação do Istio

Agora podemos seguir com a instalação. Vamos usar o Istio Operator, mas o Helm é mais recomendado para ambientes produtivos.

Cada cluster tem uma configuração dentro da pasta manifests chamado istiod.yaml. Veja que criamos clusters diferentes, redes diferentes, mas o mesmo meshID. Além disso, já deixei habilitado o access log dos proxies para fins de troubleshooting.

$ make install-istio

Instalação do Gateway

O Gateway eastwest é instalado de uma forma diferente. Usamos um script (dentro da pasta scripts) para gerar o YAML, e depois aplicar com istioctl. Precisamos também informar o cluster, network e mesh ID.

$ make install-gateway

Além disso, o arquivo Kind do tipo Gateway está sendo deployado, que efetivamente cria um ponto de entrada no LoadBalancer para enviar para os Services internos.

    - port:
        number: 15443
        name: tls
        protocol: TLS
      tls:
        mode: AUTO_PASSTHROUGH
      hosts:
        - "*.local"

O arquivo acima quer dizer que a porta 15443 usará o protocolo TLS, no modo AUTO_PASSTHROUGH, que significa que não é necessário a criação do Kind VirtualService. Será feito o forward direto para o Service do Kubernetes. Além disso, isso será aplicado para todas as requisições para URLs que terminem com *.local.

O DNS do Kubernetes é sempre <service>.<namespace>.svc.cluster.local. Ou seja, toda requisição interna será aceita e enviada para serviços internos.

Configuração do Multicluster

Até o momento ambos os cluters estão isolados. Precisamos criar secrets em cada cluster, que permite acesso ao cluster ao lado.

Ou seja, gerar credenciais de acesso no cluster 1, aplicar no cluster 2, e vice-versa.

$ make endpoint-discovery

No momento que este secret é criado, a conexão é fechada.

Deploy da aplicação demo

Bueno, vamos testar se está tudo funcional então.

$ make sample

Após os pods na namespace sample estarem ready 2/2, vamos acessar o pod sleep para enviar tráfego para o service helloworld.

$ kubectl exec -it -n sample $(kubectl get pod -n sample -l app=sleep -o custom-columns=:metadata.name --no-headers) sh
$ while true; do curl helloworld.sample:5000/hello; done

Hello version: v2, instance: helloworld-v2-7f46498c69-nhgcz
Hello version: v2, instance: helloworld-v2-7f46498c69-nhgcz
Hello version: v2, instance: helloworld-v2-7f46498c69-nhgcz
Hello version: v2, instance: helloworld-v2-7f46498c69-nhgcz
Hello version: v1, instance: helloworld-v1-867747c89-jzz5d
Hello version: v2, instance: helloworld-v2-7f46498c69-nhgcz
Hello version: v1, instance: helloworld-v1-867747c89-jzz5d
Hello version: v2, instance: helloworld-v2-7f46498c69-nhgcz
Hello version: v1, instance: helloworld-v1-867747c89-jzz5d

E com isso concluímos a nossa configuração!

Destruir o ambiente

Basta rodar:

$ make down

Tudo de uma vez

Você pode usar o:

$ make

ou

$ make up

E todos os comandos citados nesse artigo serão executados sequencialmente.

Espero que este artigo ajude e poupe o tempo de quem for testar a feature rsrs!

Grande abs.

Buy me a coffeeBuy me a coffee
Comentários Disqus