Eine Einführung in Kong

1. Einführung

Kong ist ein Open-Source-API-Gateway und eine Microservice-Verwaltungsschicht.

Basierend auf Nginx und dem lua-nginx-module (insbesondere OpenResty ) ist Kongs steckbare Architektur flexibel und leistungsstark .

2. Schlüssel Konzepte

Bevor wir in Codebeispiele eintauchen, werfen wir einen Blick auf die wichtigsten Konzepte in Kong:

  • API Object - umschließt die Eigenschaften eines beliebigen HTTP-Endpunkts

führt eine bestimmte Aufgabe aus oder liefert einen Dienst. Zu den Konfigurationen gehören HTTP-Methoden, Endpunkt-URIs, Upstream-URLs, die auf unsere API-Server verweisen und für das Proxying von Anforderungen verwendet werden.

  • Consumer Object - verpackt Eigenschaften von Personen, die unsere API verwenden

Endpunkte. Es wird für Tracking, Zugriffskontrolle und mehr verwendet Upstream Object - ** beschreibt, wie eingehende Anfragen weitergeleitet werden

Lastausgleich, dargestellt durch einen virtuellen Hostnamen Zielobjekt - ** stellt die Dienste dar, die implementiert und bereitgestellt werden,

identifiziert durch einen Hostnamen (oder eine IP-Adresse) und einen Port. Beachten Sie, dass Ziele von jedem Upstream können nur hinzugefügt oder deaktiviert werden. Eine Geschichte von Zieländerungen werden vom Upstream beibehalten Plugin Object - ** steckbare Funktionen zur Erweiterung unserer Funktionen

Anwendung während des Anforderungs- und Antwortlebenszyklus. Zum Beispiel API Authentifizierungs- und Ratenbegrenzungsfunktionen können durch Aktivieren hinzugefügt werden relevante Plugins. Kong bietet sehr leistungsfähige Plugins an https://konghq.com/plugins/ Admin-API - ** RESTful-API-Endpunkte für die Verwaltung von Kong

Konfigurationen, Endpunkte, Verbraucher, Plugins usw.

Das folgende Bild zeigt, wie sich Kong von einer älteren Architektur unterscheidet, was uns helfen könnte, zu verstehen, warum es diese Konzepte eingeführt hat:

Link:/uploads/Screen-Shot-2018-01-18-at-14.39.07-768x497.png%20768w[](Quelle: https://getkong.org/ )

3. Setup

Die offizielle Dokumentation enthält detailed Anweisungen für verschiedene Umgebungen.

4. API Management

Nachdem Sie Kong lokal eingerichtet haben, nehmen wir uns ein wenig mit den leistungsstarken Funktionen von Kong auf, indem Sie unseren einfachen Endpunkt für die Aktienabfrage verwenden:

@RestController
@RequestMapping("/stock")
public class QueryController {

    @GetMapping("/{code}")
    public String getStockPrice(@PathVariable String code){
        return "BTC".equalsIgnoreCase(code) ? "10000" : "0";
    }
}

4.1. API hinzufügen

Als Nächstes fügen wir unsere Abfrage-API in Kong hinzu.

Auf die Admin-APIs kann über http://localhost : 8001 __ zugegriffen werden, sodass alle unsere API-Verwaltungsvorgänge mit diesem Basis-URI ausgeführt werden:

APIObject stockAPI = new APIObject(
  "stock-api", "stock.api", "http://localhost:8080", "/");
HttpEntity<APIObject> apiEntity = new HttpEntity<>(stockAPI);
ResponseEntity<String> addAPIResp = restTemplate.postForEntity(
  "http://localhost:8001/apis", apiEntity, String.class);

assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode());

Hier haben wir eine API mit der folgenden Konfiguration hinzugefügt:

{
    "name": "stock-api",
    "hosts": "stock.api",
    "upstream__url": "http://localhost:8080",
    "uris": "/"
}
  • "Name" ist eine Kennung für die API, die bei der Bearbeitung der API verwendet wird

Verhalten ** „Hosts“ wird verwendet, um eingehende Anfragen an gegebene Anfragen weiterzuleiten

"Upstream url" durch Abgleichen des "Host" __ Headers ** Relative Pfade werden an die konfigurierten "uris" angepasst

Wenn wir eine API abschaffen möchten oder die Konfiguration falsch ist, können Sie sie einfach entfernen:

restTemplate.delete("http://localhost:8001/apis/stock-api");

Nachdem die APIs hinzugefügt wurden, stehen sie über http://localhost : 8000 zur Verfügung.

String apiListResp = restTemplate.getForObject(
  "http://localhost:8001/apis/", String.class);

assertTrue(apiListResp.contains("stock-api"));

