Sinau carane masang layanan mikro. Part 1. Spring Boot lan Docker

Sinau carane masang layanan mikro. Part 1. Spring Boot lan Docker

Hey Habr.

Ing artikel iki, aku pengin ngomong babagan pengalaman nggawe lingkungan sinau kanggo eksperimen karo layanan mikro. Nalika aku sinau saben alat anyar, Aku tansah wanted kanggo nyoba ora mung ing mesin lokal, nanging uga ing kahanan luwih nyata. Mulane, aku mutusake kanggo nggawe aplikasi microservice sing disederhanakake, sing mengko bisa "ditutupi" karo kabeh jinis teknologi sing menarik. Syarat utama kanggo proyek kasebut yaiku jarak fungsional maksimal menyang sistem nyata.

Kaping pisanan, aku nyuwil nggawe proyek dadi sawetara langkah:

  1. Gawe rong layanan - 'backend' (backend) lan 'gateway' (gateway), bungkus menyang gambar docker lan atur supaya bisa digunakake bebarengan

    Kata Kunci: Java 11, Spring Boot, Docker, image optimization

  2. Pangembangan konfigurasi Kubernetes lan panyebaran sistem ing Google Kubernetes Engine

    Kata Kunci: Kubernetes, GKE, manajemen sumber daya, autoscaling, rahasia

  3. Nggawe grafik nganggo Helm 3 kanggo manajemen kluster sing luwih apik

    Tags: Helm 3, penyebaran grafik

  4. Nyetel Jenkins lan pipeline kanggo pangiriman otomatis kode kanggo kluster

    Kata Kunci: konfigurasi Jenkins, plugins, repositori konfigurasi sing kapisah

Aku rencana kanggo nyawisake artikel kapisah kanggo saben langkah.

Fokus saka seri artikel iki dudu carane nulis layanan mikro, nanging kepiye carane bisa digunakake ing siji sistem. Senajan kabeh iki biasane njaba tanggung jawab pangembang, Aku isih migunani kanggo menowo karo wong-wong mau ing paling 20% ​​(sing, sing ngerti, menehi 80% saka asil). Sawetara topik tanpa syarat penting, kayata keamanan, bakal ditinggalake saka proyek iki, amarga penulis ora ngerti babagan sistem iki mung digawe kanggo panggunaan pribadi. Aku nampani panemu lan kritik sing mbangun.

Nggawe microservices

Layanan kasebut ditulis ing Java 11 nggunakake Spring Boot. Interaksi antar layanan diatur nggunakake REST. Proyèk bakal kalebu jumlah minimal saka tes (supaya mengko ana soko kanggo nyoba ing Jenkins). Kode sumber kanggo layanan kasedhiya ing GitHub: mburi и Gerbang.

Kanggo bisa mriksa status saben layanan, Spring Actuator wis ditambahake menyang dependensi. Iku bakal nggawe / actuator / endpoint kesehatan lan bali status 200 yen layanan siap kanggo nampa lalu lintas, utawa 504 yen ana masalah. Ing kasus iki, iki mriksa rada fiktif, amarga layanan banget prasaja, lan ing cilik saka sawetara force majeure, padha luwih kamungkinan kanggo dadi rampung ora kasedhiya saka tetep sebagian operasional. Nanging ing sistem nyata, Actuator bisa mbantu diagnosa masalah sadurunge pangguna miwiti perang. Contone, yen ana masalah ngakses database, kita bisa kanthi otomatis nanggapi iki kanthi mungkasi panjalukan pangolahan karo conto layanan rusak.

Layanan mburi mburi

Layanan backend mung bakal ngetung lan ngasilake jumlah panjaluk sing ditampa.

Kode pengontrol:

@RestController
public class RequestsCounterController {

    private final AtomicLong counter = new AtomicLong();

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

Tes kontrol:

@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 Layanan

Gerbang kasebut bakal nerusake panjalukan menyang layanan backend, ditambah karo informasi ing ngisor iki:

