En introduksjon til Kong

1. Introduksjon

Kong er en åpen kildekode API-gateway og mikrotjenestelag.

Basert på Nginx og lua-nginx-modulen (spesielt OpenResty), gjør Kongs pluggbare arkitektur den fleksibel og kraftig.

2. Nøkkelbegreper

Før vi dykker ned i kodeeksempler, la oss ta en titt på nøkkelbegrepene i Kong:

  • API-objekt - bryter inn egenskapene til ethvert HTTP (s) endepunkt som utfører en bestemt oppgave eller leverer noen tjenester. Konfigurasjoner inkluderer HTTP-metoder, sluttpunkts-URIer, oppstrøms URL som peker til API-serverne våre og vil bli brukt til proxy-forespørsler, maksimale pensjoner, hastighetsgrenser, tidsavbrudd, etc.
  • Forbrukerobjekt - pakker inn egenskapene til alle som bruker API-endepunktene våre. Den vil bli brukt til sporing, tilgangskontroll og mer
  • Oppstrøms objekt - beskriver hvordan innkommende forespørsler vil sendes eller belastes balansert, representert av et virtuelt vertsnavn
  • Målobjekt - representerer tjenestene er implementert og servert, identifisert av et vertsnavn (eller en IP-adresse) og en port. Merk at mål for hver oppstrøms bare kan legges til eller deaktiveres. En historie med målendringer opprettholdes av oppstrøms
  • Plugin-objekt - pluggbare funksjoner for å berike funksjonaliteten til applikasjonen vår under forespørsel og respons livssyklus. For eksempel kan API-autentisering og hastighetsbegrensende funksjoner legges til ved å aktivere relevante plugins. Kong tilbyr veldig kraftige plugins i plugins-galleriet
  • Admin API - RESTful API-endepunkter som brukes til å administrere Kong-konfigurasjoner, sluttpunkter, forbrukere, plugins og så videre

Bildet nedenfor viser hvordan Kong skiller seg fra en eldre arkitektur, noe som kan hjelpe oss å forstå hvorfor den introduserte disse konseptene:

