En introduktion til Kong

1. Introduktion

Kong er en open source API-gateway og mikroservicestyringslag.

Baseret på Nginx og lua-nginx-modulet (specifikt OpenResty) gør Kongs pluggbare arkitektur det fleksibelt og kraftfuldt.

2. Nøglebegreber

Før vi dykker ned i kodeeksempler, skal vi se på nøglebegreberne i Kong:

  • API-objekt - indpakker egenskaber for ethvert HTTP (s) slutpunkt, der udfører en bestemt opgave eller leverer en tjeneste. Konfigurationer inkluderer HTTP-metoder, slutpunkts-URI'er, upstream-URL, der peger på vores API-servere og vil blive brugt til proxy-anmodninger, maksimale pensionering, takstgrænser, timeouts osv.
  • Forbrugerobjekt - indpakker egenskaber for alle, der bruger vores API-slutpunkter. Det vil blive brugt til sporing, adgangskontrol og mere
  • Opstrøms objekt - beskriver, hvordan indgående anmodninger vil blive proxied eller belastningsbalanceret, repræsenteret af et virtuelt værtsnavn
  • Målobjekt - repræsenterer tjenesterne implementeres og serveres, identificeret ved et værtsnavn (eller en IP-adresse) og en port. Bemærk, at mål for hver opstrøm kun kan tilføjes eller deaktiveres. En historie med målændringer opretholdes af opstrøms
  • Plugin-objekt - pluggbare funktioner, der beriger funktionerne i vores applikation i løbet af anmodningens og reaktionens livscyklus. For eksempel kan API-godkendelse og hastighedsbegrænsende funktioner tilføjes ved at aktivere relevante plugins. Kong leverer meget kraftfulde plugins i sit plugins galleri
  • Admin API - RESTful API-slutpunkter, der bruges til at styre Kong-konfigurationer, slutpunkter, forbrugere, plugins osv

Billedet nedenfor viser, hvordan Kong adskiller sig fra en ældre arkitektur, hvilket kan hjælpe os med at forstå, hvorfor det introducerede disse begreber:

