División de Tráfico en Apache APISIX Ingress Controller

Fei Han

March 27, 2021

Products

La división de tráfico es una función que divide y dirige el tráfico a múltiples servicios backend. Soluciones como API Gateway (por ejemplo, Apache APISIX y Traefik), Service Mesh (por ejemplo, Istio y Linkerd) son capaces de realizar la división de tráfico e implementar funcionalidades como Canary Release y Blue-Green Deployment.

La división de tráfico también es una característica clave en Ingress Controller. Como la capa de entrada en el clúster de Kubernetes, es deseable reducir el riesgo al lanzar una nueva versión de la aplicación configurando algunas reglas de división de tráfico en el controlador de entrada, de modo que solo una cantidad controlable de tráfico se dirija a las instancias recién lanzadas. En este artículo, presentaremos la división de tráfico (también llamada lanzamiento canario) en Ingress Nginx y Kong Ingress Controller, y finalmente explicaremos la división de tráfico en Apache APISIX Ingress Controller.

(PS: Para descripciones más concisas, usamos el término "aplicación canario" para describir el servicio backend que se enruta después de que se cumplan las reglas canario, y el término "aplicación estable" para describir el servicio backend que se enruta debido a que no se cumplen las reglas canario, por ejemplo, las aplicaciones canario y estable son "foo-canary" y "foo" respectivamente en el siguiente diagrama).

1.png

Ingress Nginx

Ingress Nginx soporta el lanzamiento canario, se controla mediante una anotación "nginx.ingress.kubernetes.io/canary", y soporta varias anotaciones para personalizar esta función.

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

El destino se decide por el valor del encabezado (indicado por nginx.ingress.kubernetes.io/canary-by-header), la aplicación Canario se enrutará si el valor es "always", de lo contrario, la aplicación estable se enrutará (el valor del encabezado es "never").

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

Esta anotación extiende nginx.ingress.kubernetes.io/canary-by-header, ahora el valor del encabezado ya no necesita ser "always" o "never".

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

Similar a nginx.ingress.kubernetes.io/canary-by-header, pero el valor es una expresión regular compatible con PCRE.

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

Usa el campo de datos en el encabezado Cookie para decidir el servicio backend.

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

Asigna un valor de peso entre 0 y 100, el tráfico se entregará según este peso, un peso de 0 significa que todo el tráfico se enrutará a la aplicación canario y un peso de 100 enrutará todo el tráfico a la aplicación estable.

El siguiente fragmento de YAML redirige las solicitudes cuya ruta URI comienza con "/get" y el User-Agent coincide con el patrón ".Mozilla." a la aplicación canario "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

El Kong Gateway tiene un plugin de lanzamiento canario y expone este plugin a su controlador de entrada mediante el recurso KongPlugin. Los administradores/usuarios necesitan crear un objeto KongPlugin y llenar la regla de lanzamiento canario, inyectando una anotación "konghq.com/plugins" al Servicio de Kubernetes objetivo. O puedes crear un objeto KongClusterPlugin para que esta regla canario sea efectiva en todo el clúster.

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

El caso anterior marca el servicio "foo-canary" como "canario" y crea una regla de lanzamiento canario para redirigir el 30% del tráfico a este servicio.

Apache APISIX

Apache APISIX divide el tráfico con reglas personalizadas mediante su plugin traffic-split, y Apache APISIX Ingress Controller implementa la función de división de tráfico en ApisixRoute (como soporte de primera clase, sin depender de anotaciones) mediante este plugin y las capacidades flexibles de coincidencia de rutas en ApisixRoute.

Basado en Peso

Al configurar múltiples servicios de Kubernetes, la regla canario basada en peso se puede aplicar de la siguiente manera:

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

El caso anterior dirige ⅔ de las solicitudes cuyo Host es "foo.org" y con prefijo de ruta URI "/get" al servicio "foo-canary" y las demás a foo.

El peso para el servicio canario puede ser pequeño para la verificación a pequeña escala, y aumentar el peso modificando ApisixRoute hasta que todo el tráfico se dirija al servicio canario, finalizando el lanzamiento por completo.

Basado en Reglas

El campo Exprs en ApisixRoute permite a los usuarios configurar reglas personalizadas de coincidencia de rutas, por otro lado, múltiples reglas de ruta pueden agruparse en un solo objeto ApisixRoute, por lo que hay una forma perfecta de implementar la división de tráfico basada en reglas.

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

Las solicitudes cuyo Host es "foo.org", el prefijo de ruta URI es "/get" se separarán en dos partes:

  • El parámetro id cuyo valor es 3, 13, 23 o 33 coincidirá con rule2 y se redirigirá a foo-canary;
  • Las demás coincidirán con rule1 y se enrutarán a foo.

Resumen

La división de tráfico (lanzamiento canario) en Ingress Nginx soporta esquemas basados en peso y en reglas de encabezado, pero depende de anotaciones, cuya semántica es débil; La forma de Kong solo soporta configurar el lanzamiento canario por peso, los escenarios son algo limitados, y la configuración es complicada (necesitas configurar varios recursos); En contraste, la división de tráfico en Apache APISIX Ingress Controller es flexible y fácil de configurar, funciona bien tanto para esquemas de división de tráfico basados en peso como en reglas.

Tags: