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.