Микросервистерді қолдану жолын үйреніңіз. 1-бөлім. Spring Boot және Docker

Микросервистерді қолдану жолын үйреніңіз. 1-бөлім. Spring Boot және Docker

Эй Хабр.

Бұл мақалада мен микросервистермен тәжірибе жасау үшін оқу ортасын құрудағы тәжірибем туралы айтқым келеді. Әрбір жаңа құралды үйренген кезде мен оны тек жергілікті машинада ғана емес, сонымен қатар нақтырақ жағдайларда да қолданып көргім келді. Сондықтан мен жеңілдетілген микросервис қосымшасын жасауды шештім, оны кейінірек қызықты технологиялардың барлық түрлерімен «жабуға» болады. Жобаға қойылатын негізгі талап оның нақты жүйеге барынша функционалдық жақындығы болып табылады.

Бастапқыда мен жобаны құруды бірнеше кезеңге бөлдім:

  1. Екі қызметті жасаңыз - «backend» (backend) және «шлюз» (шлюз), оларды докер кескіндеріне жинаңыз және бірге жұмыс істеуге реттеңіз

    Түйін сөздер: Java 11, Spring Boot, Docker, кескінді оңтайландыру

  2. Google Kubernetes Engine жүйесінде Kubernetes конфигурациясын әзірлеу және жүйені орналастыру

    Түйін сөздер: Kubernetes, GKE, ресурстарды басқару, автомасштабтау, құпиялар

  3. Кластерді жақсырақ басқару үшін Helm 3 көмегімен диаграмма құру

    Тегтер: Helm 3, диаграмманы орналастыру

  4. Кодты кластерге автоматты түрде жеткізу үшін Jenkins және құбыр желісін орнату

    Түйін сөздер: Дженкинс конфигурациясы, плагиндер, бөлек конфигурациялар репозиторийі

Мен әр қадамға жеке мақала арнауды жоспарлап отырмын.

Бұл мақалалар топтамасының негізгі мақсаты микросервистерді қалай жазу керек емес, олардың бір жүйеде жұмыс істеуін қамтамасыз ету. Мұның бәрі әдетте әзірлеушінің жауапкершілігінен тыс болса да, менің ойымша, олармен кем дегенде 20% (бұл сіз білетіндей, нәтиженің 80% береді) танысу әлі де пайдалы. Кейбір сөзсіз маңызды тақырыптар, мысалы, қауіпсіздік, бұл жобадан тыс қалады, өйткені автор бұл жүйенің жеке пайдалану үшін жасалғаны туралы аз түсінеді. Кез келген пікірлер мен сындарлы сынды құптаймын.

Микросервистерді құру

Қызметтер Spring Boot көмегімен Java 11-де жазылған. Қызметаралық өзара әрекеттесу REST көмегімен ұйымдастырылады. Жоба тесттердің ең аз санын қамтиды (кейінірек Дженкинсте сынауға болатын нәрсе болуы үшін). Қызметтердің бастапқы коды GitHub сайтында қолжетімді: сервер и Шлюз.

Әрбір қызметтің күйін тексере алу үшін олардың тәуелділіктеріне серіппелі жетек қосылды. Ол /жетекші/денсаулық соңғы нүктесін жасайды және қызмет трафикті қабылдауға дайын болса, 200 күйін немесе ақаулық болса 504 күйін қайтарады. Бұл жағдайда бұл өте жалған тексеру, өйткені қызметтер өте қарапайым және қандай да бір форс-мажор жағдайында олар ішінара жұмыс істеп тұрғаннан гөрі толығымен қолжетімсіз болып қалуы ықтимал. Бірақ нақты жүйелерде Actuator пайдаланушылар онымен күресуді бастамас бұрын мәселені диагностикалауға көмектеседі. Мысалы, дерекқорға қатынасу кезінде қиындықтар туындаса, бұзылған қызмет данасы бар сұрауларды өңдеуді тоқтату арқылы біз бұған автоматты түрде жауап бере аламыз.

Backend қызметі

Сервис қызметі қабылданған сұраулардың санын жай ғана санап, қайтарады.

Контроллер коды:

@RestController
public class RequestsCounterController {

    private final AtomicLong counter = new AtomicLong();

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

Контроллер сынағы:

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

Қызметтік шлюз

Шлюз сұранысты келесі ақпаратпен толықтыра отырып, серверлік қызметке жібереді:

