Diajar kumaha nyebarkeun microservices. Bagian 1. Spring Boot jeung Docker

Diajar kumaha nyebarkeun microservices. Bagian 1. Spring Boot jeung Docker

Hejo Habr.

Dina tulisan ieu, kuring hoyong ngobrol ngeunaan pangalaman kuring dina nyiptakeun lingkungan diajar pikeun ékspérimén sareng microservices. Nalika kuring diajar unggal alat anyar, Kuring salawasna hayang nyobaan teu ukur dina mesin lokal, tapi ogé dina kaayaan leuwih realistis. Ku alatan éta, kuring mutuskeun pikeun nyieun hiji aplikasi microservice saderhana, nu engké bisa "katutupan" jeung sagala sorts téknologi metot. Sarat utama pikeun proyék nyaéta jarak fungsional anu maksimal sareng sistem nyata.

Mimitina, kuring ngarobih kreasi proyék kana sababaraha léngkah:

  1. Jieun dua jasa - 'backend' (backend) jeung 'gateway' (gateway), pak kana gambar docker tur nyetel eta nepi ka gawé bareng

    Konci: Java 11, Spring Boot, Docker, optimasi gambar

  2. Ngembangkeun konfigurasi Kubernetes sareng panyebaran sistem dina Google Kubernetes Engine

    Konci: Kubernetes, GKE, manajemén sumberdaya, autoscaling, rusiah

  3. Nyiptakeun bagan sareng Helm 3 pikeun manajemén kluster anu langkung saé

    Tag: Helm 3, panyebaran bagan

  4. Nyetel Jenkins na pipa pikeun pangiriman otomatis kode ka klaster

    Konci: Konfigurasi Jenkins, plugins, gudang configs misah

Kuring rencanana bakti hiji artikel misah pikeun tiap hambalan.

Fokus tina séri tulisan ieu sanés kumaha cara nyerat microservices, tapi kumaha carana ngajantenkeun aranjeunna tiasa dianggo dina sistem tunggal. Sanajan sagala hal ieu biasana di luar tanggung jawab pamekar, Jigana masih mangpaat pikeun akrab jeung aranjeunna sahanteuna 20% (anu, anjeun terang, masihan 80% hasilna). Sababaraha jejer penting tanpa sarat, kayaning kaamanan, bakal ditinggalkeun kaluar tina proyék ieu, saprak panulis understands saeutik ngeunaan sistem ieu dijieun solely pikeun pamakéan pribadi. Kuring ngabagéakeun sagala pendapat jeung kritik konstruktif.

Nyieun microservices

Ladenan ditulis dina Java 11 nganggo Spring Boot. Interaksi antarlayanan diatur nganggo REST. Proyék bakal kalebet sajumlah tés minimal (supaya engké aya anu diuji dina Jenkins). Kodeu sumber pikeun jasa sayogi dina GitHub: tonggong и Gerbang.

Pikeun tiasa mariksa status unggal jasa, Spring Actuator parantos ditambahkeun kana katergantunganna. Bakal nyieun hiji / actuator / titik kaséhatan sarta bakal balik a 200 status lamun jasa geus siap nampa lalulintas, atawa 504 lamun aya masalah. Dina hal ieu, ieu cek rada fiktif, saprak jasa pisan basajan, sarta dina kasus sababaraha force majeure, aranjeunna leuwih gampang jadi lengkep sadia ti tetep sawaréh operasional. Tapi dina sistem nyata, Actuator tiasa ngabantosan ngadiagnosa masalah sateuacan pangguna ngamimitian battling ngeunaan éta. Salaku conto, upami aya masalah dina ngaksés pangkalan data, urang tiasa ngabales sacara otomatis ku cara ngeureunkeun pamrosésan pamundut sareng conto jasa anu rusak.

Palayanan tukang

Ladenan backend ngan saukur bakal ngitung sareng ngabalikeun jumlah pamundut anu ditampi.

Kode controller:

@RestController
public class RequestsCounterController {

    private final AtomicLong counter = new AtomicLong();

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

Tes Controller:

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

Gerbang Palayanan

Gerbang bakal neraskeun pamundut ka jasa backend, nambihanana ku inpormasi ieu:

