Une introduction à Kong

1. Introduction

Kong est une passerelle d’API open source et une couche de gestion de microservices.

Basée sur Nginx et lua-nginx-module (plus particulièrement OpenResty ), l’architecture enfichable de Kong le rend flexible et puissant. .

2. Concepts clés

Avant de plonger dans les exemples de code, examinons les concepts clés de Kong:

  • Objet API - enveloppe les propriétés de tout point de terminaison HTTP (s) qui

accomplit une tâche spécifique ou fournit un service. Les configurations incluent des méthodes HTTP, des URI de points de terminaison, des URL en amont qui pointent vers nos serveurs d’API et seront utilisées pour les demandes de proxy, les retraits maximum, les limites de débit, les délais, etc.

  • Objet consommateur - encapsule les propriétés de toute personne utilisant notre API

points finaux. Il sera utilisé pour le suivi, le contrôle d’accès, etc. Objet en amont - ** décrit comment les demandes entrantes seront traitées par proxy

charge équilibrée, représentée par un nom d’hôte virtuel Objet cible - ** représente les services sont implémentés et servis,

identifié par un nom d’hôte (ou une adresse IP) et un port. Notez que les cibles de chaque amont ne peuvent être que ajoutées ou désactivées. Une histoire de les changements de cible sont maintenus par l’amont Plugin Object - ** fonctionnalités enfichables pour enrichir les fonctionnalités de notre

application pendant le cycle de vie de la demande et de la réponse. Par exemple, API des fonctionnalités d’authentification et de limitation de débit peuvent être ajoutées en activant plugins pertinents. Kong fournit des plugins très puissants dans son https://konghq.com/plugins/ API Admin - ** Points de terminaison de l’API RESTful utilisés pour gérer Kong

configurations, points de terminaison, consommateurs, plugins, etc.

L’image ci-dessous montre la différence entre Kong et une architecture héritée, ce qui pourrait nous aider à comprendre pourquoi elle a introduit ces concepts:

3. Configuration

La documentation officielle fournit des instructions detailed pour divers environnements.

4. Gestion des API

Après avoir configuré Kong localement, découvrons quelques-unes des fonctionnalités puissantes de Kong en effectuant un proxy pour notre terminal de requête boursière simple:

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

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

4.1. Ajout d’une API

Ensuite, ajoutons notre API de requête à Kong.

Les API d’administration sont accessibles via http://localhost : 8001 . Toutes nos opérations de gestion des API seront donc effectuées avec cet URI de base:

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());

Ici, nous avons ajouté une API avec la configuration suivante:

{
    "name": "stock-api",
    "hosts": "stock.api",
    "upstream__url": "http://localhost:8080",
    "uris": "/"
}
  • «Nom» est un identifiant pour l’API, utilisé lors de la manipulation de son

comportement ** “Hôtes” sera utilisé pour router les demandes entrantes vers

"Upstream url" en faisant correspondre l’en-tête "Host" __ ** Les chemins relatifs seront associés aux "uris" configurés

Dans le cas où nous souhaitons rendre obsolète une API ou si la configuration est fausse, nous pouvons simplement la supprimer:

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

Une fois les API ajoutées, elles seront disponibles pour la consommation via http://localhost : 8000 :

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());

Dans l’exemple de code ci-dessus, nous essayons d’interroger le cours de l’action via l’API que nous venons d’ajouter à Kong.

En demandant http://localhost : 8000/stock/btc , nous obtenons le même service que l’interrogation directe à partir de http://localhost : 8080/stock/btc .

4.2. Ajout d’un consommateur API

Parlons maintenant de la sécurité - plus particulièrement de l’authentification des utilisateurs accédant à notre API.

Ajoutons un consommateur à notre API de requête d’actions afin que nous puissions activer la fonctionnalité d’authentification ultérieurement.

Ajouter un consommateur pour une API est aussi simple que d’ajouter une API. Le nom du consommateur (ou id) est le seul champ obligatoire de toutes les propriétés du consommateur:

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());

Ici, nous avons ajouté «eugenp» en tant que nouveau consommateur:

{
    "username": "eugenp"
}

4.3. Activation de l’authentification

Voici la fonctionnalité la plus puissante de Kong, les plugins.

Nous allons maintenant appliquer un plug-in auth à notre API de requête d’actions par proxy:

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());

Si nous essayons d’interroger le prix d’une action via l’URI proxy, la demande sera rejetée:

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());

Rappelez-vous que Eugen est l’un de nos utilisateurs d’API. Nous devrions donc lui permettre d’utiliser cette API en ajoutant une clé d’authentification:

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());

Ensuite, Eugen peut utiliser cette API comme auparavant:

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. Fonctionnalités avancées

Outre le proxy et la gestion des API de base, Kong prend également en charge l’équilibrage de charge, la mise en cluster, la vérification de l’intégrité et la surveillance, etc.

Dans cette section, nous allons examiner comment charger les demandes d’équilibrage avec Kong et comment sécuriser les API d’administration.

5.1. L’équilibrage de charge

Kong propose deux stratégies d’équilibrage de charge pour les services principaux: un équilibreur en anneau dynamique et une méthode simple basée sur DNS. Par souci de simplicité, nous allons utiliser l’équilibreur .

Comme nous l’avons mentionné précédemment, les flux amont sont utilisés pour l’équilibrage de charge et chaque flux amont peut avoir plusieurs cibles.

Kong prend en charge à la fois les algorithmes d’équilibrage pondérés-alternés-basés sur le hachage. Par défaut, le schéma de pondération à tour de rôle est utilisé - les demandes sont envoyées à chaque cible en fonction de leur poids.

Premièrement, préparons l’amont:

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());

Ajoutez ensuite deux cibles pour l’amont, une version de test avec weight = 10 et une version de publication avec 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());

Avec la configuration ci-dessus, nous pouvons supposer que 1/5 des demandes iront à la version test et 4/5 à la version finale:

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);

Notez que le schéma pondéré de répétition alternée équilibre les demandes aux services principaux par rapport au ratio de pondération, de sorte que seule une approximation du ratio peut être vérifiée, comme indiqué dans la dernière ligne du code ci-dessus.

5.2. Sécuriser l’API d’administration

Par défaut, Kong n’accepte que les demandes d’administrateur de l’interface locale, ce qui est une restriction suffisante dans la plupart des cas. Mais si nous voulons le gérer via d’autres interfaces réseau, nous pouvons modifier la valeur admin listen dans kong.conf__ et configurer des règles de pare-feu.

Ou bien, nous pouvons faire en sorte que Kong serve de proxy pour l’API d’administration elle-même. Disons que nous voulons gérer les API avec le chemin “/admin-api”, nous pouvons ajouter une API comme celle-ci:

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());

Nous pouvons maintenant utiliser l’API d’administration mandatée pour gérer les API:

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());

Nous voulons sûrement que l’API mandatée soit sécurisée. Cela peut être facilement réalisé en activant le plug-in d’authentification pour l’API d’administration mandatée.

6. Résumé

Dans cet article, nous avons présenté Kong, une plate-forme pour passerelle API microservice, axée sur ses fonctionnalités principales: la gestion des API et les demandes de routage vers les serveurs en amont, ainsi que sur certaines fonctionnalités plus avancées telles que l’équilibrage de la charge.

Cependant, nous avons encore beaucoup de fonctionnalités à explorer, et nous pouvons développer nos propres plugins si nécessaire. Vous pouvez continuer à explorer la official documentation ici .

Comme toujours, la mise en œuvre complète est disponible à l’adresse over sur Github .