(kilde: //getkong.org/)

3. Opsætning

Den officielle dokumentation indeholder detaljerede instruktioner til forskellige miljøer.

4. API-styring

Efter at have konfigureret Kong lokalt, lad os tage en bid af Kongs kraftfulde funktioner ved at proxy vores enkle lagerforespørgsel slutpunkt:

@RestController @RequestMapping ("/ stock") offentlig klasse QueryController {@GetMapping ("/ {code}") offentlig streng getStockPrice (@PathVariable strengkode) {returner "BTC" .equalsIgnoreCase (kode)? "10000": "0"; }}

4.1. Tilføjelse af en API

Lad os derefter tilføje vores forespørgsel API til Kong.

Admin API'erne er tilgængelige via // localhost: 8001, så alle vores API-administrationsoperationer udføres med denne basale URI:

APIObject stockAPI = ny APIObject ("stock-api", "stock.api", "// localhost: 8080", "/"); HttpEntity apiEntity = ny HttpEntity (stockAPI); ResponseEntity addAPIResp = restTemplate.postForEntity ("// localhost: 8001 / apis", apiEntity, String.class); assertEquals (HttpStatus.CREATED, addAPIResp.getStatusCode ());

Her tilføjede vi en API med følgende konfiguration:

{"name": "stock-api", "hosts": "stock.api", "upstream_url": "// localhost: 8080", "uris": "/"}
  • "navn" er en identifikator for API'en, der bruges ved manipulation af dens adfærd
  • “Værter” vil blive brugt til at dirigere indgående anmodninger til det givne “Opstrøms_url” ved at matche "Vært" header
  • Relative stier matches med den konfigurerede “uris”

Hvis vi ønsker at udfase en API, eller konfigurationen er forkert, kan vi blot fjerne den:

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

Når API'er er tilføjet, vil de være tilgængelige til forbrug gennem // localhost: 8000:

String apiListResp = restTemplate.getForObject ("// localhost: 8001 / apis /", String.class); assertTrue (apiListResp.contains ("stock-api")); HttpHeaders headers = nye HttpHeaders (); headers.set ("Host", "stock.api"); RequestEntity requestEntity = ny RequestEntity (overskrifter, HttpMethod.GET, ny URI ("// localhost: 8000 / stock / btc")); ResponseEntity stockPriceResp = restTemplate.exchange (requestEntity, String.class); assertEquals ("10000", stockPriceResp.getBody ());

I ovenstående kodeeksempel forsøger vi at spørge aktiekursen via den API, vi lige har tilføjet til Kong.

Ved at anmode om // localhost: 8000 / lager / btc, vi får den samme service som forespørgsel direkte fra // localhost: 8080 / lager / btc.

4.2. Tilføjelse af en API-forbruger

Lad os nu tale om sikkerhed - mere specifikt godkendelse for de brugere, der får adgang til vores API.

Lad os tilføje en forbruger til vores lagerforespørgsel API, så vi kan aktivere godkendelsesfunktionen senere.

At tilføje en forbruger til en API er lige så simpelt som at tilføje en API. Forbrugerens navn (eller id) er det eneste krævede felt af alle forbrugeres egenskaber:

ConsumerObject forbruger = ny ConsumerObject ("eugenp"); HttpEntity addConsumerEntity = ny HttpEntity (forbruger); ResponseEntity addConsumerResp = restTemplate.postForEntity ("// localhost: 8001 / forbrugere /", addConsumerEntity, String.class); assertEquals (HttpStatus.CREATED, addConsumerResp.getStatusCode ());

Her tilføjede vi "eugenp" som en ny forbruger:

{"brugernavn": "eugenp"}

4.3. Aktivering af godkendelse

Her kommer den mest kraftfulde funktion i Kong, plugins.

Nu skal vi anvende et auth-plugin til vores proxy API-forespørgsel:

PluginObject authPlugin = ny PluginObject ("nøgle-godkendelse"); ResponseEntity enableAuthResp = restTemplate.postForEntity ("// localhost: 8001 / apis / stock-api / plugins", ny HttpEntity (authPlugin), String.class); assertEquals (HttpStatus.CREATED, enableAuthResp.getStatusCode ());

Hvis vi forsøger at spørge en aktiekurs gennem proxy-URI, afvises anmodningen:

HttpHeaders headers = nye HttpHeaders (); headers.set ("Host", "stock.api"); RequestEntity requestEntity = ny RequestEntity (overskrifter, HttpMethod.GET, ny URI ("// localhost: 8000 / stock / btc")); ResponseEntity stockPriceResp = restTemplate .exchange (requestEntity, String.class); assertEquals (HttpStatus.UNAUTHORIZED, stockPriceResp.getStatusCode ());

Huske på, at Eugen er en af ​​vores API-forbrugere, så vi bør tillade ham at bruge denne API ved at tilføje en godkendelsesnøgle:

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

Derefter Eugen kan bruge denne API som før:

HttpHeaders headers = nye HttpHeaders (); headers.set ("Host", "stock.api"); headers.set ("apikey", consumerKey); RequestEntity requestEntity = ny RequestEntity (overskrifter, HttpMethod.GET, ny URI ("// localhost: 8000 / stock / btc")); ResponseEntity stockPriceResp = restTemplate .exchange (requestEntity, String.class); assertEquals ("10000", stockPriceResp.getBody ());

5. Avancerede funktioner

Bortset fra grundlæggende API-proxy og styring understøtter Kong også API-belastningsbalancering, klyngedannelse, sundhedskontrol og overvågning osv.

I dette afsnit vil vi se på, hvordan man indlæser balanceanmodninger med Kong, og hvordan man sikrer admin-API'er.

5.1. Load Balancing

Kong leverer to strategier for belastningsafbalanceringsanmodninger til backend-tjenester: en dynamisk ringbalancer og en ligetil DNS-baseret metode. For enkelhedens skyld, vi bruger ringbalanceren.

Som vi nævnte tidligere, bruges upstreams til belastningsbalancering, og hver upstream kan have flere mål.

Kong understøtter både vægtede-round-robin og hash-baserede balanceringsalgoritmer. Som standard bruges den vægtede-round-robin-ordning - hvor anmodninger leveres til hvert mål i henhold til deres vægt.

Lad os først forberede opstrøms:

UpstreamObject upstream = ny UpstreamObject ("stock.api.service"); ResponseEntity addUpstreamResp = restTemplate.postForEntity ("// localhost: 8001 / upstreams", ny HttpEntity (opstrøms), String.class); assertEquals (HttpStatus.CREATED, addUpstreamResp.getStatusCode ());

Tilføj derefter to mål for opstrøms, en testversion med vægt = 10, og en frigivelsesversion med vægt = 40:

TargetObject testTarget = new TargetObject ("localhost: 8080", 10); ResponseEntity addTargetResp = restTemplate.postForEntity ("//localhost:8001/upstreams/stock.api.service/targets", ny HttpEntity (testTarget), String.class); assertEquals (HttpStatus.CREATED, ddTargetResp.getStatusCode ()); TargetObject releaseTarget = ny TargetObject ("localhost: 9090", 40); addTargetResp = restTemplate.postForEntity ("//localhost:8001/upstreams/stock.api.service/targets", ny HttpEntity (releaseTarget), String.class); assertEquals (HttpStatus.CREATED, addTargetResp.getStatusCode ());

Med ovenstående konfiguration kan vi antage, at 1/5 af anmodningerne går til testversion, og 4/5 går til frigivelsesversion:

APIObject stockAPI = ny APIObject ("balanced-stock-api", "balanced.stock.api", "//stock.api.service", "/"); HttpEntity apiEntity = ny HttpEntity (stockAPI); ResponseEntity addAPIResp = restTemplate.postForEntity ("// localhost: 8001 / apis", apiEntity, String.class); assertEquals (HttpStatus.CREATED, addAPIResp.getStatusCode ()); HttpHeaders headers = nye HttpHeaders (); headers.set ("Host", "balanced.stock.api"); for (int i = 0; i <1000; i ++) {RequestEntity requestEntity = new RequestEntity (overskrifter, HttpMethod.GET, ny URI ("// localhost: 8000 / stock / btc")); ResponseEntity stockPriceResp = restTemplate.exchange (requestEntity, String.class); assertEquals ("10000", stockPriceResp.getBody ()); } int releaseCount = restTemplate.getForObject ("// localhost: 9090 / stock / reqcount", Integer.class); int testCount = restTemplate.getForObject ("// localhost: 8080 / stock / reqcount", Integer.class); assertTrue (Math.round (releaseCount * 1.0 / testCount) == 4);

Bemærk, at en vægtet-round-robin-ordning balancerer anmodninger om backend-tjenester omtrent til vægtforholdet, så kun en tilnærmelse af forholdet kan verificeres, hvilket afspejles i den sidste linje i ovenstående kode.

5.2. Sikring af Admin API

Som standard accepterer Kong kun administratoranmodninger fra den lokale grænseflade, hvilket i de fleste tilfælde er en god nok begrænsning. Men hvis vi vil styre det via andre netværksgrænseflader, kan vi ændre admin_listen værdi i kong.conf, og konfigurer firewallregler.

Eller vi kan få Kong til at fungere som en proxy for selve Admin API. Sig, at vi vil administrere API'er med stien “/ admin-api”, vi kan tilføje en API som denne:

APIObject stockAPI = ny APIObject ("admin-api", "admin.api", "// localhost: 8001", "/ admin-api"); HttpEntity apiEntity = ny HttpEntity (stockAPI); ResponseEntity addAPIResp = restTemplate.postForEntity ("// localhost: 8001 / apis", apiEntity, String.class); assertEquals (HttpStatus.CREATED, addAPIResp.getStatusCode ());

Nu kan vi bruge den proxy-admin-API til at administrere API'er:

HttpHeaders headers = nye HttpHeaders (); headers.set ("vært", "admin.api"); APIObject baeldungAPI = ny APIObject ("baeldung-api", "baeldung.com", "//ww.baeldung.com", "/"); RequestEntity requestEntity = ny RequestEntity (baeldungAPI, overskrifter, HttpMethod.POST, ny URI ("// localhost: 8000 / admin-api / apis")); ResponseEntity addAPIResp = restTemplate .exchange (requestEntity, String.class); assertEquals (HttpStatus.CREATED, addAPIResp.getStatusCode ());

Vi vil helt sikkert have den proxy-API beskyttet. Dette kan let opnås ved at aktivere godkendelses-plugin til den proxyserverede admin API.

6. Resume

I denne artikel introducerede vi Kong - en platform til mikroservice-API-gateway og fokuseret på dens kernefunktionalitet - styring af API'er og routingsanmodninger til upstream-servere såvel som på nogle mere avancerede funktioner som f.eks.

Alligevel er der mange flere solide funktioner, som vi kan udforske, og vi kan udvikle vores egne plugins, hvis vi har brug for det - du kan fortsætte med at udforske den officielle dokumentation her.

Som altid kan den fulde implementering findes på Github.