Maßgeschneiderte Lösungen freischalten: Apache APISIX und Node-RED harmonisch nutzen

March 6, 2024

Ecosystem

Hintergrund

Viele Apache APISIX-Benutzer benötigen in Unternehmensumgebungen Anpassungen, um spezifische Anforderungen in bestimmten Szenarien zu erfüllen, obwohl es viele leistungsstarke integrierte Plugin-Funktionen bietet.

Benutzer wählen oft, Plugins in Lua zu schreiben und sie auf APISIX-Instanzen zu mounten. Lua hat jedoch eine relativ begrenzte Zielgruppe. Obwohl es einfach zu erlernen ist, ist es nicht einfach, es zu beherrschen, und die Implementierung komplexer Datenumwandlungslogik in Lua kann recht kompliziert werden. Derzeit werden nur ein Teil der Hooks vom Java Plugin Runner für Entwickler freigegeben, um sie aufzurufen, was Änderungen am Quellcode des Java Plugin Runners für Funktionen erfordert, die nicht direkt unterstützt werden.

Das folgende Diagramm zeigt drei gängige Plugin-Nutzungsmuster: Lua-Plugins, die direkt im APISIX-Kern ausgeführt werden; Plugin Runner, der über RPC mit Plugin Runnern in Sprachen wie Java, Golang usw. kommuniziert; und WASM-Plugins, die in Bytecode umgewandelt und intern im APISIX-Kern ausgeführt werden.

Plugin und Plugin Runner von APISIX

Aus Benutzerfeedback wurde festgestellt, dass der Bedarf an benutzerdefinierten Plugins oft mit Datenumwandlungen wie HTTP-Anforderungsparametern und dem Aufruf externer APIs zur Datenverarbeitung zusammenhängt.

Um dies zu lösen, wurde ein neuer Ansatz vorgeschlagen, um die Fähigkeiten von Apache APISIX zu erweitern. Dieser Ansatz beinhaltet die Verwendung nur integrierter Plugins in Apache APISIX, um gängige Funktionen wie Authentifizierung und Ratenbegrenzung zu konfigurieren, während neu angepasste Logik in externe Dienste ausgelagert wird. Der externe Dienst kann entweder ein Binärprogramm oder ein anderer API-Dienst sein, der als Upstream für APISIX behandelt wird. Dieser externe Dienst wird Anfragen und Antworten wie Middleware verarbeiten. Dieser Ansatz kann auch auf andere API-Gateways oder Proxy-Dienste angewendet werden.

Szenariobeschreibung

