Cómo hacer proxy de servicios externos en Apache APISIX Ingress Controller

Yeqi Peng

January 13, 2023

Products

En este tutorial, presentaremos cómo configurar servicios externos en recursos de ApisixUpstream.

Esto es útil cuando tu servicio depende de un servicio de terceros o de un servicio de otro clúster de K8s. También proporciona una forma de gestionar tu ApisixRoute con servicios ExternalName compartidos, sin necesidad de modificar un gran número de ApisixRoutes cuando se actualiza el nombre del servicio referenciado.

Requisitos previos

  • Un clúster de Kubernetes disponible
  • Una instalación disponible de APISIX y APISIX Ingress Controller

Asumimos que tu APISIX está instalado en el espacio de nombres apisix.

Introducción

APISIX Ingress admite la configuración de servicios externos como backends, tanto para servicios ExternalName de K8s como para dominios directos.

En este caso, no configuramos el campo backends en el recurso ApisixRoute. En su lugar, usaremos el campo upstreams para referenciar un recurso ApisixUpstream con el campo externalNodes configurado.

Por ejemplo:

# httpbin-route.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  name: httpbin-route
spec:
  http:
  - name: rule1
    match:
      hosts:
      - local.httpbin.org
      paths:
      - /*
    # backends:  # No usaremos el campo `backends`
    #    - serviceName: httpbin
    #      servicePort: 80
    upstreams:
    - name: httpbin-upstream

Esta configuración le indica al controlador de ingress que no resuelva los hosts de upstream a través de los servicios de K8s, sino que use la configuración definida en el ApisixUpstream referenciado.

El ApisixUpstream referenciado DEBE tener el campo externalNodes configurado. Por ejemplo:

# httpbin-upstream.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
  name: httpbin-upstream
spec:
  externalNodes:
  - type: Domain
    name: httpbin.org

En este ejemplo de yaml, configuramos httpbin.org como el backend. El tipo Domain indica que se trata de un servicio de terceros, y aquí se admite cualquier nombre de dominio.

Si deseas usar un servicio de nombre externo en el clúster de K8s, el tipo debe ser Service y el nombre debe ser el nombre del servicio. Al configurar ApisixUpstream con el tipo Service, el controlador de ingress rastreará automáticamente el contenido del servicio ExternalName y sus cambios.

Upstream de Dominio Externo

apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  name: httpbin-route
spec:
  http:
  - name: rule1
    match:
      hosts:
      - local.httpbin.org
      paths:
      - /*
    upstreams:
    - name: httpbin-upstream
---
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
  name: httpbin-upstream
spec:
  externalNodes:
  - type: Domain
    name: httpbin.org

Después de aplicar la configuración anterior, podemos intentar acceder a httpbin.org directamente a través de APISIX.

kubectl exec -it -n apisix APISIX_POD_NAME -- curl -i -H "Host: local.httpbin.org" http://127.0.0.1:9080/get

Si todo funciona correctamente, verás un resultado como este:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 321
Connection: keep-alive
Date: Thu, 15 Dec 2022 10:47:30 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Server: APISIX/3.0.0

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "local.httpbin.org",
    "User-Agent": "curl/7.29.0",
    "X-Amzn-Trace-Id": "Root=xxxxx",
    "X-Forwarded-Host": "local.httpbin.org"
  },
  "origin": "127.0.0.1, xxxxxxxxx",
  "url": "http://local.httpbin.org/get"
}

El encabezado Server: APISIX/3.0.0 indica que la solicitud ha sido enviada desde APISIX. Y la respuesta contiene X-Amzn-Trace-Id, lo que indica que la solicitud fue manejada por el servicio httpbin en línea.

Upstream de Servicio de Nombre Externo

Implementemos una aplicación simple de httpbin en el espacio de nombres test como backend para el servicio de nombre externo que crearemos más adelante.

kubectl create ns test
kubectl -n test run httpbin --image-pull-policy IfNotPresent --image=kennethreitz/httpbin --port 80
kubectl -n test expose pod/httpbin --port 80

Luego, usa la siguiente configuración para crear un servicio ExternalName en el espacio de nombres apisix.

apiVersion: v1
kind: Service
metadata:
  name: ext-httpbin
spec:
  type: ExternalName
  externalName: httpbin.test.svc

Ahora podemos crear un ApisixRoute y un ApisixUpstream para el servicio ExternalName.

apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  name: ext-route
spec:
  http:
  - name: rule1
    match:
      hosts:
      - ext.httpbin.org
      paths:
      - /*
    upstreams:
    - name: ext-upstream
---
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
  name: ext-upstream
spec:
  externalNodes:
  - type: Service
    name: ext-httpbin

Una vez que las configuraciones estén sincronizadas, intenta acceder con el siguiente comando.

El único argumento que cambia es el encabezado que pasamos.

kubectl exec -it -n apisix APISIX_POD_NAME -- curl -i -H "Host: ext.httpbin.org" http://127.0.0.1:9080/get

La salida debería ser similar a:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 234
Connection: keep-alive
Date: Thu, 15 Dec 2022 10:54:21 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Server: APISIX/3.0.0

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "ext.httpbin.org",
    "User-Agent": "curl/7.29.0",
    "X-Forwarded-Host": "ext.httpbin.org"
  },
  "origin": "127.0.0.1",
  "url": "http://ext.httpbin.org/get"
}

Podemos ver que la respuesta es similar a la anterior, pero algunos campos no existen. Esto se debe a que la solicitud se envió a nuestro servicio local de httpbin en lugar del servicio en línea.

Dominio en Servicio de Nombre Externo

El servicio de nombre externo también puede contener cualquier nombre de dominio fuera del clúster de K8s.

Actualicemos la configuración del servicio externo que aplicamos en la sección anterior.

apiVersion: v1
kind: Service
metadata:
  name: ext-httpbin
spec:
  type: ExternalName
  externalName: httpbin.org

Intenta acceder nuevamente, y la salida debería contener múltiples origin y un encabezado X-Amzn-Trace-Id, lo que significa que estamos accediendo al servicio en línea de httpbin.org.

Conclusión

En este tutorial, extendemos los límites funcionales del controlador de ingress de APISIX al redirigir solicitudes a servicios externos. Esto permite a los usuarios integrar fácilmente servicios de terceros, como servicios de autenticación o servicios entre clústeres.

Para obtener más información sobre la puerta de enlace de API, visita nuestros blogs o contáctanos.

Tags: