Π£Ρ‡ΠΈΠΌ ΠΊΠ°ΠΊ Π΄Π° Ρ€Π°Π·Π²ΠΈΠ²Π°ΠΌΠ΅ микросСрвиси. Част 1. Spring Boot ΠΈ Docker

Π£Ρ‡ΠΈΠΌ ΠΊΠ°ΠΊ Π΄Π° Ρ€Π°Π·Π²ΠΈΠ²Π°ΠΌΠ΅ микросСрвиси. Част 1. Spring Boot ΠΈ Docker

Π—Π΄Ρ€Π°Π²Π΅ΠΉ, Π₯Π°Π±Ρ€.

Π’ Ρ‚Π°Π·ΠΈ статия искам Π΄Π° сподСля ΠΎΠΏΠΈΡ‚Π° си Π² ΡΡŠΠ·Π΄Π°Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° ΡƒΡ‡Π΅Π±Π½Π° срСда Π·Π° СкспСримСнтиранС с микросСрвизи. ΠšΠΎΠ³Π°Ρ‚ΠΎ ΠΈΠ·ΡƒΡ‡Π°Π²Π°ΠΌ всСки Π½ΠΎΠ² инструмСнт, Π²ΠΈΠ½Π°Π³ΠΈ съм искал Π΄Π° Π³ΠΎ ΠΏΡ€ΠΎΠ±Π²Π°ΠΌ Π½Π΅ само Π½Π° Π»ΠΎΠΊΠ°Π»Π½Π°Ρ‚Π° машина, Π½ΠΎ ΠΈ ΠΏΡ€ΠΈ ΠΏΠΎ-рСалистични условия. Π—Π°Ρ‚ΠΎΠ²Π° Ρ€Π΅ΡˆΠΈΡ… Π΄Π° създам опростСно микросСрвисно ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΠ΅Ρ‚ΠΎ впослСдствиС ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС "ΠΎΠ±ΠΎΠ³Π°Ρ‚Π΅Π½ΠΎ" с всСвъзмоТни интСрСсни Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ. ΠžΡΠ½ΠΎΠ²Π½ΠΎΡ‚ΠΎ изискванС към ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π΅ максималната Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»Π½Π° близост Π΄ΠΎ Ρ€Π΅Π°Π»Π½Π° систСма.

ΠŸΡŠΡ€Π²ΠΎΠ½Π°Ρ‡Π°Π»Π½ΠΎ Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ… ΡΡŠΠ·Π΄Π°Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π½Π° няколко ΡΡ‚ΡŠΠΏΠΊΠΈ:

  1. БъздаванС Π½Π° Π΄Π²Π΅ услуги – β€˜Π±Π΅ΠΊΠ΅Π½Π΄β€™ (backend) ΠΈ β€˜ΡˆΠ»ΡŽΠ·β€™ (gateway), ΠΎΠΏΠ°ΠΊΠΎΠ²Π°Π½Π΅ Π² docker ΠΎΠ±Ρ€Π°Π·ΠΈ ΠΈ настройка Π½Π° тяхната ΡΡŠΠ²ΠΌΠ΅ΡΡ‚Π½Π° Ρ€Π°Π±ΠΎΡ‚Π°

    ΠšΠ»ΡŽΡ‡ΠΎΠ²ΠΈ Π΄ΡƒΠΌΠΈ: Java 11, Spring Boot, Docker, оптимизация Π½Π° изобраТСния

  2. Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π° конфигурация Π·Π° Kubernetes ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠΉ Π½Π° систСмата Π² Google Kubernetes Engine

    ΠšΠ»ΡŽΡ‡ΠΎΠ²ΠΈ Π΄ΡƒΠΌΠΈ: Kubernetes, GKE, ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° рСсурси, Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ ΠΌΠ°Ρ‰Π°Π±ΠΈΡ€Π°Π½Π΅, Ρ‚Π°ΠΉΠ½ΠΈ

  3. БъздаванС Π½Π° Ρ‡Π°Ρ€Ρ‚ с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° Helm 3 Π·Π° ΠΏΠΎ-Π΅Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° ΠΊΠ»ΡŠΡΡ‚Π΅Ρ€Π°

    ΠšΠ»ΡŽΡ‡ΠΎΠ²ΠΈ Π΄ΡƒΠΌΠΈ: Helm 3, Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Π½Π΅ Π½Π° Ρ‡Π°Ρ€Ρ‚

  4. Настройка Π½Π° Jenkins ΠΈ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ Π·Π° Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ доставянС Π½Π° ΠΊΠΎΠ΄Π° Π² ΠΊΠ»ΡŠΡΡ‚Π΅Ρ€Π°

    ΠšΠ»ΡŽΡ‡ΠΎΠ²ΠΈ Π΄ΡƒΠΌΠΈ: конфигурация Π½Π° Jenkins, плъгини, ΠΎΡ‚Π΄Π΅Π»Π΅Π½ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Π·Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ

На всяка ΡΡ‚ΡŠΠΏΠΊΠ° ΠΏΠ»Π°Π½ΠΈΡ€Π°ΠΌ Π΄Π° посвСтя ΠΎΡ‚Π΄Π΅Π»Π½Π° статия.

Π¦Π΅Π»Ρ‚Π° Π½Π° Ρ‚ΠΎΠ·ΠΈ Ρ†ΠΈΠΊΡŠΠ» статии Π½Π΅ Π΅ ΠΊΠ°ΠΊ Π΄Π° напишСм микросСрвизи, Π° ΠΊΠ°ΠΊ Π΄Π° Π³ΠΈ Π½Π°ΠΊΠ°Ρ€Π°ΠΌΠ΅ Π΄Π° работят Π² Π΅Π΄ΠΈΠ½Π½Π° систСма. Π’ΡŠΠΏΡ€Π΅ΠΊΠΈ Ρ‡Π΅ всичко Ρ‚ΠΎΠ²Π° ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ ΠΏΠ°Π΄Π° извън отговорността Π½Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°, мисля, Ρ‡Π΅ Π΅ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ Π΄Π° бъдСш Π·Π°ΠΏΠΎΠ·Π½Π°Ρ‚ с тях ΠΏΠΎΠ½Π΅ Π½Π° 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

Π¨Π»ΡŽΠ·ΡŠΡ‚ Ρ‰Π΅ прСнасочва заявкитС към сСрвиза Π±Π΅ΠΊΠ΅Π½Π΄ ΠΈ Ρ‰Π΅ Π³ΠΈ допълва с информацията:

  • ΠΈΠ΄ Π½Π° шлюза. НСобходим Π΅, Π·Π° Π΄Π° ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈΡ‚Π΅ СкзСмпляри Π½Π° шлюза ΠΏΠΎ ΠΎΡ‚Π³ΠΎΠ²ΠΎΡ€Π° ΠΎΡ‚ ΡΡŠΡ€Π²ΡŠΡ€Π°
  • Някакъв "сСкрСт", ΠΊΠΎΠΉΡ‚ΠΎ Ρ‰Π΅ ΠΈΠ³Ρ€Π°Π΅ роля Π½Π° ΠΌΠ½ΠΎΠ³ΠΎ Π²Π°ΠΆΠ½Π° ΠΏΠ°Ρ€ΠΎΠ»Π° (β„– Π½Π° ΠΊΠ»ΡŽΡ‡Π° Π·Π° ΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°Π½Π΅ Π½Π° Π²Π°ΠΆΠ½Π° бисквитка)

ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ Π² 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 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("Π‘Ρ€ΠΎΠΉ заявки %s (Π³Π΅ΠΉΡ‚ΡƒΠ΅ΠΉ %d, сСкрСт %s)", backendAdapter.getRequests(), instanceId, secret);
    }
}

Π‘Ρ‚Π°Ρ€Ρ‚ΠΈΡ€Π°Π½Π΅:

Π‘Ρ‚Π°Ρ€Ρ‚ΠΈΡ€Π°ΠΌΠ΅ Π±Π΅ΠΊΠ΅Π½Π΄Π°:

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

Π‘Ρ‚Π°Ρ€Ρ‚ΠΈΡ€Π°ΠΌΠ΅ шлюза:

./mvnw ΠΏΠ°ΠΊΠ΅Ρ‚ -DskipTests
java -jar target/microservices-gateway-1.0.0.jar

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ²Π°ΠΌΠ΅:

$ curl http://localhost:8080/
Π‘Ρ€ΠΎΠΉ заявки 1 (gateway 38560358, сСкрСт "default-secret")

Всичко Ρ€Π°Π±ΠΎΡ‚ΠΈ. ВниматСлният Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π» Ρ‰Π΅ ΠΎΡ‚Π±Π΅Π»Π΅ΠΆΠΈ, Ρ‡Π΅ Π½ΠΈΡ‰ΠΎ Π½Π΅ Π½ΠΈ ΠΏΡ€Π΅Ρ‡ΠΈ Π΄Π° сС ΠΎΠ±ΡŠΡ€Π½Π΅ΠΌ към Π±Π΅ΠΊΠ΅Π½Π΄Π° Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ, заобикаляйки шлюза (http://localhost:8081/requests). Π—Π° Π΄Π° Π³ΠΎ ΠΏΠΎΠΏΡ€Π°Π²ΠΈΠΌ, услугитС трябва Π΄Π° Π±ΡŠΠ΄Π°Ρ‚ ΠΎΠ±Π΅Π΄ΠΈΠ½Π΅Π½ΠΈ Π² Π΅Π΄Π½Π° ΠΌΡ€Π΅ΠΆΠ°, Π° навън "Π΄Π° ΡΡ‚ΡŠΡ€Ρ‡ΠΈ" само ΡˆΠ»ΡŽΠ·ΡŠΡ‚.
Π‘ΡŠΡ‰ΠΎ Ρ‚Π°ΠΊΠ° ΠΈ Π΄Π²Π°Ρ‚Π° ΡΡŠΡ€Π²ΠΈΡΠ° сподСлят Π΅Π΄Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π° систСма, ΠΌΠ½ΠΎΠΆΠ°Ρ‚ ΠΏΠΎΡ‚ΠΎΡ†ΠΈ ΠΈ Π² Π΅Π΄ΠΈΠ½ ΠΌΠΎΠΌΠ΅Π½Ρ‚ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° Π·Π°ΠΏΠΎΡ‡Π½Π°Ρ‚ Π΄Π° сС ΠΏΡ€Π΅Ρ‡Π°Ρ‚ Π΅Π΄ΠΈΠ½ Π½Π° Π΄Ρ€ΡƒΠ³. Налага сС Π΄Π° ΠΈΠ·ΠΎΠ»ΠΈΡ€Π°ΠΌΠ΅ Π½Π°ΡˆΠΈΡ‚Π΅ микросСрвиси. Π’ΠΎΠ²Π° ΠΌΠΎΠΆΠ΅ Π΄Π° сС постигнС Ρ‡Ρ€Π΅Π· разпрСдСлянС Π½Π° прилоТСнията Π½Π° Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ машини (ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠ°Ρ€ΠΈ, слоТно), ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»Π½ΠΈ машини (рСсурсоСмко, дълъг старт) ΠΈΠ»ΠΈ Ρ‡Ρ€Π΅Π· контСйнСризация. ΠžΡ‡Π°ΠΊΠ²Π°Π½ΠΎ ΠΈΠ·Π±ΠΈΡ€Π°ΠΌΠ΅ трСтия Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΈ Docker ΠΊΠ°Ρ‚ΠΎ инструмСнт Π·Π° контСйнСризация.

Docker

Накратко, Docker създава ΠΈΠ·ΠΎΠ»ΠΈΡ€Π°Π½ΠΈ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΈ, ΠΏΠΎ Π΅Π΄ΠΈΠ½ Π·Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. Π—Π° Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ Docker, трябва Π΄Π° Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Dockerfile β€” инструкция Π·Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ ΠΈ пусканС Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ. Π‘Π»Π΅Π΄ Ρ‚ΠΎΠ²Π° Ρ‰Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΈΠ·Π³Ρ€Π°Π΄ΠΈΡ‚Π΅ ΠΎΠ±Ρ€Π°Π·, Π΄Π° Π³ΠΎ ΠΊΠ°Ρ‡ΠΈΡ‚Π΅ Π² Ρ€Π΅Π³ΠΈΡΡ‚ΡŠΡ€ Π·Π° ΠΎΠ±Ρ€Π°Π·ΠΈ (β„– DockerHub) ΠΈ с Π΅Π΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π° Π΄Π° Ρ€Π°Π·Π²Π΅Ρ€Π½Π΅Ρ‚Π΅ своя микросСрвис Π² ΠΎΠΊΠΎΠ»Π½Π°Ρ‚Π° срСда с Docker.

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 сигнализира Π½Π° Docker, Ρ‡Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° Ρ‰Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° нСговия ΠΏΠΎΡ€Ρ‚ 8080 (Ρ‚ΠΎΠ²Π° Π½Π΅ ΠΏΡ€Π°Π²ΠΈ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ Π΄ΠΎΡΡ‚ΡŠΠΏΠ½ΠΎ навън, Π½ΠΎ Ρ‰Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈ Π΄ΠΎΡΡ‚ΡŠΠΏ Π΄ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ Π² ΡΡŠΡ‰Π°Ρ‚Π° ΠΌΡ€Π΅ΠΆΠ° Π½Π° Docker).

Π—Π° Π΄Π° ΠΎΠΏΠ°ΠΊΠΎΠ²Π°Ρ‚Π΅ услугитС Π² ΠΎΠ±Ρ€Π°Π·ΠΈ, трябва Π΄Π° ΠΈΠ·ΠΏΡŠΠ»Π½ΠΈΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄ΠΈΡ‚Π΅ ΠΎΡ‚ ΠΊΠΎΡ€Π΅Π½Π° Π½Π° всСки ΠΏΡ€ΠΎΠ΅ΠΊΡ‚:

docker image build . -t msvc-backend:1.0.0

Π’ Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π°Π²Π°ΠΌΠ΅ ΠΎΠ±Ρ€Π°Π· с Ρ€Π°Π·ΠΌΠ΅Ρ€ 456 ΠœΠ±Π°ΠΉΡ‚Π° (ΠΎΡ‚ ΠΊΠΎΠΈΡ‚ΠΎ основният ΠΎΠ±Ρ€Π°Π· JDK Π·Π°Π΅ ΠœΠ±Π°ΠΉΡ‚Π°). И всичко Ρ‚ΠΎΠ²Π°, ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‡Π΅ класовСтС Π² нашия ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° сС прСброят Π½Π° ΠΏΡ€ΡŠΡΡ‚ΠΈΡ‚Π΅ Π½Π° Π΅Π΄Π½Π°Ρ‚Π° Ρ€ΡŠΠΊΠ°. Π—Π° Π΄Π° Π½Π°ΠΌΠ°Π»ΠΈΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€Π° Π½Π° нашия ΠΎΠ±Ρ€Π°Π·:

  • ИзползвамС многостСпСнна компилация. На ΠΏΡŠΡ€Π²Π°Ρ‚Π° ΡΡ‚ΡŠΠΏΠΊΠ° Ρ‰Π΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€Π°ΠΌΠ΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, Π½Π° Π²Ρ‚ΠΎΡ€Π°Ρ‚Π° Ρ‰Π΅ инсталирамС 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

ΠŸΡŠΡ€Π²ΠΎ Π½Π°ΡˆΠΈΡ‚Π΅ услуги трябва Π΄Π° Π±ΡŠΠ΄Π°Ρ‚ Π² Π΅Π΄Π½Π° ΠΌΡ€Π΅ΠΆΠ°. Π’ 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 ΠΌΡ€Π΅ΠΆΠ°Ρ‚Π° прСдоставя Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ ΠΎΡ‚ΠΊΡ€ΠΈΠ²Π°Π½Π΅ Π½Π° услуги Π·Π° ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΠΎ Ρ‚Π΅Ρ…Π½ΠΈΡ‚Π΅ ΠΈΠΌΠ΅Π½Π°. ВоСст, услугата Π±Π΅ΠΊΠ΅Π½Π΄ Ρ‰Π΅ бъдС Π΄ΠΎΡΡ‚ΡŠΠΏΠ½Π° Π²ΡŠΡ‚Ρ€Π΅ Π² Docker ΠΌΡ€Π΅ΠΆΠ°Ρ‚Π° Π½Π° адрСс 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 ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ Π·Π° Π·Π°Π΄Π°Π²Π°Π½Π΅ Π½Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата, ΠΊΠΎΠΈΡ‚ΠΎ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ Ρ‰Π΅ Π±ΡŠΠ΄Π°Ρ‚ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ΠΈ ΠΎΡ‚ Spring ΠΈ Ρ‰Π΅ замСстят свойствата ΠΎΡ‚ application.properties.

Π‘Π»Π΅Π΄ стартиранС ΠΈΠ·Π²ΠΈΠΊΠ²Π°ΠΌΠ΅ http://localhost/ ΠΈ сС увСрявамС, Ρ‡Π΅ всичко Ρ€Π°Π±ΠΎΡ‚ΠΈ, ΠΊΠ°ΠΊΡ‚ΠΎ Π² ΠΏΡ€Π΅Π΄ΠΈΡˆΠ½ΠΈΡ случай.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

Π’ ΠΊΡ€Π°ΠΉΠ½Π° смСтка ΡΡŠΠ·Π΄Π°Π΄ΠΎΡ…ΠΌΠ΅ Π΄Π²Π° опростСни микросСрвиза, ΠΎΠΏΠ°ΠΊΠΎΠ²Π°Ρ…ΠΌΠ΅ Π³ΠΈ Π² Docker ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΈ ΠΈ Π³ΠΈ стартирахмС ΡΡŠΠ²ΠΌΠ΅ΡΡ‚Π½ΠΎ Π½Π° Π΅Π΄Π½Π° машина. Π’ΡŠΠΏΡ€Π΅ΠΊΠΈ Ρ‚ΠΎΠ²Π°, ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π°Ρ‚Π° систСма ΠΈΠΌΠ° Ρ€Π΅Π΄ Π½Π΅Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ†ΠΈ:

  • Π›ΠΎΡˆΠ° отказоустойчивост β€” всичко Ρ€Π°Π±ΠΎΡ‚ΠΈ Π½Π° Π΅Π΄ΠΈΠ½ ΡΡŠΡ€Π²ΡŠΡ€
  • Π›ΠΎΡˆΠ° мащабируСмост β€” ΠΏΡ€ΠΈ ΡƒΠ²Π΅Π»ΠΈΡ‡Π°Π²Π°Π½Π΅ Π½Π° Π½Π°Ρ‚ΠΎΠ²Π°Ρ€Π²Π°Π½Π΅Ρ‚ΠΎ Π±ΠΈ Π±ΠΈΠ»ΠΎ Π΄ΠΎΠ±Ρ€Π΅ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π½ΠΎ Π΄Π° сС Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Ρ‚ Π΄ΠΎΠΏΡŠΠ»Π½ΠΈΡ‚Π΅Π»Π½ΠΈ СкзСмпляри Π½Π° услугитС ΠΈ Π΄Π° сС балансира Π½Π°Ρ‚ΠΎΠ²Π°Ρ€Π²Π°Π½Π΅Ρ‚ΠΎ ΠΌΠ΅ΠΆΠ΄Ρƒ тях
  • БлоТност Π½Π° стартиранС β€” Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ бСшС Π΄Π° въвСдСм ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ 3 ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ, с ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ (Ρ‚ΠΎΠ²Π° само Π·Π° 2 услуги)

Π—Π° Ρ€Π΅ΡˆΠ°Π²Π°Π½Π΅ Π½Π° горСпосочСнитС ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ ΡΡŠΡ‰Π΅ΡΡ‚Π²ΡƒΠ²Π°Ρ‚ Ρ€Π΅Π΄ΠΈΡ†Π° Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ, ΠΊΠ°Ρ‚ΠΎ Docker Swarm, Nomad, Kubernetes ΠΈΠ»ΠΈ OpenShift. Ако цялата систСма Π΅ написана Π½Π° Java, ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ Spring Cloud (Π΄ΠΎΠ±Ρ€Π° статия).

Π’ слСдващата част Ρ‰Π΅ Ρ€Π°Π·ΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π°Ρ… Kubernetes ΠΈ Π΄Π΅ΠΏΠ»ΠΎΠΉΠ²Π°Ρ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π² Google Kubernetes Engine.

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС с Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ πŸ”₯ ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС с Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ | ProHoster