HttpHeaders headers = new HttpHeaders();
headers.set("Host", "stock.api");
RequestEntity<String> requestEntity = new RequestEntity<>(
  headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
ResponseEntity<String> stockPriceResp
  = restTemplate.exchange(requestEntity, String.class);

assertEquals("10000", stockPriceResp.getBody());

Im obigen Codebeispiel versuchen wir, den Aktienkurs über die API abzufragen, die wir gerade zu Kong hinzugefügt haben.

Wenn Sie http://localhost : 8000/stock/btc anfordern, erhalten wir denselben Service wie eine direkte Abfrage von http://localhost : 8080/stock/btc .

4.2. API-Consumer hinzufügen

Lassen Sie uns jetzt über Sicherheit sprechen, insbesondere über die Authentifizierung der Benutzer, die auf unsere API zugreifen.

Fügen wir unserer Stock-Abfrage-API einen Consumer hinzu, damit wir die Authentifizierungsfunktion später aktivieren können.

Das Hinzufügen eines Consumer für eine API ist genauso einfach wie das Hinzufügen einer API. Der Name des Verbrauchers (oder die ID) ist das einzige erforderliche Feld aller Eigenschaften des Verbrauchers:

ConsumerObject consumer = new ConsumerObject("eugenp");
HttpEntity<ConsumerObject> addConsumerEntity = new HttpEntity<>(consumer);
ResponseEntity<String> addConsumerResp = restTemplate.postForEntity(
  "http://localhost:8001/consumers/", addConsumerEntity, String.class);

assertEquals(HttpStatus.CREATED, addConsumerResp.getStatusCode());

Hier haben wir "eugenp" als neuen Verbraucher hinzugefügt:

{
    "username": "eugenp"
}

4.3. Aktivieren der Authentifizierung

Hier kommt das mächtigste Feature von Kong, Plugins.

Jetzt werden wir ein Auth-Plugin auf unsere Proxy-Aktien-Abfrage-API anwenden:

PluginObject authPlugin = new PluginObject("key-auth");
ResponseEntity<String> enableAuthResp = restTemplate.postForEntity(
  "http://localhost:8001/apis/stock-api/plugins",
  new HttpEntity<>(authPlugin),
  String.class);
assertEquals(HttpStatus.CREATED, enableAuthResp.getStatusCode());

Wenn wir versuchen, den Aktienkurs über den Proxy-URI abzufragen, wird die Anfrage abgelehnt:

HttpHeaders headers = new HttpHeaders();
headers.set("Host", "stock.api");
RequestEntity<String> requestEntity = new RequestEntity<>(
  headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
ResponseEntity<String> stockPriceResp = restTemplate
  .exchange(requestEntity, String.class);

assertEquals(HttpStatus.UNAUTHORIZED, stockPriceResp.getStatusCode());

Denken Sie daran, dass Eugen einer unserer API-Benutzer ist. Daher sollten wir ihm erlauben, diese API durch Hinzufügen eines Authentifizierungsschlüssels zu verwenden:

String consumerKey = "eugenp.pass";
KeyAuthObject keyAuth = new KeyAuthObject(consumerKey);
ResponseEntity<String> keyAuthResp = restTemplate.postForEntity(
  "http://localhost:8001/consumers/eugenp/key-auth",
  new HttpEntity<>(keyAuth),
  String.class);
assertTrue(HttpStatus.CREATED == keyAuthResp.getStatusCode());

Dann kann Eugen diese API wie zuvor verwenden:

HttpHeaders headers = new HttpHeaders();
headers.set("Host", "stock.api");
headers.set("apikey", consumerKey);
RequestEntity<String> requestEntity = new RequestEntity<>(
  headers,
  HttpMethod.GET,
  new URI("http://localhost:8000/stock/btc"));
ResponseEntity<String> stockPriceResp = restTemplate
  .exchange(requestEntity, String.class);

assertEquals("10000", stockPriceResp.getBody());

5. Erweiterte Funktionen

Neben dem grundlegenden API-Proxy und -Management unterstützt Kong auch den API-Lastausgleich, Clustering, Statusprüfung und -Überwachung usw.

In diesem Abschnitt erfahren Sie, wie Sie Lastausgleichsanforderungen mit Kong laden und wie Sie Administrations-APIs schützen.

5.1. Lastverteilung

Kong bietet zwei Strategien für Lastausgleichsanforderungen an Backend-Services: einen dynamischen Ringausgleich und eine einfache DNS-basierte Methode. Der Einfachheit halber verwenden wir den Ring-Balancer .

Wie bereits erwähnt, werden Upstreams für den Lastausgleich verwendet, und jeder Upstream kann mehrere Ziele haben.

Kong unterstützt sowohl gewichtete Round-Robin-Algorithmen als auch Hash-basierte Algorithmen. Standardmäßig wird das Schema mit gewichtetem Round-Robin-Verfahren verwendet. - Hier werden Anforderungen an jedes Ziel entsprechend ihrem Gewicht übermittelt.

Lassen Sie uns zunächst den Upstream vorbereiten:

UpstreamObject upstream = new UpstreamObject("stock.api.service");
ResponseEntity<String> addUpstreamResp = restTemplate.postForEntity(
  "http://localhost:8001/upstreams",
  new HttpEntity<>(upstream),
  String.class);

assertEquals(HttpStatus.CREATED, addUpstreamResp.getStatusCode());

Fügen Sie dann zwei Ziele für den Upstream hinzu, eine Testversion mit weight = 10 und eine Release-Version mit weight = 40 :

TargetObject testTarget = new TargetObject("localhost:8080", 10);
ResponseEntity<String> addTargetResp = restTemplate.postForEntity(
  "http://localhost:8001/upstreams/stock.api.service/targets",
  new HttpEntity<>(testTarget),
  String.class);

assertEquals(HttpStatus.CREATED, ddTargetResp.getStatusCode());

TargetObject releaseTarget = new TargetObject("localhost:9090",40);
addTargetResp = restTemplate.postForEntity(
  "http://localhost:8001/upstreams/stock.api.service/targets",
  new HttpEntity<>(releaseTarget),
  String.class);

assertEquals(HttpStatus.CREATED, addTargetResp.getStatusCode());

Bei der obigen Konfiguration können wir davon ausgehen, dass 1/5 der Anforderungen zur Testversion und 4/5 zur Release-Version gehen:

APIObject stockAPI = new APIObject(
  "balanced-stock-api",
  "balanced.stock.api",
  "http://stock.api.service",
  "/");
HttpEntity<APIObject> apiEntity = new HttpEntity<>(stockAPI);
ResponseEntity<String> addAPIResp = restTemplate.postForEntity(
  "http://localhost:8001/apis", apiEntity, String.class);

assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode());

HttpHeaders headers = new HttpHeaders();
headers.set("Host", "balanced.stock.api");
for(int i = 0; i < 1000; i++) {
    RequestEntity<String> requestEntity = new RequestEntity<>(
      headers, HttpMethod.GET, new URI("http://localhost:8000/stock/btc"));
    ResponseEntity<String> stockPriceResp
     = restTemplate.exchange(requestEntity, String.class);

    assertEquals("10000", stockPriceResp.getBody());
}

int releaseCount = restTemplate.getForObject(
  "http://localhost:9090/stock/reqcount", Integer.class);
int testCount = restTemplate.getForObject(
  "http://localhost:8080/stock/reqcount", Integer.class);

assertTrue(Math.round(releaseCount **  1.0/testCount) == 4);

Beachten Sie, dass das Weighted-Round-Robin-Schema die Anforderungen an Backend-Services ungefähr auf das Gewichtsverhältnis ausbalanciert, sodass nur eine Annäherung an das Verhältnis überprüft werden kann, die in der letzten Zeile des obigen Codes dargestellt wird.

5.2. Sichern der Admin-API

Standardmäßig akzeptiert Kong nur Administratoranforderungen von der lokalen Schnittstelle, was in den meisten Fällen eine hinreichende Einschränkung darstellt. Wenn Sie es jedoch über andere Netzwerkschnittstellen verwalten möchten, können Sie den Wert admin listen in kong.conf__ ändern und Firewall-Regeln konfigurieren.

Oder wir können Kong als Proxy für die Admin-API selbst verwenden. Angenommen, wir möchten APIs mit dem Pfad „/admin-api“ verwalten, wir können eine API wie folgt hinzufügen:

APIObject stockAPI = new APIObject(
  "admin-api",
  "admin.api",
  "http://localhost:8001",
  "/admin-api");
HttpEntity<APIObject> apiEntity = new HttpEntity<>(stockAPI);
ResponseEntity<String> addAPIResp = restTemplate.postForEntity(
  "http://localhost:8001/apis",
  apiEntity,
  String.class);

assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode());

