Divisão de Tráfego no Apache APISIX Ingress Controller

Fei Han

March 27, 2021

Products

O Traffic Split é uma funcionalidade que divide e direciona o tráfego para múltiplos serviços de backend. Soluções como API Gateway (por exemplo, Apache APISIX e Traefik), Service Mesh (por exemplo, Istio e Linkerd) são capazes de realizar a divisão de tráfego e implementar funcionalidades como Canary Release e Blue-Green Deployment.

O Traffic Split também é uma funcionalidade chave no Ingress Controller. Como a camada de entrada no cluster Kubernetes, é desejável reduzir o risco ao liberar uma nova versão da aplicação configurando algumas regras de divisão de tráfego no controlador de entrada, de modo que apenas uma quantidade controlada de tráfego seja direcionada para as instâncias recém-lançadas. Neste artigo, vamos introduzir o Traffic Split (também chamado de Canary Release) no Ingress Nginx e no Kong Ingress Controller, e, por fim, explicaremos o Traffic Split no Apache APISIX Ingress Controller.

(PS: Para descrições mais concisas, usamos o termo "canary app" para descrever o serviço de backend que é direcionado após as regras de canário serem atendidas, e o termo "stable app" para descrever o serviço de backend que é direcionado quando as regras de canário não são atendidas. Por exemplo, no diagrama a seguir, os aplicativos canário e estável são "foo-canary" e "foo", respectivamente.)

1.png

Ingress Nginx

O Ingress Nginx suporta o canary release, que é controlado por uma anotação "nginx.ingress.kubernetes.io/canary", e ele suporta várias anotações para personalizar essa funcionalidade.

  • nginx.ingress.kubernetes.io/canary-by-header

O destino é decidido com base no valor do cabeçalho (indicado por nginx.ingress.kubernetes.io/canary-by-header). O aplicativo Canary será direcionado se o valor for "always", caso contrário, o aplicativo estável será direcionado (valor do cabeçalho é "never").

  • nginx.ingress.kubernetes.io/canary-by-header-value

Esta anotação estende a funcionalidade de nginx.ingress.kubernetes.io/canary-by-header, agora o valor do cabeçalho não precisa mais ser "always" ou "never".

  • nginx.ingress.kubernetes.io/canary-by-header-pattern

Semelhante a nginx.ingress.kubernetes.io/canary-by-header, mas o valor é uma expressão regular compatível com PCRE.

  • nginx.ingress.kubernetes.io/canary-by-cookie

Usa o campo de dados no cabeçalho Cookie para decidir o serviço de backend.

  • nginx.ingress.kubernetes.io/canary-weight

Atribui um valor de peso entre 0 e 100, o tráfego será entregue de acordo com esse peso. Um peso de 0 significa que todo o tráfego será direcionado para o aplicativo canário, e um peso de 100 direcionará todo o tráfego para o aplicativo estável.

O seguinte trecho YAML direciona as solicitações cujo caminho URI começa com "/get" e o User-Agent corresponde ao padrão ".Mozilla." para o aplicativo canário "foo-canary".

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
      kubernetes.io/ingress.class: nginx
      nginx.ingress.kubernetes.io/canary: "true"
      nginx.ingress.kubernetes.io/canary-by-header: "User-Agent"
      nginx.ingress.kubernetes.io/canary-by-header-pattern:
".*Mozilla.*"
  name: ingress-v1beta1

Kong

O Kong Gateway possui um plugin de canary release e expõe esse plugin ao seu controlador de entrada por meio do recurso KongPlugin. Administradores/Usuários precisam criar um objeto KongPlugin e preencher a regra de canary release, injetando uma anotação "konghq.com/plugins" no Kubernetes Service alvo. Ou você pode criar um objeto KongClusterPlugin para que essa regra de canário seja efetiva em todo o cluster.

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: foo-canary
config:
  percentage: 30
  upstream_host: foo.com
  upstream_fallback: false
  upstream_port: 80
plugin: canary
---
apiVersion: v1
kind: Service
metadata:
  name: foo-canary
  labels:
    app: foo
  annotations:
    konghq.com/plugins: foo-canary
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
      name: http
  selector:
    app: foo
    canary: true

O caso acima marca o serviço "foo-canary" como "canary" e cria uma regra de canary release para direcionar 30% do tráfego para esse serviço.

Apache APISIX

O Apache APISIX divide o tráfego com regras personalizadas por meio de seu plugin traffic-split, e o Apache APISIX Ingress Controller implementa a funcionalidade de divisão de tráfego no ApisixRoute (como suporte de primeira classe, sem depender de anotações) por meio desse plugin e das habilidades flexíveis de correspondência de rotas no ApisixRoute.

Baseado em Peso

Ao configurar múltiplos Kubernetes Services, a regra de canário baseada em peso pode ser aplicada da seguinte forma:

apiVersion: apisix.apache.org/v2alpha1
kind: ApisixRoute
metadata:
  name: foo-route
spec:
  http:
    - name: rule1
      match:
        hosts:
          - foo.org
        paths:
          - /get*
      backends:
        - serviceName: foo-canary
          servicePort: 80
          weight: 10
        - serviceName: foo
          servicePort: 80
          weight: 5

O caso acima direciona ⅔ das solicitações cujo Host é "foo.org" e com prefixo de caminho URI "/get" para o serviço "foo-canary" e o restante para "foo".

O peso para o serviço canário pode ser pequeno para uma verificação em pequena escala, e o peso pode ser aumentado modificando o ApisixRoute até que todo o tráfego seja direcionado para o serviço canário, concluindo totalmente a liberação.

Baseado em Regras

O campo Exprs no ApisixRoute permite que os usuários configurem regras personalizadas de correspondência de rotas. Por outro lado, várias regras de rota podem ser agrupadas em um único objeto ApisixRoute, então há uma maneira perfeita de implementar a divisão de tráfego baseada em regras.

apiVersion: apisix.apache.org/v2alpha1
kind: ApisixRoute
metadata:
  name: foo-route
spec:
  http:
    - name: rule1
      priority: 1
      match:
        hosts:
          - foo.org
        paths:
          - /get*
      backends:
        - serviceName: foo
          servicePort: 80
    - name: rule2
      priority: 2
      match:
        hosts:
          - foo.org
        paths:
          - /get*
        exprs:
          - subject:
              scope: Query
              name: id
            op: In
            set:
              - "3"
              - "13"
              - "23"
              - "33"
      backends:
        - serviceName: foo-canary
          servicePort: 80

As solicitações cujo Host é "foo.org" e o prefixo do caminho URI é "/get" serão separadas em duas partes:

  • O parâmetro id cujo valor é 3, 13, 23 ou 33 irá corresponder à regra2 e será encaminhado para foo-canary;
  • Outros irão corresponder à regra1 e serão direcionados para foo.

Resumo

O Traffic Split (Canary release) no Ingress Nginx suporta esquemas baseados em peso e em regras de cabeçalho, mas depende de anotações, cuja semântica é fraca; A abordagem do Kong suporta apenas a configuração de canary release por peso, os cenários são um tanto limitados, e a configuração é complicada (você precisa configurar vários recursos); Em contraste, o traffic split no Apache APISIX Ingress Controller é flexível e fácil de configurar, funcionando bem tanto para esquemas de divisão de tráfego baseados em peso quanto em regras.

Tags: