Mikroservislarni qo'llashni o'rganish. 1-qism. Spring Boot va Docker

Mikroservislarni qo'llashni o'rganish. 1-qism. Spring Boot va Docker

Salom, Xabr.

Ushbu maqolada men mikroservislar bilan tajriba o'tkazish uchun o'quv muhitini yaratish tajribam haqida gapirmoqchiman. Har bir yangi vositani o'rganayotganda, men uni nafaqat mahalliy mashinamda, balki realroq sharoitlarda ham sinab ko'rishni xohlardim. Shuning uchun men soddalashtirilgan mikroservis dasturini yaratishga qaror qildim, keyinchalik uni har xil qiziqarli texnologiyalar bilan "osib qo'yish" mumkin. Loyihaning asosiy talabi uning real tizimga maksimal funktsional yaqinligidir.

Dastlab, men loyihani yaratishni bir necha bosqichlarga ajratdim:

  1. Ikkita xizmat yarating - "backend" va "shlyuz", ularni docker tasvirlariga to'plang va ularni birgalikda ishlash uchun sozlang

    Kalit so'zlar: Java 11, Spring Boot, Docker, tasvirni optimallashtirish

  2. Google Kubernetes Engine-da Kubernetes konfiguratsiyasi va joylashtirish tizimini ishlab chiqish

    Kalit so'zlar: Kubernetes, GKE, resurslarni boshqarish, avtomatik o'lchov, sirlar

  3. Klasterni yanada samarali boshqarish uchun Helm 3 yordamida diagramma yarating

    Kalit so'zlar: Helm 3, diagrammani joylashtirish

  4. Kodni klasterga avtomatik yetkazib berish uchun Jenkins va quvur liniyasini sozlash

    Kalit so'zlar: Jenkins konfiguratsiyasi, plaginlar, alohida konfiguratsiyalar ombori

Men har bir bosqichga alohida maqola bag'ishlashni rejalashtirmoqdaman.

