Uvod u Kong

1. Uvod

Kong je API pristupnik otvorenog koda i sloj upravljanja mikroservisima.

Zasnovana na Nginxu i lua-nginx modulu (posebno OpenResty), Kongova priključna arhitektura čini ga fleksibilnim i moćnim.

2. Ključni pojmovi

Prije nego što uđemo u uzorke koda, pogledajmo ključne koncepte u Kongu:

  • API objekt - obavija svojstva bilo koje HTTP (s) krajnje točke koja izvršava određeni zadatak ili pruža neku uslugu. Konfiguracije uključuju HTTP metode, URI krajnje točke, URL uzlazne struje koji upućuje na naše API poslužitelje i koristit će se za zahtjeve za proksiranje, maksimalno povlačenje, ograničenja brzine, vremenska ograničenja itd.
  • Potrošački objekt - obavija svojstva bilo koga tko koristi naše krajnje točke API-ja. Koristit će se za praćenje, kontrolu pristupa i još mnogo toga
  • Uzvodni objekt - opisuje kako će se dolazni zahtjevi proksirati ili uravnotežiti opterećenje, predstavljeno virtualnim imenom hosta
  • Ciljani objekt - predstavlja da su usluge implementirane i uslužene, identificirane imenom hosta (ili IP adresom) i portom. Imajte na umu da se ciljevi svakog uzvodno mogu dodavati ili onemogućavati. Uzvodno održava povijest ciljanih promjena
  • Objekt dodatka - priključne značajke za obogaćivanje funkcionalnosti naše aplikacije tijekom životnog ciklusa zahtjeva i odgovora. Na primjer, API autentifikacija i značajke ograničavanja brzine mogu se dodati omogućavanjem relevantnih dodataka. Kong nudi vrlo moćne dodatke u svojoj galeriji dodataka
  • Admin API - RESTful API krajnje točke koje se koriste za upravljanje Kong konfiguracijama, krajnjim točkama, potrošačima, dodacima itd

Slika ispod prikazuje kako se Kong razlikuje od naslijeđene arhitekture, što bi nam moglo pomoći da shvatimo zašto je uveo ove koncepte:

(izvor: //getkong.org/)

3. Postavljanje

Službena dokumentacija sadrži detaljne upute za različita okruženja.

4. API upravljanje

Nakon lokalnog postavljanja Konga, zagrizimo Kong-ove moćne značajke proksiranjem naše jednostavne krajnje točke upita o dionicama:

@RestController @RequestMapping ("/ stock") javna klasa QueryController {@GetMapping ("/ {code}") javni String getStockPrice (@PathVariable String code) {return "BTC" .equalsIgnoreCase (code)? "10000": "0"; }}

4.1. Dodavanje API-ja

Dalje, dodajmo naš API za upite u Kong.

Administratorskim API-ima je dostupan putem // localhost: 8001, tako da će se sve naše operacije upravljanja API-jem obavljati s ovim osnovnim URI-jem:

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

Ovdje smo dodali API sa sljedećom konfiguracijom:

{"name": "stock-api", "hosts": "stock.api", "upstream_url": "// localhost: 8080", "uris": "/"}
  • "Ime" je identifikator za API, koji se koristi pri manipulaciji njegovim ponašanjem
  • "Domaćini" koristit će se za usmjeravanje dolaznih zahtjeva na zadane "Uzvodni_url" podudaranjem "Domaćin" Zaglavlje
  • Relativni se putovi podudaraju s konfiguriranim "urisom"

U slučaju da želimo obustaviti API ili je konfiguracija pogrešna, možemo ga jednostavno ukloniti:

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

Nakon dodavanja API-ja, oni će biti dostupni za upotrebu putem // localhost: 8000:

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

U gornjem uzorku koda pokušavamo ispitati cijenu dionica putem API-ja koji smo upravo dodali u Kong.

Zahtjevom // localhost: 8000 / dionica / btc, dobivamo istu uslugu kao i izravno slanje upita // localhost: 8080 / stock / btc.

4.2. Dodavanje API potrošača

Razgovarajmo sada o sigurnosti - točnije provjeri autentičnosti za korisnike koji pristupaju našem API-ju.

Dodajmo potrošača našem API-ju upita za dionice kako bismo kasnije mogli omogućiti značajku provjere autentičnosti.

Dodavanje potrošača za API jednako je jednostavno kao i dodavanje API-ja. Potrošačevo ime (ili id) jedino je obavezno polje svih svojstava potrošača:

ConsumerObject potrošač = novi ConsumerObject ("eugenp"); HttpEntity addConsumerEntity = novi HttpEntity (potrošač); ResponseEntity addConsumerResp = restTemplate.postForEntity ("// localhost: 8001 / potrošači /", addConsumerEntity, String.class); assertEquals (HttpStatus.CREATED, addConsumerResp.getStatusCode ());

Ovdje smo dodali "eugenp" kao novog potrošača:

{"korisničko ime": "eugenp"}

4.3. Omogućavanje provjere autentičnosti

Evo najsnažnije značajke Konga, dodataka.

Sada ćemo primijeniti autorski dodatak na naš proxy API za upite dionica:

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

Ako pokušamo ispitati cijenu dionice putem proxy URI-ja, zahtjev će biti odbijen:

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

Zapamti to Eugen jedan je od naših API potrošača, pa bismo mu trebali dopustiti da koristi ovaj API dodavanjem ključa za provjeru autentičnosti:

String consumerKey = "eugenp.pass"; KeyAuthObject keyAuth = novi KeyAuthObject (potrošački ključ); ResponseEntity keyAuthResp = restTemplate.postForEntity ("// localhost: 8001 / consumer / eugenp / key-auth", novi HttpEntity (keyAuth), String.class); assertTrue (HttpStatus.CREATED == keyAuthResp.getStatusCode ());

Zatim Eugen može koristiti ovaj API kao i prije:

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

5. Napredne značajke

Osim osnovnog API proxyja i upravljanja, Kong također podržava API uravnoteženje opterećenja, klasteriranje, provjeru stanja i nadzor, itd.

U ovom ćemo odjeljku pogledati kako učitati zahtjeve za saldo s Kongom i kako osigurati API-je za administratore.

5.1. Uravnoteženje opterećenja

Kong pruža dvije strategije zahtjeva za uravnoteženjem opterećenja za pozadinske usluge: dinamički balansiranje prstena i jednostavna metoda temeljena na DNS-u. Zbog jednostavnosti, koristit ćemo prsten-balanser.

Kao što smo ranije spomenuli, uzvodni tokovi se koriste za uravnoteženje opterećenja, a svaki uzvodni može imati više ciljeva.

Kong podržava algoritme za uravnoteženje s ponderiranim krugovima i algoritme zasnovan na raspršivanju. Prema zadanim postavkama koristi se shema ponderiranog kruga - gdje se zahtjevi dostavljaju svakoj meti u skladu s njihovom težinom.

Prvo, pripremimo uzvodno:

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

Zatim dodajte dva cilja za uzvodno, test verziju s težina = 10i izdanje s težina = 40:

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

S gornjom konfiguracijom možemo pretpostaviti da će 1/5 zahtjeva ići na testnu verziju, a 4/5 na verziju izdanja:

APIObject stockAPI = novi APIObject ("uravnoteženi-zaliha-api", "uravnoteženi.stock.api", "//stock.api.service", "/"); HttpEntity apiEntity = novi HttpEntity (stockAPI); ResponseEntity addAPIResp = restTemplate.postForEntity ("// localhost: 8001 / apis", apiEntity, String.class); assertEquals (HttpStatus.CREATED, addAPIResp.getStatusCode ()); HttpHeaders zaglavlja = novi HttpHeaders (); headers.set ("Host", "uravnoteženi.stock.api"); za (int i = 0; i <1000; i ++) {RequestEntity requestEntity = novi RequestEntity (zaglavlja, HttpMethod.GET, novi 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);

Imajte na umu da shema ponderiranog kruga balansira zahtjeve za pozadinske usluge približno omjeru težine, tako da se može provjeriti samo približna vrijednost omjera, što se odražava u zadnjem retku gornjeg koda.

5.2. Osiguravanje administratorskog API-ja

Prema zadanim postavkama Kong prihvaća samo administrativne zahtjeve s lokalnog sučelja, što je u većini slučajeva dovoljno dobro ograničenje. Ali ako želimo upravljati njime putem drugih mrežnih sučelja, možemo promijeniti admin_listen vrijednost u kong.confi konfigurirajte pravila vatrozida.

Ili možemo natjerati Kong da služi kao proxy za sam Admin API. Recimo da želimo upravljati API-jevima s putanjom “/ admin-api”, možemo dodati API poput ovog:

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

Sada možemo koristiti proxy administratorski API za upravljanje API-jem:

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

Svakako, želimo osigurati proxy API. To se lako može postići omogućavanjem dodatka za provjeru autentičnosti za proxy administratorski API.

6. Sažetak

U ovom smo članku predstavili Kong - platformu za microservice API gateway i usredotočili se na njegovu osnovnu funkcionalnost - upravljanje API-jevima i zahtjevima za usmjeravanje na uzlazne poslužitelje, kao i na neke naprednije značajke poput uravnoteženja opterećenja.

Ipak, postoji mnogo solidnijih značajki koje možemo istražiti, a ako je potrebno, možemo razviti vlastite dodatke - ovdje možete nastaviti istraživati ​​službenu dokumentaciju.

Kao i uvijek, cjelovitu implementaciju možete pronaći na Githubu.