Wir haben eine Reihe von Diensten, die Datenabfragedienste upstream bereitstellen (dieser Artikel verwendet https://api-ninjas.com/api als Beispiel). Beispielsweise kann man basierend auf dem Stadtnamen die neuesten Wetterinformationen und Informationen über das Land (wie das BIP des Landes, den Namen der Hauptstadt und die Währungseinheit) abrufen.

Unser Hauptziel ist es, Entwicklern eine generische Anfrageschnittstelle bereitzustellen, während wir dennoch in der Lage sind, den gewünschten Dateninhalt basierend auf dem Stadtnamen und dem Datenbereichsparameter zu bestimmen. Um die Upstream-Dienste vor Missbrauch zu schützen, müssen wir dem Entwicklerinterface einen Authentifizierungsdienst hinzufügen, sodass nur Anfragen mit dem richtigen API-Schlüssel an den Upstream-Dienst weitergeleitet werden.

Problemanalyse

Vor der Einführung von Node-Red würden APISIX-Entwickler, um die oben genannten Anforderungen zu erfüllen, die Verwendung von Lua-Plugins in Betracht ziehen. Obwohl Apache APISIX eine detaillierte Plugin-Entwicklungsdokumentation bereitstellt, müssen Geschäftsentwickler die Lua-Syntax und Optimierungstechniken erlernen, die verschiedenen Anfrage-Hooks verstehen, die von APISIX freigegeben werden, und während des Schreibens der Logik für die Parameterextraktion und -validierung kontinuierlich Plugins neu laden. Nach Abschluss der Tests müssen sie auch Lua-Plugins in das APISIX-Programm packen oder an alle APISIX-Instanzen verteilen, um sie zu mounten.

Die Beispielanforderungen, die wir in diesem Blog bereitstellen, beinhalten das Parsen spezifischer Parameter aus Client-Anfragen und dann das Erstellen von Anfragen, um Daten von verschiedenen Upstream-Diensten abzurufen. Wir haben jedoch viel Zeit damit verbracht, sich mit Transaktionen außerhalb der Geschäftsschreibung zu befassen. Daher können wir für solche Logiken, die Parameterumwandlung, Formatumwandlung oder externe Aufrufe beinhalten, einen leichteren, intuitiveren Ansatz wählen, was genau das Problem ist, das Node-Red lösen kann.

Node-Red Einführung

Node-RED ist ein leistungsstarkes und einfach zu bedienendes Flow-basiertes Programmierwerkzeug, das sich für Automatisierungs- und Datenflussverarbeitungsaufgaben in verschiedenen Bereichen eignet. Seine Programmieroberfläche, reiche Knotenbibliothek und flexible Erweiterbarkeit ermöglichen es uns, schnell komplexe Flows zu erstellen und verschiedene Anwendungsszenarien zu implementieren. Hier sind einige der von Node-RED bereitgestellten Knoten:

  • HTTP_IN-Knoten: Stellt einen Endpunkt für den Aufruf externer Dienste bereit, den wir als Upstream-Dienst für APISIX verwenden werden.

  • Funktionsknoten: Ermöglicht Entwicklern, Codefunktionen in JavaScript zu schreiben, um Eingaben/Ausgaben zu ändern, zu löschen usw.

  • Switch-Knoten: Ermöglicht Entwicklern, eine Reihe von Bedingungen festzulegen, um den nächsten angegebenen Knoten zu betreten, wenn eine Bedingung erfüllt ist.

  • HTTP_Request-Knoten: Kann URL usw. festlegen, um Daten beim Ausführen des gesamten Workflows an diesen Endpunkt zu senden.

  • Change-Knoten: Kann angegebene Werte eines angegebenen Objekts hinzufügen, ändern oder löschen.

  • HTTP_Response-Knoten: Wird verwendet, um Antworten an Clients zurückzugeben.

Neben den oben aufgeführten Knoten bietet Node-RED auch viele andere integrierte Knoten. Dieser Artikel wird den Lesern zeigen, wie man die oben genannten Anforderungen durch Node-RED implementiert.

Beispiel-Demonstration

Umgebungseinrichtung

Wir werden die benötigten Komponenten durch Containerisierung bereitstellen und einen DigitalOcean Droplet als Serverressource verwenden.

$ doctl compute ssh-key list

ID          Name             FingerPrint
25621060    Zhiyuan Ju       2c:84:b7:d8:14:0a:a0:0f:ca:fe:ca:24:06:a4:fe:39

$ doctl compute droplet create \
    --image docker-20-04 \
    --size s-2vcpu-4gb-amd \
    --region sgp1 \
    --vpc-uuid 646cf2b8-03d8-4f48-b7c8-57cdee60ad27 \
    --ssh-keys 25621060 \
    apisix-nodered-docker-ubuntu-s-2vcpu-4gb-amd-sgp1-01
  
$ doctl compute droplet list

ID           Name                                                    Public IPv4       Private IPv4    Public IPv6    Memory    VCPUs    Disk    Region    Image                                   VPC UUID                                Status    Tags    Features                            Volumes
404094941    apisix-nodered-docker-ubuntu-s-2vcpu-4gb-amd-sgp1-01    143.198.192.64    10.104.0.3                     4096      2        80      sgp1      Ubuntu Docker 25.0.3 on Ubuntu 22.04    646cf2b8-03d8-4f48-b7c8-57cdee60ad27    active            droplet_agent,private_networking

Apache APISIX bereitstellen

Wir werden den APISIX Quickstart verwenden, um eine neue APISIX-Instanz zu starten. Für spezifische Dokumentation siehe https://docs.api7.ai/apisix/getting-started/.

$ curl -sL https://run.api7.ai/apisix/quickstart | sh

Node-RED bereitstellen

Node-RED bietet mehrere Bereitstellungsmethoden, und wir werden es schnell über Docker bereitstellen und in die bestehende Umgebung integrieren. Weitere Bereitstellungsdetails finden Sie in der offiziellen Dokumentation: https://nodered.org/docs/getting-started/.

Stellen Sie sicher, dass der Container beim Bereitstellen von Node-RED zum APISIX-Netzwerk hinzugefügt wird, um sicherzustellen, dass er mit APISIX kommunizieren und Anfragen verarbeiten kann.

$ docker run -d -it -p 1880:1880 -v $PWD/configs/nodered/data:/data --network=apisix-quickstart-net --name mynodered -u Node-Red:dialout nodered/Node-Red

Node-RED konfigurieren

  1. Um Anfragen, die von APISIX in Node-RED eingehen, zu verarbeiten, muss Node-Red überprüfen, ob die Parameter in der Anfrage vorhanden und gültig sind. Wenn die Parameter fehlen oder ungültig sind, wird eine Fehlermeldung zurückgegeben. Wenn sie gültig sind, wird der nächste Knoten ausgeführt. In diesem spezifischen Szenario erlauben wir nur Datenabfragen für zwei Städte, Stockholm (city=stockholm) und Berlin (city=berlin).

Verwenden von Node-Red, um Parameter zu überprüfen

  1. Sobald die Anfrage den nächsten Knoten betritt, muss Node-RED den Typ der angeforderten Daten bestimmen. In diesem Szenario gibt es drei Typen: Wetterinformationen (scope=weather), Informationen über das Land, in dem sich die Stadt befindet (scope=country), und das BIP des Landes, in dem sich die Stadt befindet (scope=gdp).

Verwenden von Node-Red, um den Datentyp zu bestimmen

  1. Wenn sowohl der City- als auch der Scope-Parameter gültig sind, wird Node-RED basierend auf dem Wert von scope bestimmen, von welcher API Daten abgerufen werden sollen. Nachdem URL, Methode, Payload, X-API-Key usw. festgelegt wurden, wird der Knoten von Node-RED beim Auslösen den entsprechenden Endpunkt aufrufen, um Daten abzurufen.

API für die Datenbeschaffung nach Scope auswählen

  1. Beim Abrufen von Daten für scope=gdp muss Node-RED den BIP-Wert aus dem Antwortkörper der externen API extrahieren. Dies kann mit dem Change-Knoten für die Extraktion oder dem Function-Knoten erfolgen.

BIP-Wert aus dem Antwortkörper der externen API parsen

  1. Schließlich wird Node-RED die verarbeiteten Daten an APISIX zurückgeben, die sie an den Client weiterleiten. Das endgültige Node-RED-Diagramm ist unten dargestellt.

Flussdiagramm der Kombination von APISIX und Node-Red

APISIX-Routen erstellen

Um den Node-Red-Dienst für Clients verfügbar zu machen, müssen wir APISIX als Reverse-Proxy für die von Node-Red freigegebenen Endpunkte verwenden. Hier sind die Schritte, die Sie befolgen müssen:

  1. Erstellen Sie eine APISIX-Route und setzen Sie mynodered:1880 als Upstream für diese Route. Dadurch werden alle Anfragen, die an diesen Endpunkt gesendet werden, an den Node-Red-Dienst weitergeleitet.

  2. Aktivieren Sie die Schlüsselauthentifizierung, um sicherzustellen, dass nur Anfragen mit einem gültigen API-Schlüssel die Authentifizierung bestehen und auf den Node-Red-Dienst zugreifen können.

Durch die Befolgung der oben genannten Schritte können wir den Node-Red-Dienst sicher für Clients freigeben und sicherstellen, dass nur autorisierte Benutzer darauf zugreifen können.

$ curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
  "id": "proxy-global-data-endpoint",
  "uri": "/global-data",
  "upstream": {
    "type": "roundrobin",
    "nodes": {
      "mynodered:1880": 1
    }
  },
  "plugins": {
    "key-auth": {}
  }
}'

$ curl -i "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT -d '
{
  "username": "tom",
  "plugins": {
    "key-auth": {
      "key": "secret-key"
    }
  }
}'

Anfragevalidierung

Wir werden mehrere Szenarien separat testen, um zu überprüfen, ob APISIX und Node-Red wie erwartet funktionieren:

Szenario 1

  • Szenariobeschreibung: Zugriff auf die API mit einem falschen Schlüssel.

  • Erwartetes Ergebnis: Da der bereitgestellte API-Schlüssel falsch ist, sollte die Anfrage abgelehnt werden, und die entsprechende Fehlermeldung sollte zurückgegeben werden.

$ curl http://143.198.192.64:9080/global-data -H "apikey: invalid-key" -i

HTTP/1.1 401 Unauthorized
Date: Mon, 04 Mar 2024 07:47:24 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/3.8.0

{"message":"Invalid API key in request"}

Szenario 2

  • Szenariobeschreibung: Zugriff auf die API mit dem richtigen Schlüssel, aber einem ungültigen City-Feld.

  • Erwartetes Ergebnis: Da die Anfrageparameter die Anforderungen nicht erfüllen, sollte die entsprechende Fehlermeldung zurückgegeben werden, die angibt, dass das City-Feld ungültig ist.

$ curl "http://143.198.192.64:9080/global-data?city=singapore&scope=country" -H "apikey: secret-key" -i

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 69
Connection: keep-alive
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
ETag: W/"45-IOhgB2XkDHi2Kt4PP42n1xa8Gys"
Date: Mon, 04 Mar 2024 07:48:02 GMT
Server: APISIX/3.8.0

{"errorCode":400,"message":"Allowed city Options: Stockholm, Berlin"}

Szenario 3

  • Szenariobeschreibung: Zugriff auf die API mit dem richtigen Schlüssel und gültigen City- und Scope-Feldern, um Länd
Tags: