Õpime mikroteenuseid juurutama. Osa 1. Spring Boot ja Docker

Õpime mikroteenuseid juurutama. Osa 1. Spring Boot ja Docker

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:

  1. 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.

  2. Kubernetes konfiguratsiooni arendamine ja sĂŒsteemi paigaldamine Google Kubernetes Engine'i.

    Kasutatud mÀrksÔnad: Kubernetes, GKE, ressursside haldamine, automaatne skaleerimine, saladused.

  3. Helm 3 abil chart'i loomine klastrihalduse tÔhustamiseks.

    Kasutatud mÀrksÔnad: Helm 3, chart'i paigaldamine.

  4. 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: tagakĂŒlg ja lĂŒnk.

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.jar

KĂ€ivitame gateway:

./mvnw package -DskipTests
java -jar target/microservices-gateway-1.0.0.jar

Kontrollin:

$ 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 (http://localhost:8081/requests). 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 Docker 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 (№ DockerHub) 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.0

Selle 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 https://habr.com/ru/company/ruvds/blog/485650/.

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-network

JĂ€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.0

Tasub 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 http://backend:8080.

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.0

Selles 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 http://localhost/ 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 (hea artikkel).

V jÀrgmises osas ma rÀÀgin sellest, kuidas ma seadistasin Kubernetes't ja deployisin projekti Google Kubernetes Engine'is.

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster