Fêr bibin ka meriv çawa mîkroservisan bi cih dike. Part 1. Spring Boot and Docker

Fêr bibin ka meriv çawa mîkroservisan bi cih dike. Part 1. Spring Boot and Docker

Hey Habr.

Di vê gotarê de, ez dixwazim li ser ezmûna xwe biaxivim ku hawîrdorek fêrbûnê ji bo ceribandina mîkroservisan diafirîne. Dema ku her amûrek nû fêr bûm, min her gav dixwest ku wê ne tenê li ser makîneya xweya herêmî, lê di heman demê de di şert û mercên rastîn de jî biceribînim. Ji ber vê yekê, min biryar da ku ez serîlêdanek mîkroxizmetek hêsan biafirînim, ku paşê dikare bi her cûre teknolojiyên balkêş ve were "daliqandin". Pêdiviya sereke ji bo projeyê nêzîkbûna fonksiyonê ya herî zêde ya pergala rastîn e.

Di destpêkê de, min çêkirina projeyê li çend gavan dabeş kir:

  1. Du karûbaran biafirînin - 'backend' û 'gateway', wan di nav wêneyên docker de pak bikin û wan mîheng bikin ku bi hev re bixebitin

    Peyvên sereke: Java 11, Spring Boot, Docker, xweşbîniya wêneyê

  2. Pêşxistina pergala vesazkirin û bicîhkirina Kubernetes di Google Kubernetes Engine

    Peyvên sereke: Kubernetes, GKE, rêveberiya çavkaniyê, otoscaling, veşartî

  3. Ji bo rêveberiya komê ya bikêrtir nexşeyek bi karanîna Helm 3 biafirînin

    Peyvên sereke: Helm 3, belavkirina nexşeyê

  4. Sazkirina Jenkins û boriyê da ku bixweber kodê bide komê

    Peyvên sereke: Veavakirina Jenkins, pêvek, depoya veavakirina veqetandî

Ez plan dikim ku ji her gavê re gotarek cuda veqetînim.

Mebesta vê rêze gotaran ne ew e ku meriv çawa karûbaran binivîsîne, lê meriv çawa wan di yek pergalê de bixebite. Dema ku van hemî tiştan bi gelemperî li derveyî berpirsiyariya pêşdebiran in, ez difikirim ku hîn jî kêrhatî ye ku bi kêmî ve 20% bi wan re were nas kirin (ya ku tê zanîn ku ji% 80-ê encamê hesab dike). Hin mijarên bêkêmasî yên girîng, wek ewlehî, dê li derveyî vê projeyê bimînin, ji ber ku nivîskar ji vê yekê hindik fam dike; pergal bi taybetî ji bo karanîna kesane tê afirandin. Ez pêşwaziya her nêrîn û rexneyên çêker dikim.

Çêkirina microservices

Karûbar di Java 11 de bi karanîna Spring Boot hatine nivîsandin. Têkiliya nav-karûbar bi karanîna REST tê organîze kirin. Proje dê hejmareke hindiktirîn ceribandinan bigire (da ku paşê dê li Jenkins tiştek ceribandinê hebe). Koda çavkaniyê ji bo karûbaran li ser GitHub heye: paşvekêşana и Derî.

Ji bo ku hûn karibin rewşa her yek ji karûbaran kontrol bikin, Actuatorek Spring Spring li girêdayîbûna wan hate zêdekirin. Ew ê xalek dawîn / çalakvan / tenduristî biafirîne û heke karûbar amade be ku seyrûseferê qebûl bike, an jî 200 di bûyera pirsgirêkan de dê statûyek 504 vegerîne. Di vê rewşê de, ev kontrolek berbiçav e, ji ber ku karûbar pir hêsan in, û di bin cûreyek hêzek major de ew îhtîmal e ku ew bi tevahî nederbasdar bibin ji ya ku bi qismî xebitîn bimînin. Lê di pergalên rastîn de, Actuator dikare berî ku bikarhêner dest bi lêdana wê bikin pirsgirêkek tespît bikin. Mînakî, heke di gihîştina databasê de pirsgirêk derkevin, em ê karibin bixweber bersivê bidin vê yekê bi rawestandina daxwazên pêvajoyê yên bi mînakek şikestî ya karûbarê re.

xizmeta Backend

Karûbarê paşîn dê tenê hejmara daxwazên pejirandî bijmêre û vegerîne.

