Aprendendo a implantar microsserviços. Parte 1. Spring Boot e Docker


Olá, Habr.


Neste artigo, quero falar sobre minha experiência na criação de um ambiente de aprendizado para experimentos com microsserviços. Ao estudar cada nova ferramenta, sempre quis experimentá-la não apenas na máquina local, mas também em condições mais realistas. Portanto, decidi criar um aplicativo simplificado de microsserviço, que posteriormente pode ser "ponderado" com todos os tipos de tecnologias interessantes. O principal requisito para o projeto é sua proximidade funcional máxima ao sistema real.


Inicialmente, quebrei a criação do projeto em várias etapas:


  1. — '' (backend) '' (gateway), docker-


    : Java 11, Spring Boot, Docker, image optimization


  2. Kubernetes Google Kubernetes Engine


    : Kubernetes, GKE, resource management, autoscaling, secrets


  3. Helm 3


    : Helm 3, chart deployment


  4. Jenkins


    : Jenkins configuration, plugins, separate configs repository



.


, , . , , 20% (, , 80% ). , , , . .



Java 11 Spring Boot. REST. ( , Jenkins). GitHub: .


, Spring Actuator. /actuator/health 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"));
    }
}

Gateway

, :


  • id . ,
  • "", (№ )

application.properties:


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

:


@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). , , "" .
, . . ( , ), (, ) . Docker .


Docker


, , . , Dockerfile — . , (№ DockerHub) .


Dockerfile


— . , , . , . 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"]

Alpine JDK . ADD src, (WORKDIR) . EXPOSE 8080 , 8080 ( , , , ).


:


docker image build . -t msvc-backend:1.0.0

456 ( JDK 340 ). , . :


  • . , JRE, Alpine . .
  • java. Java 9, jlink JRE

, https://habr.com/ru/company/ruvds/blog/485650/.


Dockerfile:


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 anshelen@yandex.ru"
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


. , — bridge, , . :


docker network create msvc-network

'backend' microservices-backend:1.0.0:


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

, bridge- service discovery . 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 )

Para resolver os problemas acima, existem várias soluções, como Docker Swarm, Nomad, Kubernetes ou OpenShift. Se todo o sistema for escrito em Java, você pode olhar para o Spring Cloud (um bom artigo ).


Na próxima parte, falarei sobre como eu configurei o Kubernetes e implantei o projeto no Google Kubernetes Engine.

Source: https://habr.com/ru/post/undefined/


All Articles