Jetzt können wir die Proxy-Admin-API verwenden, um APIs zu verwalten:

HttpHeaders headers = new HttpHeaders();
headers.set("Host", "admin.api");
APIObject baeldungAPI = new APIObject(
  "baeldung-api",
  "baeldung.com",
  "http://ww.baeldung.com",
  "/");
RequestEntity<APIObject> requestEntity = new RequestEntity<>(
  baeldungAPI,
  headers,
  HttpMethod.POST,
  new URI("http://localhost:8000/admin-api/apis"));
ResponseEntity<String> addAPIResp = restTemplate
  .exchange(requestEntity, String.class);

assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode());

Sicher möchten wir, dass die Proxy-API gesichert wird. Dies kann leicht durch Aktivieren des Authentifizierungs-Plugins für die Proxy-Admin-API erreicht werden.

6. Zusammenfassung

In diesem Artikel haben wir Kong - eine Plattform für Microservice API Gateway - vorgestellt, die sich auf ihre Kernfunktionen konzentriert: APIs verwalten und Anforderungen an Upstream-Server weiterleiten sowie einige erweiterte Funktionen wie Lastverteilung.

Es gibt jedoch noch viele weitere solide Features, die wir erforschen können, und wir können bei Bedarf eigene Plugins entwickeln.

Wie immer ist die vollständige Implementierung über Github zu finden .