
Tere, Habr.
Selles artiklis tahan rÀÀkida oma kogemustest Ă”pik keskkonna loomisel mikroteenuste jaoks eksperimenteerimiseks. Iga uue tööriista uurimisel on mul alati olnud soov proovida seda mitte ainult kohalikul masinal, vaid ka realistlikumates tingimustes. SeetĂ”ttu otsustasin luua lihtsustatud mikroteenuste rakenduse, mida oleks hiljem vĂ”imalik "varustada" mitmesuguste huvitavate tehnoloogiate abil. Peamine nĂ”ue projektile on selle maksimaalne funktsionaalne sarnasus reaalsĂŒsteemiga.
Alguses jagasin projekti loomise mitmeks sammuks:
Loo kaks teenust â âbackendâ ja âgatewayâ, pakendi need docker-piltidesse ja seadista nende koostöö.
Kasutatud mÀrksÔnad: Java 11, Spring Boot, Docker, pildieditamise optimeerimine.
Kasutatud mÀrksÔnad: Kubernetes, GKE, ressursside haldamine, automaatne skaleerimine, saladused.
Helm 3 abil chart'i loomine klastrihalduse tÔhustamiseks.
Kasutatud mÀrksÔnad: Helm 3, chart'i paigaldamine.
Jenkins'i ja töövoo seadistamine koodi automaatseks kohaletoimetamiseks klastrisse.
Kasutatud mÀrksÔnad: Jenkins'i konfiguratsioon, pistikprogrammide seadistamine, eraldi konfiguratsioonide hoidla.
Iga sammu jaoks plaanin kirjutada eraldi artikli.
Selle artiklite seeria fookus pole mitte selles, kuidas mikroteenuseid kirjutada, vaid kuidas neid tĂ”husalt töötama panna ĂŒhes sĂŒsteemis. Kuigi need teemad jÀÀvad sageli arendaja vastutusalast vĂ€lja, arvan, et on ikkagi kasulik neist vĂ€hemalt 20% ulatuses teada (mille kohta on teada, et see annab 80% tulemusest). MĂ”ned kindlasti olulised teemad, nagu kĂŒberturvalisus, jÀÀvad selle projekti raames kĂ”rvale, kuna autor ei mĂ”ista seda valdkonda piisavalt. SĂŒsteem luuakse rangelt isiklikuks kasutamiseks. Ootan kĂ”iki arvamusi ja konstruktiivset kriitikat.
Mikroteenuste loomine
Teenused on kirjutatud Java 11 kasutades Spring Booti. Teenustevaheline suhtlus on korraldatud RESTi abil. Projekt sisaldab minimaalset arvu teste (et hiljem oleks, mida Jenkinsis testida). Teenuste lÀhtekood on saadaval GitHubis: ja .
Kuna iga teenuse olekut kontrollida, on nende sĂ”ltuvusse lisatud Spring Actuator. See loob lĂ”pp-punkti /actuator/health ja tagastab 200 staatuse, kui teenus on liikluse vastuvĂ”tmiseks valmis, vĂ”i 504 probleemide korral. Sel juhul on see pigem nĂ€iline kontroll, kuna teenused on vĂ€ga lihtsad, ja mingisuguse erakorralise olukorra korral muutuvad nad tĂ”enĂ€oliselt tĂ€ielikult kĂ€ttesaamatuks, mitte ei jÀÀ osaliselt funktsioneerima. Kuid reaalsetes sĂŒsteemides vĂ”ib Actuator aidata probleemide diagnoosimisel enne, kui kasutajad hakkavad neid lahendama. NĂ€iteks, kui esinevad probleemid andmebaasi juurdepÀÀsuga, saame automaatselt sellele reageerida, lĂ”petades katkise teenuse abil pĂ€ringute töötlemise.
Tagasi side teenus
Tagasi side teenus loendab lihtsalt ja edastab vastu vÔetud pÀringute arvu.
Kontrolleri kood:
@RestController
public class RequestsCounterController {
private final AtomicLong counter = new AtomicLong();
@GetMapping("/requests")
public Long getRequestsCount() {
return counter.incrementAndGet();
}
}Kontrolleri test:
@WebMvcTest(RequestsCounterController.class)
public class RequestsCounterControllerTests {
@Autowired
private MockMvc mockMvc;
@Test
public void firstRequest_one() throws Exception {
mockMvc.perform(get("/requests"))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content().string("1"));
}
}Gateway teenus
Ć luzi suunab pĂ€ringu tagakĂŒljeteenusele, lisades sellele jĂ€rgmise teabe:
- ĆĄluzi id. See on vajalik, et serveri vastusest eristada ĂŒhte ĆĄluzi teisest
- Teatud "saladus", mis toimib vÀga olulise paroolina (ƥifreerimise vÔtme nr cookies)
Seadistus failis application.properties:
backend.url=http://localhost:8081
instance.id=${random.int}
secret="default-secret"Adapter tagakĂŒljega suhtlemiseks:
@Service
public class BackendAdapter {
private static final String REQUESTS_ENDPOINT = "/requests";
private final RestTemplate restTemplate;
@Value("${backend.url}")
private String backendUrl;
public BackendAdapter(RestTemplateBuilder builder) {
restTemplate = builder.build();
}
public String getRequests() {
ResponseEntity response = restTemplate.getForEntity(
backendUrl + REQUESTS_ENDPOINT, String.class);
return response.getBody();
}
}Kontrollija:
@RestController
@RequiredArgsConstructor
public class EndpointController {
private final BackendAdapter backendAdapter;
@Value("${instance.id}")
private int instanceId;
@Value("${secret}")
private String secret;
@GetMapping("/")
public String getRequestsCount() {
return String.format("Number of requests %s (gateway %d, secret %s)", backendAdapter.getRequests(), instanceId, secret);
}
}KĂ€ivitamine:
KĂ€ivitame backend:
./mvnw package -DskipTests
java -Dserver.port=8081 -jar target/microservices-backend-1.0.0.jarKĂ€ivitame gateway:
./mvnw package -DskipTests
java -jar target/microservices-gateway-1.0.0.jarKontrollin:
$ curl http://localhost:8080/
Number of requests 1 (gateway 38560358, secret "default-secret")KĂ”ik töötab. TĂ€helepanelik lugeja mĂ€rkab, et meid ei takista midagi backend'i otse kĂŒlastada, ĂŒmbersĂ”itmise kĂ€igus gateway'st (). Selle parandamiseks peaksid teenused olema ĂŒhendatud ĂŒhte vĂ”rgusse ning vĂ€lispidiselt peaks "kuni" olema vaid gateway.
Samuti jagab mĂ”lemad teenused ĂŒhte failisĂŒsteemi, genereerivad vooge ja vĂ”ivad ĂŒhel hetkel hakata ĂŒksteist segama. Oleks hea isoleerida meie mikroteenused. Selleks vĂ”ib rakendusi jagada erinevatele masinatele (palju raha, keeruline), kasutada virtuaalmasinaid (ressursimahukas, pikk kĂ€ivitamine) vĂ”i kasutada konteineriseerimist. Oodatult valime kolmanda variandi ja konteineriseerimise tööriistana.
Docker
LĂŒhidalt öeldes loob Docker isoleeritud konteinerid, igaĂŒhe oma rakenduse jaoks. Dockerit kasutamiseks tuleb kirjutada Dockerfile â juhend rakenduse kokkupanekuks ja kĂ€ivitamiseks. SeejĂ€rel saab luua pildi ja laadida selle pildiregistrisse (â ) ning ĂŒhe kĂ€suga kĂ€ivitada oma mikroteenuse igas Dockeriga varustatud keskkonnas.
Dockerfile
Ăks olulisemaid pildi omadusi on selle suurus. Kompaktne pilt laaditakse eemalt kiiremini alla, vĂ”tab vĂ€hem ruumi ja teie teenus kĂ€ivitub kiiremini. Iga pilt ehitatakse aluspildi pĂ”hjal ja soovitatav on valida vĂ”imalikult minimalistlik variant. Heaks valikuks on Alpine â tĂ€ielik Linuxi distributsioon miinimumpakettidega.
Katsume alguses kirjutada Dockerfile "puhtalt" (ĂŒtlen kohe, et see on halb viis, Ă€rge tehke nii):
FROM adoptopenjdk/openjdk11:jdk-11.0.5_10-alpine
ADD . /src
WORKDIR /src
RUN ./mvnw package -DskipTests
EXPOSE 8080
ENTRYPOINT ["java","-jar","target/microservices-gateway-1.0.0.jar"]Siin me kasutame Alpine'i pÔhjalikku pilti, millel on juba JDK installitud meie projekti koostamiseks. ADD kÀskliselt lisame pildi praeguse katalooge src, mÀÀrame selle töökaustaks (WORKDIR) ja kÀivitame koostamise. EXPOSE 8080 kÀsk annab Dockerile mÀrku, et konteineri rakendus kasutab porti 8080 (see ei tee rakendust vÀlistele juurdepÀÀsetavaks, kuid vÔimaldab nÀiteks teise konteineri sees samas Docker-vÔrgus rakendust vÀlja kutsuda).
Teenuste pakkimiseks piltidesse tuleb tÀita kÀsud iga projekti juurest:
docker image build . -t msvc-backend:1.0.0Selle tulemusena saame pildi, mille suurus on 456 MB (millest pÔhjalik pilt JDK 340 vÔttis MB). Ja see kÔik just seetÔttu, et meie projektis on klasse, mis vÔib sÔrmedega kokku lugeda. Pildi suuruse vÀhendamiseks:
- Kasutame mitmeastmelist koostamist. Esimeses etapis koostame projekti, teises etapis installime JRE ja kolmandas etapis kopeerime kÔik uude puhtasse Alpine'i pilti. LÔpuks jÀÀvad pildile vaid vajalikud komponendid.
- Kasutame Java modulariseerimist. Alates Java 9-st on vÔimalik jlink tööriistaga luua JRE ainult vajalikest moodulitest.
Uudishimu jaoks, siin on hea artikkel piltide suuruse vÀhendamise lÀhenemistest .
LÔplik Dockerfile:
FROM adoptopenjdk/openjdk11:jdk-11.0.5_10-alpine as builder
ADD . /src
WORKDIR /src
RUN ./mvnw package -DskipTests
FROM alpine:3.10.3 as packager
RUN apk --no-cache add openjdk11-jdk openjdk11-jmods
ENV JAVA_MINIMAL="/opt/java-minimal"
RUN /usr/lib/jvm/java-11-openjdk/bin/jlink
--verbose
--add-modules
java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument
--compress 2 --strip-debug --no-header-files --no-man-pages
--release-info="add:IMPLEMENTOR=radistao:IMPLEMENTOR_VERSION=radistao_JRE"
--output "$JAVA_MINIMAL"
FROM alpine:3.10.3
LABEL maintainer="Anton Shelenkov anshelen@yandex.ru"
ENV JAVA_HOME=/opt/java-minimal
ENV PATH="$PATH:$JAVA_HOME/bin"
COPY --from=packager "$JAVA_HOME" "$JAVA_HOME"
COPY --from=builder /src/target/microservices-backend-*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]Uuendame pildi ja selle suurus vĂ€henes 6 korda, olles 77 MB. Mitte paha. Valmis pildid saab seejĂ€rel ĂŒles laadida piltide registrisse, et need oleksid internetist allalaadimiseks saadaval.
Teenuste ĂŒhis запŃŃĐșа Dockeris
Esiteks peavad meie teenused olema ĂŒhes vĂ”rgus. Dockeris on mitu tĂŒĂŒpi vĂ”rke ja kasutame nende seas kĂ”ige lihtsamat â bridge, mis vĂ”imaldab ĂŒhendatud konteineritel töötada ĂŒhel puhul. Loome vĂ”rgu jĂ€rgmise kĂ€suga:
docker network create msvc-networkJĂ€rgmise sammuna kĂ€ivitame backend konteineri nimega âbackendâ kujutisega microservices-backend:1.0.0:
docker run -dit --name backend --network msvc-net microservices-backend:1.0.0Tasub mÀrkida, et bridge-vÔrk pakub konteinerite nimede pÔhjal teenuste avastamist otse vÀlja. See tÀhendab, et backend teenus on dokkeri vÔrgus kergesti ligipÀÀsetav aadressil .
KĂ€ivitame gateway:
docker run -dit -p 80:8080 --env secret=my-real-secret --env BACKEND_URL=http://backend:8080/ --name gateway --network msvc-net microservices-gateway:1.0.0Selles kĂ€sus mÀÀratleme, et suuname meie hosti 80. pordi 8080. konteineri pordile. Env valikud kasutame keskkonnaparameetrite mÀÀramiseks, mis springi poolt automaatselt loetakse ja ĂŒletavad application.properties omadusi.
PÀrast kÀivitamist kutsume vÀlja ja veendume, et kÔik töötab nagu eelmisel korral.
KokkuvÔte
KokkuvĂ”ttes oleme loonud kaks lihtsat mikroteenust, pakkinud need dockeri konteineritesse ja kĂ€ivitanud need ĂŒhel masinal. Saadud sĂŒsteemil on siiski mitmeid puudusi:
- Halb talitlushĂ€ire taluvus - kĂ”ik töötab ĂŒhel serveril
- Halb skaleeritavus - koormuse suurenedes oleks hea automaatselt juurutada lisaseenteenuseid ja tasakaalustada nende vahel koormust.
- KĂ€ivitamise keerukus â meie jaoks oli vajalik sisestada vĂ€hemalt 3 kĂ€sku, sealhulgas teatud parameetritega (see kehtib ainult 2 teenuse kohta)
Selleks, et lahendada ĂŒlalnimetatud probleeme, on olemas mitmeid lahendusi, nagu Docker Swarm, Nomad, Kubernetes vĂ”i OpenShift. Kui kogu sĂŒsteem on kirjutatud Java-s, vĂ”iks vaadata ka Spring Cloudi poole ().
V ma rÀÀgin sellest, kuidas ma seadistasin Kubernetes't ja deployisin projekti Google Kubernetes Engine'is.
Allikas: habr.com