(kilde: //getkong.org/)

3. Oppsett

Den offisielle dokumentasjonen gir detaljerte instruksjoner for forskjellige miljøer.

4. API-styring

Etter å ha konfigurert Kong lokalt, la oss ta en bit av Kongs kraftige funksjoner ved å fullføre vårt enkle sluttspørsmål:

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

4.1. Legge til en API

La oss deretter legge til vår API for søk i Kong.

Administrator-API-ene er tilgjengelig via // lokal vert: 8001, så alle våre API-administrasjonsoperasjoner vil bli gjort 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 la vi til en API med følgende konfigurasjon:

{"name": "stock-api", "hosts": "stock.api", "upstream_url": "// localhost: 8080", "uris": "/"}
  • "Navn" er en identifikator for API, som brukes når du manipulerer oppførselen
  • “Verter” vil bli brukt til å rute innkommende forespørsler til gitt “Oppstrøms_url” ved å matche "Vert" Overskrift
  • Relative stier vil bli matchet med den konfigurerte “uris”

Hvis vi ønsker å avvikle et API eller konfigurasjonen er feil, kan vi bare fjerne den:

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

Etter at APIer er lagt til, vil de være tilgjengelige for forbruk gjennom // lokal vert: 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 kodeeksemplet ovenfor prøver vi å spørre aksjekursen via API-en vi nettopp har lagt til Kong.

Ved å be om // localhost: 8000 / lager / btc, får vi den samme tjenesten som å spørre direkte fra // localhost: 8080 / lager / btc.

4.2. Legge til en API-forbruker

La oss nå snakke om sikkerhet - mer spesifikt autentisering for brukerne som får tilgang til API-en vår.

La oss legge til en forbruker i aksjespørrings-API-et vårt, slik at vi kan aktivere godkjenningsfunksjonen senere.

Å legge til en forbruker for en API er like enkelt som å legge til en API. Forbrukerens navn (eller id) er det eneste obligatoriske feltet for alle forbrukerens egenskaper:

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

Her la vi til "eugenp" som en ny forbruker:

{"brukernavn": "eugenp"}

4.3. Aktiverer autentisering

Her kommer den kraftigste funksjonen i Kong, plugins.

Nå skal vi bruke et autent-plugin til vårt nærliggende aksjespørrings-API:

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

Hvis vi prøver å spørre en aksjekurs gjennom proxy-URI, vil forespørselen bli avvist:

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

Husk at Eugen er en av våre API-forbrukere, så vi bør tillate ham å bruke denne API-en ved å legge til en autentiseringsnøkkel:

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

Deretter Eugen kan bruke denne APIen 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. Avanserte funksjoner

Bortsett fra grunnleggende API-proxy og administrasjon, støtter Kong også API-balansering, klynging, helsekontroll og overvåking etc.

I denne delen skal vi ta en titt på hvordan du kan laste inn balanseforespørsler med Kong, og hvordan du sikrer admin-APIer.

5.1. Lastbalansering

Kong tilbyr to strategier for belastningsbalanseringsforespørsler om backend-tjenester: en dynamisk ringbalanser, og en enkel DNS-basert metode. For enkelhets skyld, vi bruker ringbalanseren.

Som vi nevnte tidligere, brukes oppstrøms for balansering av belastning, og hver oppstrøms kan ha flere mål.

Kong støtter både vektede rund-robin og hasj-baserte balanseringsalgoritmer. Som standard brukes den vektede rund-robin-ordningen - der forespørsler leveres til hvert mål i henhold til vekten.

La oss først forberede oppstrøms:

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

Deretter legger du til to mål for oppstrøms, en testversjon med vekt = 10, og en utgivelsesversjon med vekt = 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 = new 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 konfigurasjonen ovenfor kan vi anta at 1/5 av forespørslene vil gå til testversjon og 4/5 vil gå til utgivelsesversjon:

APIObject stockAPI = ny APIObject ("balansert-lager-api", "balansert.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 ("Vert", "balansert.stock.api"); for (int i = 0; i <1000; i ++) {RequestEntity requestEntity = new RequestEntity (headers, HttpMethod.GET, new 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);

Vær oppmerksom på at vektet rund-robin-ordning balanserer forespørsler om å støtte tjenester omtrent til vektforholdet, så bare en tilnærming av forholdet kan verifiseres, reflektert i den siste linjen i ovennevnte kode.

5.2. Sikring av Admin API

Som standard godtar Kong bare administratorforespørsler fra det lokale grensesnittet, noe som i de fleste tilfeller er en god nok begrensning. Men hvis vi vil administrere det via andre nettverksgrensesnitt, kan vi endre admin_listen verdi i kong.conf, og konfigurer brannmurregler.

Eller vi kan få Kong til å fungere som en proxy for selve Admin API. Si at vi vil administrere APIer med banen “/ admin-api”, vi kan legge til en API som dette:

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

Nå kan vi bruke proxy admin admin til å administrere APIer:

HttpHeaders headers = nye HttpHeaders (); headers.set ("Vert", "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 ());

Sikkert, vi vil ha den nærliggende API-en sikret. Dette kan enkelt oppnås ved å aktivere godkjenningsplugin for proxy admin API.

6. Sammendrag

I denne artikkelen introduserte vi Kong - en plattform for microservice API gateway og fokusert på kjernefunksjonaliteten - administrering av API-er og ruteforespørsler til oppstrøms-servere, samt på noen mer avanserte funksjoner som lastbalansering.

Likevel er det mange flere solide funksjoner for oss å utforske, og vi kan utvikle våre egne plugins hvis vi trenger det - du kan fortsette å utforske den offisielle dokumentasjonen her.

Som alltid kan den fullstendige implementeringen finnes på Github.