Koda kontrolker:

@RestController
public class RequestsCounterController {

    private final AtomicLong counter = new AtomicLong();

    @GetMapping("/requests")
    public Long getRequestsCount() {
        return counter.incrementAndGet();
    }
}

Testa kontrolker:

@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"));
    }
}

xizmeta Gateway

Dergeh dê daxwazê ​​ji karûbarê paşverû re bişîne, wê bi agahdariya jêrîn temam bike:

  • id dergehê. Pêdivî ye ku yek mînakek dergehê ji hêla bersiva serverê ve ji ya din were veqetandin
  • Hin "veşartî" ku dê rola şîfreyek pir girîng bilîze (hejmara sereke ji bo şîfrekirina cookieyek girîng)

Veavakirin di application.properties:

backend.url=http://localhost:8081
instance.id=${random.int}
secret="default-secret"

Adapter ji bo danûstendina bi paşnavê re:

@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<String> response = restTemplate.getForEntity(
backendUrl + REQUESTS_ENDPOINT, String.class);
        return response.getBody();
    }
}

Kontrolker:

@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);
    }
}

Destpêkirin:

Ka em paşîn dest pê bikin:

./mvnw package -DskipTests
java -Dserver.port=8081 -jar target/microservices-backend-1.0.0.jar

Ka em derî dest pê bikin:

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

Em kontrol dikin:

$ curl http://localhost:8080/
Number of requests 1 (gateway 38560358, secret "default-secret")

