В этом быстро меняющемся мире мы, разработчики, должны быстро разрабатывать, быстро доставлять, и наше приложение должно запускаться и работать быстро.

Что такое Кваркус?

Quarkus — это проект с открытым исходным кодом под лицензией Apache License version 2.0. Он был создан, чтобы позволить разработчикам Java создавать приложения для современного облачного мира. Quarkus — это нативная платформа Java для Kubernetes, адаптированная для GraalVM и HotSpot с библиотеками и стандартами Java. Вы можете узнать больше об этом здесь на их официальной странице документации.

Цель состоит в том, чтобы облегчить нашу жизнь, обратившись к более широкому спектру архитектур распределенных приложений, включая Kubernetes и бессерверные среды.

Наша цель:

Мы создадим простое приложение с предоставлением REST API для пользовательского ресурса. Мы увидим, как получить быструю обратную связь в процессе разработки и как мы развернем ее в контейнерах, используя как openjdk, так и собственный образ.

Начнем с кода. В случае возникновения вопросов не стесняйтесь обращаться к нам или оставлять комментарии. Я поделюсь URL-адресом кода репозитория github, используемого в этом примере, в конце этой истории.

Предпосылки

  1. Java 11 или выше
  2. Грейдл или Мейвен
  3. Докер или Кубернетес

Я буду использовать Java 17, Gradle 7.4 и Quarkus 2.7. Также я буду использовать IntelliJ IDEA в качестве IDE. Вы можете использовать свою любимую конфигурацию с вашей IDE.

Начнем с создания нового проекта с помощью https://code.quarkus.io. Мы добавим [quarkus-resteasy] и [quarkus-resteasy-jackson] в качестве зависимостей и настроим детали проекта. Вы можете напрямую получить конфигурации, используемые в этом примере, щелкнув здесь.
Это должно выглядеть примерно так:

Теперь нажмите «Создать приложение», а затем «загрузите ZIP-файл». Он загрузит сгенерированный проект на ваш компьютер, распакует его и откроет в вашей среде IDE.

Мы видим, что в проекте уже есть пример стартового кода. Мы удалим исходный код и тестовый класс и запустим наш код, просто для свежего взгляда.

Давайте начнем с написания тестовых случаев, а затем напишем код. Мы будем следовать практике TDD, нажмите здесь, чтобы узнать больше о TDD.

Спецификация API

Мы создадим только операции CRUD:
[GET] /users : Получить всех пользователей
[GET] /users/{userId} : Получить пользователя по идентификатору пользователя
[POST] / пользователи : добавить нового пользователя
[PUT] /users/{userId} : обновить существующего пользователя
[DELETE] /users/{userId} : удалить пользователя по идентификатору пользователя

Для простоты мы пишем наши тесты по порядку, чтобы сначала он создавал, потом получал и, наконец, удалял.

Код тестового класса:

private User user;

@Inject
private UserRepository userRepository;

@BeforeAll
void init() {
    user = new User(1, "John", "Doe");
}
@Test
@Order(1)
public void testAddNewUser_Get201Response() {
    given()
            .body(user)
            .contentType(ContentType.JSON)
            .when().post("/users")
            .then()
            .statusCode(201)
            .body("firstName", is(user.getFirstName()))
            .body("lastName", is(user.getLastName()));
}

Код класса реализации:

@Inject
private UserRepository userRepository;

@POST
public Response addNewUser(User user) {
    User resUser = userRepository.addNewUser(user);
    return Response.created(URI.create("/users/"+resUser.getUserId())).entity(resUser).build();
}

Мы можем выполнить тестовые примеры, а затем исправить наш код реализации, чтобы получить окончательный результат. В конце должно получиться примерно так:

Чтобы включить режим разработки, мы откроем наш терминал по этому пути и выполним следующую команду: './gradlew quarkusDev'
Оно должно запустить наше приложение в режиме разработки, и мы должны иметь доступ к нему с помощью нашего браузера и почтальона через порт по умолчанию 8080. Вам не нужно завершать и запускать приложение каждый раз, когда вы вносите изменения, оно будет автоматически повторно развертывать ваши изменения.
Quarkus также предоставляет панель управления, где мы можем динамически настраивать свойства нашего приложения и получать всю информацию о нашей информации. Просто зайдите в браузер и нажмите: http://localhost:8080. Мы должны получить что-то вроде этого:

Развертывание

Теперь давайте создадим развертываемый jar-файл и попробуем запустить его. Выполните следующую команду, чтобы создать сборочный jar-файл './gradlew build'
. Теперь выполните следующую команду, чтобы запустить эту сборку 'java -jar build/quarkus-app/quarkus-run.jar'

Мы видим, что оно может запуститься за считанные секунды, теперь вы можете получить доступ к этому приложению в браузере.

Теперь давайте создадим образ докера и развернем его в контейнере. В нашем коде уже есть каталог docker в src/main/docker, и он содержит несколько файлов Dockerfile для создания разных типов изображений. Это функция OOTB генератора кода quarkus.

Мы уже создали сборку на последнем шаге, теперь мы выполним следующую команду для создания образа Docker:
docker build -f src/main/docker/Dockerfile.jvm -t quarkus-demo-jvm .

Теперь мы запустим это в нашем контейнере Docker с помощью следующей команды:
docker run -i — rm -p 8080:8080 quarkus-demo-jvm

Мы также можем увидеть использование ресурсов, используя следующие команды «docker stats».

Мы видим, что он также использует очень мало памяти даже в ненативном режиме, мы можем создать собственный образ и запустить его. Это будет намного быстрее, а использование ресурсов будет меньше.

Развертывание в собственном режиме

Теперь попробуем создать нативный образ и запустить его в контейнере. Для этого нам сначала нужно создать собственную сборку, а затем создать образ докера для ее запуска.
Если у вас установлен собственный образ, вы можете выполнить следующую команду, чтобы создать сборку './gradlew build -Dquarkus. package.type=native' или вы можете запустить следующую команду, чтобы создать сборку './gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true'
Создание нативной сборки займет некоторое время, пожалуйста, идите и выпейте кофе :-P

Совет. Если вы получаете какую-либо ошибку, связанную с памятью Docker, попробуйте увеличить выделение памяти Docker до 8 ГБ и добавить этот параметр "-Dquarkus.native.native-image-xmx=8g', а в случае проблемы, связанной с версией Java 17, добавьте следующую опцию '-Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:21.3-java17' . Для меня у меня возникли обе проблемы, поэтому я выполнил следующую команду './gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true -Dquarkus.native.native-image-xmx=8g - Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:21.3-java17'

Вы можете запустить этот собственный исполняемый файл, используя следующую команду ./build/quarkus-demo-1.0.0-SNAPSHOT-runner’.

Теперь мы создадим собственный образ Docker и запустим его в контейнере, выполнив следующую команду для создания образа Docker:
docker build -f src/main/docker/Dockerfile.native -t quarkus-demo-native .

Давайте запустим это приложение в док-контейнере и проверим использование ресурсов, выполнив следующую команду:
docker run -i — rm -p 8080:8080 quarkus-demo-native

Мы видим, что наше приложение запустилось за 37 мс и занимает всего 4,6 МБ памяти, что очень мало для Java-приложения. Также производительность этого приложения очень хорошая.

Заключение

Мы разработали простой REST API с использованием Java, Gradle и Quarkus. Мы успешно выполнили сборку, а также развернули ее в док-контейнере как в обычном, так и в собственном режиме.
Это решает многие проблемы, особенно в бессерверной среде. Теперь мы можем развернуть наши Java-приложения на AWS Lambda, Azure Functions или даже использовать их с Kubernetes KEDA. В следующей статье я напишу о развертывании приложения Quarkus в Kubernetes и использовании KEDA для развертывания без подов.
Вы можете найти код этого примера в этом репозитории github здесь.