DEV Community

Cover image for O básico de mirror do Istio
Wander
Wander

Posted on

O básico de mirror do Istio

O Istio é a principal ferramenta de service mesh para o Kubernetes, ele disponibiliza diversas features para você gerenciar a sua malha de serviços, dentre essas features temos a parte de gerenciamento de tráfego onde uma das possibilidade é criar um 'mirror'. Mas o que é um mirror? um mirror permite você 'espelhar' o tráfego de requisições de um serviço para outro. E porque isso é útil? podemos encaixar essa funcionalidade em algumas situações, dentre elas vou destacar uma:

Vamos supor que você tem uma aplicação que usa o banco de dados mysql e você precisa migra-la para postgresql, porém, antes de tornar a versão migrada produtiva você quer testar o comportamento dela para ver se os dados serão salvos corretamente e se a aplicação não apresentará erros. Para isso, você pode espelhar as requisições que chegam na aplicação cuja versão utiliza o mysql para a versão que utiliza o postgresql. O tráfego continuará sendo enviado para a versão com mysql e a versão com postgresql receberá uma cópia desse tráfego, o retorno da aplicação com postgresql não é enviado ao cliente, garantindo assim que o cliente receba apenas o retorno da aplicação com mysql que já funciona, evitanto assim receber possíveis erros da versão nova com postgresql.


Interessante, não? 🔥

Vamos ver como funciona na prática? Para isso vamos precisar das seguintes ferramentas instaladas na nossa máquina:

⚠️ Os comandos citados abaixo para criar os componentes começam com a instrução istioctl kube-inject -f, esta instrução injeta no pod a ser criado o container de proxy do istio, para que o istio possa controlar este pod. Caso você não queira usar esta instrução confira aqui como injetar o proxy do istio de outras maneiras.

Mãos a obra 🤝🎓

1 - Para começar, vamos subir nosso cluster minikube, primeiramente inicie o docker abrindo o docker desktop (para Windows), em seguida abra um terminal git bash e execute o seguinte comando para subir o minikube:

minikube start
Enter fullscreen mode Exit fullscreen mode

2 - Instale o istio

istioctl install --set profile=demo -y
Enter fullscreen mode Exit fullscreen mode

3 - Copie o código abaixo e execute no git bash para criar o deployment principal

cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: istioapp-v1
  labels:
    app: istioapp
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: istioapp
      version: v1
  template:
    metadata:
      labels:
        app: istioapp
        version: v1
    spec:
      containers:
      - name: istioapp
        image: wandpsilva/istioapp:v1.0
        ports:
        - containerPort: 8080
EOF
Enter fullscreen mode Exit fullscreen mode

4 - Agora faça o mesmo para o código abaixo para a versão 2 que receberá o tráfego espelhado

cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: istioapp-v2
  labels:
    app: istioapp
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: istioapp
      version: v2
  template:
    metadata:
      labels:
        app: istioapp
        version: v2
    spec:
      containers:
      - name: istioapp
        image: wandpsilva/istioapp:v1.0
        ports:
        - containerPort: 8080
EOF
Enter fullscreen mode Exit fullscreen mode

5 - Vamos criar o service do kubernetes

kubectl create -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: istioapp-service
spec:
  selector:
    app: istioapp
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
  type: NodePort
EOF
Enter fullscreen mode Exit fullscreen mode

6 - Criaremos agora nosso virtualservice e destinationrule, estes são componentes do istio utilizados para gerenciamento de tráfego e neste momento possuem uma configuração básica, apenas enviar a requisição recebida para o pod v1

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: istioapp-virtualservice
spec:
  hosts:
    - istioapp-service.default.svc.cluster.local
  http:
    - route:
        - destination:
            host: istioapp-service.default.svc.cluster.local
            subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: istioapp-destinationrule
spec:
  host: istioapp-service.default.svc.cluster.local
  subsets:
  - name: v1
    labels:
      app: istioapp
      version: v1
EOF
Enter fullscreen mode Exit fullscreen mode

7 - Com todos os componentes criados, vamos criar um deployment do httpbin para chamarmos a nossa aplicação e testa-la