Her tişt dixebite. Xwendevanê baldar dê bala xwe bide ku tiştek me nahêle ku em rasterast bigihîjin paşnavê, ji dergehê derbas bibin (http://localhost:8081/requests). Ji bo rastkirina vê yekê, pêdivî ye ku karûbar di yek torê de bêne hev kirin, û tenê dergeh divê li derve "derkeve".
Di heman demê de, her du karûbar heman pergala pelê parve dikin, têlan çêdikin, û di yek xalê de dikarin dest bi destwerdana hevdu bikin. Dê xweş be ku em mîkroxizmetên xwe veqetînin. Ev dikare bi belavkirina serîlêdanan li ser makîneyên cihêreng (gelek drav, dijwar), bi karanîna makîneyên virtual (çavkaniyek zirav, destpêkirina dirêj) an bi karanîna konteynir ve were bidestxistin. Wekî ku tê hêvî kirin, em vebijarka sêyemîn hilbijêrin û Docker wekî amûrek ji bo konteynirkirinê.

Docker

Bi kurtasî, Docker konteynerên veqetandî, yek serîlêdanê diafirîne. Ji bo ku Docker bikar bînin, hûn hewce ne ku Dockerfile binivîsin - rêwerzên ji bo çêkirin û xebitandina serîlêdanê. Dûv re, hûn dikarin wêneyê ava bikin, wê li tomara wêneyê bar bikin (No. DockerHub) û di yek fermanê de mîkroxizmeta xwe li her hawîrdorek dockerkirî bicîh bikin.

dockerfile

Yek ji taybetmendiyên herî girîng ên wêneyê mezinahiya wê ye. Wêneyek kompakt dê ji depoyek dûr zûtir dakêşîne, cîhê kêmtir bigire, û karûbarê we dê zûtir dest pê bike. Her wêneyek li ser bingeha wêneyek bingehîn hatî çêkirin, û tê pêşniyar kirin ku vebijarka herî hindiktirîn hilbijêrin. Vebijêrkek baş Alpine ye, belavkirina Linux-ê ya bêkêmasî ya bi hindiktirîn pakêtan.

Pêşîn, em hewl bidin ku Dockerfile "bi serê xwe" binivîsin (ez ê tavilê bibêjim ku ev rêyek xirab e, wiya nekin):

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"]

Li vir em wêneyek bingehîn a Alpine bi JDK-ya ku jixwe hatî saz kirin bikar tînin da ku projeya xwe ava bikin. Bi karanîna fermana ADD-ê, em pelrêça src ya heyî li wêneyê zêde dikin, wê wekî kar (WORKDIR) nîşan bikin û dest bi çêkirinê dikin. Fermana EXPOSE 8080 ji dokerê re îşaret dike ku sepana di konteynerê de dê porta xwe 8080 bikar bîne (ev ê serîlêdanê ji derve ve negihîne, lê dê bihêle ku serîlêdan were gihîştin, mînakî, ji konteynirek din li ser heman tora dokerê ).

Ji bo pakêtkirina karûbaran di wêneyan de, hûn hewce ne ku emrên ji koka her projeyê bimeşînin:

docker image build . -t msvc-backend:1.0.0

Wekî encamek, em wêneyek mezinahiya 456 MB distînin (ya ku wêneya bingehîn JDK 340 MB girt). Û hemî tevî vê yekê ku dersên di projeya me de dikarin li ser yek tiliyek bêne jimartin. Ji bo kêmkirina mezinahiya wêneya me:

  • Em kombûna pir-gavekî bikar tînin. Di gava yekem de em ê projeyê bicivînin, di ya duyemîn de em ê JRE saz bikin, û di gava sêyemîn de em ê van hemîyan di wêneyek nû ya paqij a Alpine de kopî bikin. Bi tevahî, wêneya paşîn dê tenê hêmanên pêwîst hebe.
  • Ka em modularîzasyona java bikar bînin. Bi Java 9-ê dest pê dike, hûn dikarin amûra jlink bikar bînin da ku JRE-yek tenê ji modulên ku hûn hewce ne biafirînin

Ji bo meraqdaran, li vir gotarek baş li ser nêzîkatiyên kêmkirina mezinahiya wêneyê heye https://habr.com/ru/company/ruvds/blog/485650/.

Pelê Dockera Dawî:

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 [email protected]"
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"]

Me wêne ji nû ve afirand, û di dawiyê de 6 qat ziravtir bû, bi qasî 77 MB. Xerab nîne. Dûv re, wêneyên qedandî dikarin li qeyda wêneyê werin barkirin da ku wêneyên we ji bo dakêşana ji Înternetê peyda bibin.

Karûbarên bi hev re li Docker dimeşînin

Ji bo destpêkê, karûbarên me divê li ser heman torê bin. Di Docker de gelek celeb toran hene, û em ji wan ên herî bingehîn bikar tînin - pira, ku dihêle hûn konteynerên torê yên ku li ser heman mêvandar dixebitin. Ka em bi fermana jêrîn torgilokek biafirînin:

docker network create msvc-network

Dûv re, bila em konteynirek paşîn a bi navê 'backend' bi wêneya microservices-backend:1.0.0 vekin:

docker run -dit --name backend --network msvc-net microservices-backend:1.0.0

Hêjayî bibîrxistinê ye ku şebekeya pirê ji bo konteynerên bi navên wan vedîtina karûbarê ji qutiyê peyda dike. Ango, karûbarê paşerojê dê di nav tora Docker de peyda bibe http://backend:8080.

Ka em derî dest pê bikin:

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

Di vê fermanê de em destnîşan dikin ku em porta 80 ya mêvandarê xwe dişînin porta 8080 ya konteynerê. Em vebijarkên env bikar tînin da ku guhêrbarên jîngehê yên ku dê bixweber bi biharê ve werin xwendin û taybetmendiyên ji application.properties veqetînin bikar tînin.

Piştî destpêkirinê, telefon bikin http://localhost/ û piştrast bikin ku her tişt dixebite, wekî di doza berê de.

encamê

Wekî encamek, me du mîkroxizmetên hêsan afirandin, wan di konteynerên dokerê de pak kirin û wan bi hev re li ser heman makîneyê da destpêkirin. Lêbelê, pergala ku di encamê de pêk tê, çend kêmasiyên xwe hene:

  • Tolerasyona xeletiya xirab - her tişt ji bo me li ser yek serverê dixebite
  • Scalability xerab - her ku bar zêde dibe, dê xweş be ku bixweber karûbarên karûbarê zêde werin bicîh kirin û barkirinê di navbera wan de hevseng bikin
  • Tevliheviya destpêkirinê - hewce bû ku em bi kêmî ve 3 fermanan, bi hin parameteran re têkevin (ev tenê ji bo 2 karûbaran e)

Ji bo çareserkirina pirsgirêkên jorîn, hejmarek çareseriyên wekî Docker Swarm, Nomad, Kubernetes an OpenShift hene. Ger tevahiya pergalê bi Java-yê hatî nivîsandin, hûn dikarin berbi Spring Cloud (gotara baş).

В beşa din Ez ê ji we re vebêjim ka min çawa Kubernetes saz kir û proje li Google Kubernetes Engine bicîh kir.

Source: www.habr.com

Add a comment