Ushbu maqolalar turkumining asosiy maqsadi mikroservislarni qanday yozish emas, balki ularni qanday qilib yagona tizimda ishlashidir. Bularning barchasi odatda ishlab chiquvchining javobgarligidan tashqarida bo'lsa-da, menimcha, ular bilan kamida 20% tanish bo'lish hali ham foydalidir (natijaning 80% ni tashkil qilishi ma'lum). Xavfsizlik kabi ba'zi mutlaqo muhim mavzular ushbu loyihadan chetda qoladi, chunki muallif bu haqda kam tushunadi; tizim faqat shaxsiy foydalanish uchun yaratilgan. Men har qanday fikr va konstruktiv tanqidni mamnuniyat bilan qabul qilaman.

Mikroservislarni yaratish

Xizmatlar Java 11 da Spring Boot yordamida yozilgan. Xizmatlararo aloqa REST yordamida tashkil etiladi. Loyiha minimal miqdordagi testlarni o'z ichiga oladi (keyinchalik Jenkinsda sinab ko'rish uchun biror narsa bo'ladi). Xizmatlar uchun manba kodi GitHub da mavjud: backend и Gateway.

Xizmatlarning har birining holatini tekshirish uchun ularning bog'liqligiga Spring Actuator qo'shildi. U so'nggi nuqta / aktuator / sog'liqni yaratadi va agar xizmat trafikni qabul qilishga tayyor bo'lsa, 200 yoki muammo yuzaga kelganda 504 holatini qaytaradi. Bunday holda, bu juda xayoliy tekshirish, chunki xizmatlar juda oddiy va qandaydir fors-major holatlarida ular qisman ishlamay qolishdan ko'ra butunlay ishlamay qolish ehtimoli ko'proq. Biroq, haqiqiy tizimlarda, Actuator foydalanuvchilar uni urishni boshlashdan oldin muammoni aniqlashga yordam beradi. Misol uchun, agar ma'lumotlar bazasiga kirish bilan bog'liq muammolar yuzaga kelsa, biz xizmatning buzilgan namunasi bilan so'rovlarni qayta ishlashni to'xtatib, bunga avtomatik ravishda javob bera olamiz.

Backend xizmati

Backend xizmati qabul qilingan so'rovlar sonini hisoblab chiqadi va qaytaradi.

Tekshirish kodi:

@RestController
public class RequestsCounterController {

    private final AtomicLong counter = new AtomicLong();

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

Tekshirish moslamasi testi:

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

Shlyuz so'rovni quyidagi ma'lumotlar bilan to'ldirib, backend xizmatiga yo'naltiradi:

  • shlyuz identifikatori. Bu shlyuzning bir nusxasini server javobi bilan boshqasidan ajratib olishi uchun kerak
  • Juda muhim parol rolini o'ynaydigan ma'lum bir "sir" (muhim cookie-faylni shifrlash uchun kalit raqami)

application.properties da konfiguratsiya:

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

Backend bilan aloqa uchun adapter:

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

Nazoratchi:

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

Ishga tushirish:

Backendni ishga tushiramiz:

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

Keling, shlyuzni boshlaylik:

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

Biz tekshiramiz:

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

Hammasi ishlayapti. Diqqatli o'quvchi shuni ta'kidlaydiki, hech narsa bizga shlyuzni chetlab o'tib, to'g'ridan-to'g'ri orqa qismga kirishimizga to'sqinlik qilmaydi (http://localhost:8081/requests). Buni tuzatish uchun xizmatlarni bitta tarmoqqa birlashtirish kerak va faqat shlyuz tashqaridan "chiqishi" kerak.
Bundan tashqari, ikkala xizmat ham bir xil fayl tizimini baham ko'radi, mavzularni yaratadi va bir vaqtning o'zida bir-biriga xalaqit bera boshlaydi. Mikroservislarimizni izolyatsiya qilish yaxshi bo'lardi. Bunga turli xil mashinalar (ko'p pul, qiyin) bo'yicha ilovalarni tarqatish, virtual mashinalar (resursni ko'p talab qiladigan, uzoq ishga tushirish) yoki konteynerlashtirish yordamida erishish mumkin. Kutilganidek, biz uchinchi variantni tanlaymiz va Docker konteynerlash uchun vosita sifatida.

Docker

Muxtasar qilib aytganda, Docker har bir dastur uchun bittadan ajratilgan konteynerlarni yaratadi. Docker-dan foydalanish uchun siz Dockerfile yozishingiz kerak - dasturni yaratish va ishga tushirish bo'yicha ko'rsatmalar. Keyinchalik, siz rasmni yaratishingiz, uni tasvirlar reestriga yuklashingiz mumkin (№. Dockerhub) va bitta buyruqda mikroservisingizni istalgan dokerlashtirilgan muhitda joylashtiring.

Docker fayli

Tasvirning eng muhim xususiyatlaridan biri uning o'lchamidir. Yilni tasvir masofaviy ombordan tezroq yuklab olinadi, kamroq joy egallaydi va sizning xizmatingiz tezroq boshlanadi. Har qanday tasvir asosiy tasvir asosida quriladi va eng minimalist variantni tanlash tavsiya etiladi. Yaxshi variant - Alpine, minimal paketlarga ega to'liq huquqli Linux tarqatish.

Birinchidan, keling, Dockerfile faylini "boshqa" yozishga harakat qilaylik (darhol aytaman, bu yomon yo'l, buni qilmang):

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

Bu erda biz loyihamizni qurish uchun allaqachon o'rnatilgan JDK bilan Alp tog'lariga asoslangan asosiy tasvirdan foydalanmoqdamiz. ADD buyrug'i yordamida biz rasmga joriy src katalogini qo'shamiz, uni ishlayotgan deb belgilaymiz (WORKDIR) va qurishni boshlaymiz. EXPOSE 8080 buyrug'i dockerga konteynerdagi ilova o'zining 8080 portidan foydalanishi haqida signal beradi (bu ilovaga tashqaridan kirish imkoniyatini yaratmaydi, lekin ilovaga, masalan, xuddi shu doker tarmog'idagi boshqa konteynerdan kirish imkonini beradi. ).

Xizmatlarni tasvirlarga joylashtirish uchun har bir loyihaning ildizidan buyruqlarni ishga tushirishingiz kerak:

docker image build . -t msvc-backend:1.0.0

Natijada biz 456 MB hajmdagi tasvirni olamiz (shundan JDK 340 asosiy tasviri MB olgan). Va bizning loyihamizdagi darslarni bir barmoq bilan sanash mumkinligiga qaramay. Tasvirimiz hajmini kamaytirish uchun:

  • Biz ko'p bosqichli yig'ilishdan foydalanamiz. Birinchi bosqichda biz loyihani yig'amiz, ikkinchisida biz JRE-ni o'rnatamiz va uchinchi bosqichda bularning barchasini yangi toza Alp tog'lari tasviriga nusxalaymiz. Hammasi bo'lib, yakuniy rasm faqat kerakli komponentlarni o'z ichiga oladi.
  • Keling, java modulizatsiyasidan foydalanamiz. Java 9 dan boshlab, faqat kerakli modullardan JRE yaratish uchun jlink vositasidan foydalanishingiz mumkin

Qiziqqanlar uchun bu erda tasvir o'lchamlarini kamaytirish yondashuvlari haqida yaxshi maqola mavjud https://habr.com/ru/company/ruvds/blog/485650/.

Yakuniy Docker fayli:

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

Biz tasvirni qayta yaratdik va u oxir-oqibat 6 barobar yupqaroq bo'lib, 77 MB ni tashkil qildi. Yomon emas. Shundan so'ng, tayyor rasmlarni tasvirlar reestriga yuklash mumkin, shunda sizning rasmlaringiz Internetdan yuklab olish mumkin bo'ladi.

Docker-da xizmatlarni birgalikda ishlatish

Boshlash uchun bizning xizmatlarimiz bir xil tarmoqda bo'lishi kerak. Docker-da tarmoqlarning bir nechta turlari mavjud va biz ulardan eng ibtidoiysi - ko'prikdan foydalanamiz, bu sizga bitta xostda ishlaydigan konteynerlarni tarmoqqa ulash imkonini beradi. Quyidagi buyruq bilan tarmoq yaratamiz:

docker network create msvc-network

Keyin, microservices-backend:1.0.0 tasviri bilan “backend” nomli backend konteynerini ishga tushiramiz:

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

Shuni ta'kidlash kerakki, ko'prik tarmog'i konteynerlar uchun ularning nomlari bo'yicha xizmat ko'rsatishni ta'minlaydi. Ya'ni, backend xizmati Docker tarmog'ida mavjud bo'ladi http://backend:8080.

Keling, shlyuzni boshlaylik:

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

Ushbu buyruqda biz hostimizning 80-portini konteynerning 8080-portiga yo'naltirayotganimizni bildiramiz. Biz env parametrlaridan bahorgacha avtomatik ravishda o'qiladigan muhit o'zgaruvchilarini o'rnatish va application.properties dan xususiyatlarni bekor qilish uchun foydalanamiz.

Ishga tushgandan so'ng, qo'ng'iroq qiling http://localhost/ va avvalgi holatda bo'lgani kabi hamma narsa ishlayotganiga ishonch hosil qiling.

xulosa

Natijada, biz ikkita oddiy mikroservisni yaratdik, ularni docker konteynerlariga joylashtirdik va ularni bitta mashinada birga ishga tushirdik. Olingan tizim bir qator kamchiliklarga ega:

  • Kambag'al xatolarga chidamlilik - biz uchun hamma narsa bitta serverda ishlaydi
  • Yomon miqyoslilik - yuk ortib borayotganligi sababli, qo'shimcha xizmat misollarini avtomatik ravishda o'rnatish va ular orasidagi yukni muvozanatlash yaxshi bo'lar edi
  • Ishga tushirishning murakkabligi - biz ma'lum parametrlarga ega kamida 3 ta buyruqni kiritishimiz kerak edi (bu faqat 2 ta xizmat uchun)

Yuqoridagi muammolarni hal qilish uchun Docker Swarm, Nomad, Kubernetes yoki OpenShift kabi bir qator echimlar mavjud. Agar butun tizim Java-da yozilgan bo'lsa, siz Spring Cloud-ga qarashingiz mumkin (yaxshi maqola).

В keyingi qism Men sizga Kubernetes-ni qanday sozlaganim va loyihani Google Kubernetes Engine-ga qanday joylashtirganim haqida aytib beraman.

Manba: www.habr.com

a Izoh qo'shish