  • шлюз идентификаторы. Бұл сервердің жауабы арқылы шлюздің бір данасын екіншісінен ажырату үшін қажет.
  • Өте маңызды құпия сөздің рөлін атқаратын кейбір «құпия» (маңызды cookie файлының шифрлау кілтінің саны)

application.properties ішіндегі конфигурация:

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

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

Контроллер:

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

Іске қосу:

Біз серверді бастаймыз:

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

Шлюзді іске қосу:

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

Тексеру:

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

Барлығы жұмыс істейді. Мұқият оқырман шлюзді айналып өтіп, серверге тікелей қол жеткізуге ештеңе кедергі келтірмейтінін атап өтеді (http://localhost:8081/requests). Мұны түзету үшін қызметтерді бір желіге біріктіру керек және тек шлюз сыртында «шығарып» тұруы керек.
Сондай-ақ, екі қызмет де бір файлдық жүйені ортақ пайдаланады, ағындар шығарады және бір сәтте бір-біріне кедергі жасай бастайды. Біздің микросервистерді оқшаулау жақсы болар еді. Бұған әртүрлі машиналарда қосымшаларды тарату (көп ақша, қиын), виртуалды машиналарды (ресурсты қажет ететін, ұзақ іске қосу) немесе контейнерлеуді пайдалану арқылы қол жеткізуге болады. Күтілгендей, біз үшінші нұсқаны таңдаймыз және Докер контейнерлеу құралы ретінде.

Докер

Қысқаша айтқанда, докер оқшауланған контейнерлерді жасайды, әр қолданбаға бір. Докерді пайдалану үшін сізге Dockerfile жазу керек - қолданбаны құру және іске қосу нұсқаулары. Әрі қарай, сіз суретті құра аласыз, оны кескіндер тізіліміне жүктей аласыз (№. Dockerhub) және бір пәрменде микросервисті кез келген докерленген ортада орналастырыңыз.

Докер файлы

Кескіннің ең маңызды сипаттамаларының бірі оның өлшемі болып табылады. Ықшам кескін қашықтағы репозиторийден жылдамырақ жүктеледі, аз орын алады және қызметіңіз жылдамырақ басталады. Кез келген сурет негізгі кескіннің негізінде құрастырылады және ең минималистік опцияны таңдау ұсынылады. Жақсы нұсқа - Alpine, ең аз пакеттері бар толық Linux дистрибуциясы.

Алдымен, Dockerfile файлын «маңдайға» жазуға тырысайық (бұл жаман жол екенін бірден айтамын, оны жасамаңыз):

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

Мұнда жобамызды құру үшін JDK орнатылған альпі негізіндегі негізгі кескінді қолданамыз. ADD командасы арқылы суретке ағымдағы src каталогын қосып, оны жұмыс (WORKDIR) деп белгілеп, құрастыруды бастаймыз. EXPOSE 8080 пәрмені докерге контейнердегі қолданба өзінің 8080 портын пайдаланатыны туралы сигнал береді (бұл қолданбаға сырттан қол жеткізуге мүмкіндік бермейді, бірақ қолданбаға, мысалы, сол докер желісіндегі басқа контейнерден кіруге мүмкіндік береді. ).

Қызметтерді кескіндерге бумалау үшін әр жобаның түбірінен пәрмендерді орындау керек:

docker image build . -t msvc-backend:1.0.0

Нәтиже - 456 МБ кескін (оның ішінде негізгі JDK кескіні 340 МБ алып). Біздің жобадағы сабақтарды саусақпен санауға болатынына қарамастан. Біздің суреттің өлшемін азайту үшін:

  • Біз көп сатылы құрастыруды қолданамыз. Бірінші қадамда жобаны құрастырамыз, екінші қадамда JRE орнатамыз, үшінші қадамда оның барлығын жаңа таза Альпі кескініне көшіреміз. Жалпы, соңғы кескінде тек қажетті компоненттер ғана болады.
  • Java модульизациясын қолданайық. Java 9-дан бастап, сізге қажет модульдерден JRE жасау үшін jlink құралын пайдалануға болады

Ізденімпаздар үшін суретті азайту тәсілдері туралы жақсы мақала бар. https://habr.com/ru/company/ruvds/blog/485650/.

Соңғы Docker файлы:

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

Біз кескінді қайта жасаймыз, нәтижесінде ол 6 есе салмағын жоғалтып, 77 МБ құрайды. Жаман емес. Осыдан кейін дайын суреттерді суреттер тізіліміне жүктеп салуға болады, осылайша сіздің суреттеріңіз Интернеттен жүктеп алуға болады.

Docker-те бірге жұмыс істейтін қызметтер

Алдымен біздің қызметтеріміз бір желіде болуы керек. Докерде желілердің бірнеше түрі бар және біз олардың ең қарапайым түрін қолданамыз - бір хостта жұмыс істейтін контейнерлерді желіге қосуға мүмкіндік беретін көпір. Келесі пәрмен арқылы желіні жасаңыз:

docker network create msvc-network

Содан кейін microservices-backend:1.0.0 кескінімен «backend» деп аталатын серверлік контейнерді бастаңыз:

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

Айта кету керек, көпір желісі контейнерлер үшін олардың атаулары бойынша ашық қызмет көрсетуді қамтамасыз етеді. Яғни, серверлік қызмет докер желісінің ішінде қол жетімді болады http://backend:8080.

Шлюзді іске қосу:

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

Бұл пәрменде біз хосттың 80 портын контейнердің 8080 портына бағыттайтынымызды көрсетеміз. Біз env опцияларын көктем арқылы автоматты түрде оқылатын және application.properties сипаттарын қайта анықтайтын орта айнымалыларын орнату үшін пайдаланамыз.

Бастағаннан кейін біз қоңырау шаламыз http://localhost/ және алдыңғы жағдайдағыдай бәрі жұмыс істейтініне көз жеткізіңіз.

қорытынды

Нәтижесінде біз екі қарапайым микросервис жасап, оларды докер контейнерлеріне жинап, бір машинада бірге іске қостық. Алынған жүйенің бірқатар кемшіліктері бар:

  • Ақауларға төзімділік нашар - бәрі біз үшін бір серверде жұмыс істейді
  • Нашар масштабтау - жүктеме ұлғайған кезде, қосымша қызмет даналарын автоматты түрде орналастыру және олардың арасындағы жүктемені теңестіру жақсы болар еді.
  • Іске қосудың күрделілігі - бізге кем дегенде 3 пәрменді енгізу керек болды және белгілі бір параметрлермен (бұл тек 2 қызметке арналған)

Жоғарыда аталған мәселелерді шешу үшін Docker Swarm, Nomad, Kubernetes немесе OpenShift сияқты бірқатар шешімдер бар. Бүкіл жүйе Java тілінде жазылған болса, Spring Cloud-қа қарай аласыз (жақсы мақала).

В келесі бөлім Мен Kubernetes-ті қалай орнатқаным және жобаны Google Kubernetes Engine жүйесіне қалай енгізгенім туралы айтатын боламын.

Ақпарат көзі: www.habr.com

пікір қалдыру