  • id gateway Perlu supaya bisa mbedakake siji conto gateway saka liyane kanthi respon server
  • Sawetara "rahasia" sing bakal dadi sandhi sing penting banget (nomer kunci enkripsi cookie penting)

Konfigurasi ing application.properties:

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

Adaptor mburi:

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

pengontrol:

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

Bukak:

Kita miwiti backend:

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

Miwiti gateway:

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

Priksa:

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

Kabeh mlaku. Sing maca sing ati-ati bakal nyathet yen ora ana sing ngalangi kita ngakses backend langsung, ngliwati gateway (http://localhost:8081/requests). Kanggo ndandani iki, layanan kasebut kudu digabung dadi siji jaringan, lan mung gateway sing kudu "metu" ing njaba.
Kajaba iku, loro layanan nuduhake siji sistem file, ngasilake stream lan ing wayahe bisa mulai ngganggu siji liyane. Luwih becik ngisolasi layanan mikro kita. Iki bisa digayuh kanthi nyebarake aplikasi ing mesin sing beda-beda (dhuwit akeh, angel), nggunakake mesin virtual (intensif sumber daya, wiwitan dawa), utawa nggunakake containerization. Kaya samesthine, kita milih pilihan katelu lan docker minangka alat kanggo containerization.

docker

Ing cendhak, docker nggawe wadhah sing terisolasi, siji saben aplikasi. Kanggo nggunakake docker, sampeyan kudu nulis Dockerfile - instruksi kanggo mbangun lan mbukak aplikasi. Sabanjure, sampeyan bisa mbangun gambar, upload menyang registri gambar (No. Dockerhub) lan masang microservice ing sembarang lingkungan dockerized ing siji printah.

file docker

Salah sawijining ciri sing paling penting saka gambar yaiku ukurane. Gambar sing kompak bakal diundhuh luwih cepet saka repositori remot, njupuk papan sing luwih sithik, lan layanan sampeyan bakal luwih cepet. Sembarang gambar dibangun kanthi basis gambar dhasar, lan dianjurake kanggo milih pilihan sing paling minimalis. Pilihan sing apik yaiku Alpine, distribusi Linux lengkap kanthi paket minimal.

Pisanan, ayo nyoba nulis Dockerfile "ing bathuk" (aku bakal langsung ngomong yen iki cara sing ala, aja nglakoni):

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

Ing kene kita nggunakake gambar basis Alpine kanthi JDK sing wis diinstal kanggo mbangun proyek kita. Kanthi printah ADD, kita nambah direktori src saiki kanggo gambar, tandha minangka digunakake (WORKDIR) lan miwiti mbangun. Printah EXPOSE 8080 menehi sinyal menyang docker yen aplikasi ing wadhah bakal nggunakake port 8080 (iki ora bakal nggawe aplikasi bisa diakses saka njaba, nanging ngidini aplikasi bisa diakses, contone, saka wadhah liyane ing jaringan docker sing padha. ).

Kanggo paket layanan menyang gambar, sampeyan kudu mbukak printah saka ROOT saben project:

docker image build . -t msvc-backend:1.0.0

Asil punika 456 MB gambar (kang basis JDK gambar dikuwasani 340 MB). Lan kabeh senadyan kasunyatane yen kelas ing proyek kita bisa diitung nganggo driji. Kanggo nyuda ukuran gambar kita:

  • Kita nggunakake perakitan multi-langkah. Ing langkah pisanan kita bakal mbangun proyek, ing langkah kapindho kita bakal nginstal JRE, lan ing langkah katelu kita bakal nyalin kabeh menyang gambar Alpine resik anyar. Secara total, mung komponen sing dibutuhake bakal ana ing gambar pungkasan.
  • Ayo nggunakake modularization of java. Miwiti karo Java 9, sampeyan bisa nggunakake alat jlink kanggo nggawe JRE mung saka modul sing dibutuhake

Kanggo sing kepengin weruh, ing kene ana artikel sing apik babagan pendekatan pengurangan gambar. https://habr.com/ru/company/ruvds/blog/485650/.

File Docker pungkasan:

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

Kita nggawΓ© ulang gambar, lan minangka asil, iku ilang 6 kaping bobot, gunggungipun 77 MB. Ora ala. Sawise iku, gambar sing wis siap bisa diunggah menyang registri gambar supaya gambar sampeyan kasedhiya kanggo diundhuh saka Internet.

Co-running layanan ing Docker

Kanggo miwiti, layanan kita kudu ing jaringan sing padha. Ana sawetara jinis jaringan ing docker, lan kita nggunakake paling primitif saka wong-wong mau - bridge, sing ngijini sampeyan kanggo jaringan kontaner mlaku ing inang padha. Gawe jaringan kanthi printah ing ngisor iki:

docker network create msvc-network

Sabanjure, miwiti wadhah backend jenenge 'backend' karo microservices-backend:1.0.0 gambar:

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

Wigati dicathet yen jaringan jembatan nyedhiyakake panemuan layanan out of the box kanggo wadhah kanthi jenenge. Yaiku, layanan backend bakal kasedhiya ing jaringan docker ing http://backend:8080.

Miwiti 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

Ing printah iki, kita nuduhake yen kita nerusake port 80 saka host menyang port 8080 saka wadhah kasebut. Kita nggunakake opsi env kanggo nyetel variabel lingkungan sing bakal diwaca kanthi otomatis dening spring lan override sifat saka application.properties.

Sawise miwiti, kita nelpon http://localhost/ lan priksa manawa kabeh bisa digunakake, kaya ing kasus sadurunge.

kesimpulan

AkibatΓ©, kita nggawe loro microservices prasaja, rangkep mau ing wadhah docker lan dibukak bebarengan ing mesin padha. Sistem sing diasilake, nanging, duwe sawetara kekurangan:

  • toleransi fault miskin - kabeh bisa kanggo kita ing siji server
  • Skalabilitas sing ora apik - nalika beban mundhak, luwih becik masang conto layanan tambahan kanthi otomatis lan ngimbangi beban ing antarane.
  • Kerumitan peluncuran - kita kudu ngetik paling ora 3 printah, lan kanthi paramΓ¨ter tartamtu (iki mung kanggo 2 layanan)

Kanggo ndandani masalah ing ndhuwur, ana sawetara solusi kayata Docker Swarm, Nomad, Kubernetes utawa OpenShift. Yen kabeh sistem ditulis ing Jawa, sampeyan bisa ndeleng menyang Spring Cloud (artikel apik).

Π’ bagean sabanjure Aku bakal ngomong babagan carane nyiyapake Kubernetes lan nyebarake proyek kasebut menyang Google Kubernetes Engine.

Source: www.habr.com

Add a comment