Uso do Istio+Kiali para implementar e visualizar o Canary deployment

Artigos desta série
- (este artigo)
- Canary Deployment usando Jenkins-X Istio Flagger
Canary Deployment
Esperamos que você tenha lido , onde explicamos brevemente o que são Canary deployments e mostramos como implementá-los usando recursos padrão do Kubernetes.
Istio
E presumimos que ao ler este artigo, você já sabe o que é Istio. Se não, você pode ler sobre ele .
Aplicativo para testes

Cada pod contém dois contêineres: nosso aplicativo e o istio-proxy.
Vamos usar um aplicativo de teste simples com pods frontend-nginx e backend em Python. O pod com nginx apenas redirecionará cada solicitação para o pod com backend e funcionará como um proxy. Você pode ver mais detalhes nos seguintes arquivos YAML:
Executando o aplicativo de teste por conta própria
Se você quiser seguir meu exemplo e usar este aplicativo de teste, consulte .
Deployment inicial
Ao iniciar o primeiro Deployment, vemos que os pods do nosso aplicativo têm apenas 2 contêineres, ou seja, o Istio sidecar ainda está sendo implementado:

E também vemos o Istio Gateway Loadbalancer no namespace istio-system:

Gerando tráfego
Usaremos o seguinte IP para gerar tráfego que será recebido pelos pods frontend e redirecionado para os pods backend:
while true; do curl -s --resolve 'frontend.istio-test:80:35.242.202.152' frontend.istio-test; sleep 0.1; done
Nós também adicionaremos frontend.istio-test ao nosso arquivo hosts.
Visualizando o Mesh através do Kiali
Instalamos o aplicativo de teste e o Istio junto com Tracing, Grafana, Prometheus e Kiali (veja mais em ). Portanto, podemos acessar o Kiali através de:
istioctl dashboard kiali # admin:admin

O Kiali visualiza o tráfego atual através do Mesh
Como vemos, 100% do tráfego vai para o serviço frontend, depois para o pod frontend com label v1, já que estamos usando um simples proxy nginx que redireciona as solicitações para o serviço backend, que por sua vez as redireciona para os pods backend com label v1.
O Kiali funciona perfeitamente com o Istio e fornece uma solução pronta para visualização do Mesh. É simplesmente excelente.
Canary Deployment
Nosso backend já tem dois deployments k8s, um para v1 e outro para v2. Agora só precisamos dizer ao Istio para redirecionar uma certa porcentagem de solicitações para v2.
Passo 1: 10%
E tudo o que precisamos fazer é ajustar o peso do VirtualService em :
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
- match:
- {}
route:
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 90
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 10 
Vemos que 10% das requisições estão sendo redirecionadas para o v2.
Passo 2: 50%
E agora é só aumentar isso para 50%:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
...
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 50
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 50 
Passo 3: 100%
Agora o deployment Canary pode ser considerado completo e todo o tráfego é redirecionado para o v2:

Testando o Canary manualmente
Suponha que agora estamos enviando para o backend v2 10% de todas as requisições. E se quisermos testar manualmente o v2 para garantir que tudo funcione como esperado?
Podemos adicionar uma regra de correspondência especial, baseada em cabeçalhos HTTP:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
- match:
- headers:
canary:
exact: "canary-tester"
route:
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 100
- match:
- {}
route:
- destination:
host: backend.default.svc.cluster.local
subset: v1
port:
number: 80
weight: 90
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 10Agora, usando curl, podemos solicitar forçadamente o v2 enviando o cabeçalho:
![]()
As requisições sem cabeçalho ainda serão gerenciadas na proporção de 1/10:

Canary para duas versões dependentes
Agora vamos considerar o caso em que temos a versão v2 tanto para o frontend quanto para o backend. Para ambos, especificamos que 10% do tráfego deve ir para o v2:

Vemos que o frontend v1 e v2 estão ambos redirecionando tráfego na proporção de 1/10 para o backend v1 e v2.
E se precisássemos redirecionar tráfego do frontend-v2 apenas para o backend-v2, porque ele não é compatível com o v1? Para isso, vamos estabelecer a proporção de 1/10 para o frontend, que controla qual tráfego chega ao backend-v2 usando a correspondência por sourceLabels :
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: backend
namespace: default
spec:
gateways: []
hosts:
- "backend.default.svc.cluster.local"
http:
...
- match:
- sourceLabels:
app: frontend
version: v2
route:
- destination:
host: backend.default.svc.cluster.local
subset: v2
port:
number: 80
weight: 100Assim, obtemos o que precisamos:

Diferenças em relação à abordagem manual de Canary
Em primeira parte Realizamos o Canary deployment manualmente, utilizando também duas implantações k8s. Lá, gerenciamos a proporção de solicitações, alterando o número de réplicas. Essa abordagem funciona, mas possui desvantagens significativas.
O Istio permite definir a proporção de solicitações independentemente do número de réplicas. Isso significa, por exemplo, que podemos usar HPAs (Horizontal Pod Autoscalers — escalonamento horizontal de pods) e não é necessário configurá-lo de acordo com o estado atual do Canary deployment.
Resultado
O Istio funciona muito bem e, ao usá-lo junto com o Kiali, obtemos uma combinação poderosa. O próximo em minha lista de interesses é a combinação do Spinnaker com o Istio para automação e análise de Canary.
Fonte: habr.com