cat <<EOF | istioctl kube-inject -f - | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      containers:
      - name: sleep
        image: curlimages/curl
        command: ["/bin/sleep","3650d"]
        imagePullPolicy: IfNotPresent
EOF
Enter fullscreen mode Exit fullscreen mode

8 - Com o httpbin criado podemos chamar o endpoint da aplicação que subimos no minikube e verificarmos o response dela pelo log do pod. Vamos então chamar a aplicação com o seguinte comando

export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec "${SLEEP_POD}" -c sleep -- curl -sS http://istioapp-service:8080/v1/istioapp/hello-word/ping
Enter fullscreen mode Exit fullscreen mode

Verifique as logs dos dois pods

pod v1

export V1_POD=$(kubectl get pod -l app=istioapp,version=v1 -o jsonpath={.items..metadata.name})
kubectl logs "$V1_POD" -c istioapp
Enter fullscreen mode Exit fullscreen mode

pod v2

export V2_POD=$(kubectl get pod -l app=istioapp,version=v2 -o jsonpath={.items..metadata.name})
kubectl logs "$V2_POD" -c istioapp
Enter fullscreen mode Exit fullscreen mode

você deverá ver a mensagem 'PONG' na log do pod v1 e nada na log do pod v2.

9 - Vamos fazer agora o mirror funcionar, fazendo com que a chamada feita no passo 8 chegue tanto para o pod v1 quanto para o pod v2, para isso vamos configurar novamente nosso virtualservice e destinationrule, aplique as configurações abaixo

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: istioapp-virtualservice
spec:
  hosts:
    - istioapp-service.default.svc.cluster.local
  http:
    - route:
        - destination:
            host: istioapp-service.default.svc.cluster.local
            subset: v1
          weight: 100
      mirror:
        host: istioapp-service.default.svc.cluster.local
        subset: v2
      mirrorPercentage:
        value: 100
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: istioapp-destinationrule
spec:
  host: istioapp-service.default.svc.cluster.local
  subsets:
  - name: v1
    labels:
      app: istioapp
      version: v1
  - name: v2
    labels:
      app: istioapp
      version: v2
EOF
Enter fullscreen mode Exit fullscreen mode

10 - Chame novamente a aplicação

export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec "${SLEEP_POD}" -c sleep -- curl -sS http://istioapp-service:8080/v1/istioapp/hello-word/ping
Enter fullscreen mode Exit fullscreen mode

Verifique a log dos pods novamente

pod v1

export V1_POD=$(kubectl get pod -l app=istioapp,version=v1 -o jsonpath={.items..metadata.name})
kubectl logs "$V1_POD" -c istioapp
Enter fullscreen mode Exit fullscreen mode

pod v2

export V2_POD=$(kubectl get pod -l app=istioapp,version=v2 -o jsonpath={.items..metadata.name})
kubectl logs "$V2_POD" -c istioapp
Enter fullscreen mode Exit fullscreen mode

O que aconteceu? 🤔

Como você pode notar, ambos os pods exibiram nas logs a mensagem PONG, o que significa que ambos receberam a requisição feita, porém, o pod v2 recebe apenas uma cópia do tráfego, o seu retorno seja sucesso ou falha não retorna ao cliente, o que nos dá segurança de testarmos qualquer alteração e em qualquer ambiente.

Como aconteceu? 😃

Toda a lógica do mirror fica entre os componentes virtualservice e destinationrule, analisando os arquivos acima note que o virtualservice através do atributo mirror consegue replicar o tráfego para um outro subset (v2), este subset é configurado no destinationrule e lá dizemos através de labels para qual pod a requisição deverá ser enviada. Também é possível dizer o percentual de tráfego que deverá ser espelhado com o atributo mirrorPercentage, se este for omitido, 100% do tráfego será espelhado.


Este artigo foi baseado na documentação oficial do istio. Recomendo navegar pela documentação e explorar mais e mais do istio 🚀

Espero que tenham gostado, até a próxima. 😉

Top comments (1)

Collapse
 
filipefbf profile image
Filipe Ferreira

Muito bom a demo bem clara e objetiva.