  • gateway id. Ieu diperlukeun ku kituna kasebut nyaéta dimungkinkeun pikeun ngabedakeun hiji conto tina gateway ti sejen ku respon server
  • Sababaraha "rusiah" anu bakal maénkeun peran kecap konci anu penting pisan (jumlah konci enkripsi cookie penting)

Konfigurasi dina application.properties:

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

Adaptor backend:

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

Controller:

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

peluncuran:

Urang ngamimitian backend:

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

Ngamimitian gateway:

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

Kami cek:

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

Sagalana jalan. Pamaca anu ati-ati bakal dicatet yén teu aya anu ngahalangan urang pikeun ngaksés backend sacara langsung, ngalangkungan gerbang (http://localhost:8081/requests). Pikeun ngalereskeun ieu, jasa kedah digabungkeun kana hiji jaringan, sareng ngan ukur gateway anu kedah "nempel" di luar.
Ogé, duanana jasa ngabagi hiji sistem file, ngahasilkeun aliran sareng dina hiji waktos tiasa ngawitan ngaganggu. Éta hadé pikeun ngasingkeun jasa mikro kami. Ieu bisa dihontal ku ngadistribusikaeun aplikasi dina mesin béda (loba duit, hese), ngagunakeun mesin virtual (sumberdaya intensif, lila ngamimitian), atawa ngagunakeun containerization. Saperti nu diharapkeun, urang milih pilihan katilu jeung Docker salaku alat pikeun containerization.

Docker

Pondokna, docker nyiptakeun peti terasing, hiji per aplikasi. Pikeun nganggo docker, anjeun kedah nyerat Dockerfile - petunjuk pikeun ngawangun sareng ngajalankeun aplikasi. Salajengna, anjeun tiasa ngawangun gambar, unggah kana pendaptaran gambar (No. Dockerhub) sareng nyebarkeun microservice anjeun dina lingkungan dockerized dina hiji paréntah.

dockerfile

Salah sahiji ciri anu paling penting dina gambar nyaéta ukuranana. Gambar anu kompak bakal diunduh langkung gancang tina gudang jauh, nyéépkeun rohangan anu sakedik, sareng jasa anjeun bakal ngamimitian langkung gancang. Sakur gambar diwangun dina dasar gambar dasar, sareng disarankeun pikeun milih pilihan anu paling minimalis. Pilihan anu saé nyaéta Alpine, distribusi Linux lengkep sareng pakét minimal.

Pikeun dimimitian ku, hayu urang coba nulis Dockerfile "dina dahi" (Kuring bakal langsung nyebutkeun yén ieu téh cara goréng, ulah ngalakukeun eta):

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

Di dieu kami nganggo gambar dasar Alpine sareng JDK parantos dipasang pikeun ngawangun proyék kami. Kalayan paréntah ADD, urang tambahkeun diréktori src ayeuna kana gambar, cirian éta damel (WORKDIR) sareng ngamimitian ngawangun. Paréntah EXPOSE 8080 sinyal ka docker yén aplikasi dina wadahna bakal nganggo port na 8080 (ieu moal ngajantenkeun aplikasi tiasa diaksés ti luar, tapi bakal ngamungkinkeun aplikasina diaksés, contona, tina wadah anu sanés dina jaringan docker anu sami. ).

Pikeun ngarangkep jasa kana gambar, anjeun kedah ngajalankeun paréntah tina akar unggal proyék:

docker image build . -t msvc-backend:1.0.0

Hasilna nyaéta gambar 456 MB (nu dasarna gambar JDK nempatan 340 MB). Sarta sakabeh sanajan kanyataan yén kelas dina proyék urang bisa diitung dina ramo. Pikeun ngurangan ukuran gambar urang:

  • Urang make assembly multi-hambalan. Dina lengkah kahiji urang bakal ngawangun proyék, dina lengkah kadua urang masang JRE, sarta dina hambalan katilu urang bakal nyalin sadayana kana gambar Alpine bersih anyar. Dina total, ngan komponén diperlukeun bakal dina gambar ahir.
  • Hayu urang nganggo modularisasi java. Dimimitian ku Java 9, anjeun tiasa nganggo alat jlink pikeun nyiptakeun JRE tina modul anu anjeun peryogikeun

Pikeun anu hoyong terang, ieu mangrupikeun tulisan anu saé ngeunaan pendekatan réduksi gambar. https://habr.com/ru/company/ruvds/blog/485650/.

Dockerfile ahir:

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

Urang nyieun deui gambar, sarta salaku hasilna, éta leungit 6 kali beurat na, jumlahna 77 MB. Lumayan. Saatos éta, gambar siap-siap tiasa diunggah ka pendaptaran gambar supados gambar anjeun tiasa diunduh tina Internét.

jasa co-ngajalankeun di Docker

Pikeun mimitian, jasa kami kedah aya dina jaringan anu sami. Aya sababaraha jenis jaringan dina docker, sarta kami nganggo paling primitif di antarana - sasak, nu ngidinan Anjeun pikeun wadah jaringan ngajalankeun on host sarua. Jieun jaringan kalayan paréntah di handap ieu:

docker network create msvc-network

Salajengna, mimitian wadah backend ngaranna 'backend' jeung microservices-backend: 1.0.0 gambar:

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

Eta sia noting yén jaringan sasak nyadiakeun out of the box kapanggihna jasa pikeun wadahna ku ngaran maranéhanana. Nyaéta, jasa backend bakal sayogi di jero jaringan docker di http://backend:8080.

Ngamimitian 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

Dina paréntah ieu, kami nunjukkeun yén kami nuju neraskeun port 80 host kami ka port 8080 wadahna. Urang make pilihan env ka set variabel lingkungan anu otomatis bakal dibaca ku cinyusu jeung override sipat tina application.properties.

Sanggeus dimimitian, urang nelepon http://localhost/ tur pastikeun yén sagalana jalan, sakumaha dina kasus saméméhna.

kacindekan

Hasilna, urang dijieun dua microservices basajan, rangkep aranjeunna dina peti docker sarta dibuka aranjeunna babarengan dina mesin sarua. Sistem anu dihasilkeun, kumaha oge, ngagaduhan sababaraha kalemahan:

  • Kasabaran lepat goréng - sagalana lumaku pikeun urang dina hiji server
  • Skalabilitas goréng - nalika beban naék, langkung saé pikeun otomatis nyebarkeun instansi jasa tambahan sareng saimbangkeun beban di antara aranjeunna
  • Pajeulitna peluncuran - urang kedah ngalebetkeun sahenteuna 3 paréntah, sareng kalayan parameter anu tangtu (ieu ngan ukur pikeun 2 jasa)

Pikeun ngalereskeun masalah di luhur, aya sababaraha solusi sapertos Docker Swarm, Nomad, Kubernetes atanapi OpenShift. Upami sadayana sistem ditulis dina Java, anjeun tiasa ningali ka arah Spring Cloud (artikel alus).

В bagian salajengna Kuring bakal ngobrol ngeunaan kumaha kuring nyetél Kubernetes sareng nyebarkeun proyék ka Google Kubernetes Engine.

sumber: www.habr.com

Tambahkeun komentar