[Перевод] Ускоряем запуск Spring Boot-приложений в контейнере

6bea8185f8981e5fda7afaa5f4bd65f0.jpeg

Знаете ли вы, что Spring Boot-приложение в контейнере может запускаться за миллисекунды? При этом без ущерба для производительности, памяти, паритета окружений разработки-продакшена, без ограничений возможностей языка Java, и почти без изменения кода приложения. Но как? С помощью Liberty 23.0.0.10-beta…

Liberty InstantOn

Функциональность InstantOn в Open Liberty использует IBM Semeru JDK и технологию Linux Checkpoint/Restore in Userspace (CRIU), позволяющую во время выполнения делать снимки состояния процесса (снапшоты, контрольные точки). Впоследствии состояние очень быстро восстанавливается и работа возобновляется. Восстановить приложение можно несколько раз, поскольку Open Liberty и Semeru JDK сохраняют уникальность каждого восстановленного процесса в контейнере. После восстановления состояния процессу нет необходимости выполнять инициализацию при запуске, что экономит до 90% времени старта (зависит от вашего приложения). Использование InstantOn требует незначительных изменений вашего Java-приложения.

Подробнее о Liberty InstantOn см. в статье How to package your cloud-native Java application for rapid startup и в разделе Faster startup for containerized applications with Open Liberty InstantOn документации Open Liberty.

Поддержка checkpoint/restore в Spring Boot

В Spring Framework 6.1 будет реализована интеграция с JVM checkpoint/restore с помощью проекта org.crac, что позволит ускорить запуск приложений. В Liberty InstantOn версии 23.0.0.10-beta для получения реализации org.crac API нужно добавить функциональный модуль (feature) crac-1.3. Это позволит развертывать Spring-приложения, включая Spring Boot, с помощью Liberty InstantOn.

Production-ready образы контейнеров Liberty

Образы контейнеров для всех новых релизов Liberty создаются на основе Universal Base Image и загружаются в репозиторий IBM Container Registry. Образ Liberty UBI с версии Liberty 23.0.0.6 включает необходимые компоненты для создания контрольных точек приложения с помощью Liberty InstantOn. А с версии 23.0.0.10-beta — также и для Spring Boot 3.2.

Образы Liberty упрощают разработку InstantOn-приложений, готовых к развертыванию в продакшене. Важное преимущество Liberty InstantOn — возможность создавать контрольные точки процесса приложения внутри контейнера без необходимости запуска приложения в контейнере под root, что важно с точки зрения безопасности. Это также позволяет развертывать ваши InstantOn-образы в облачных сервисах Kubernetes, таких как AWS EKS и Azure EKS.

Пример приложения на Spring Boot 3.2.0 с использованием Liberty InstantOn

В этом примере используются материалы туториала Containerizing, packaging, and running a Spring Boot application. Самый простой способ начать работу — клонировать ветку cracSpringBoot из github-репозитория с примером:

git clone --branch cracSpringBoot https://github.com/openliberty/guide-spring-boot.git
cd guide-spring-boot/finish

В ветке cracSpringBoot используются более новые версии Open Liberty и Spring Boot, поддерживающие org.crac для Spring Boot-приложений. Понадобится Java 17 или более поздняя версия. 

Для сборки приложения запустим mvnw в папке finish.

./mvnw package

Далее будем контейнеризовать наше приложение. Мы обратим внимание только на изменения в контейнеризации, связанные с Liberty InstantOn. Подробнее о лучших практиках контейнеризации Spring Boot-приложений с Open Liberty см. в руководстве Containerizing, packaging, and running a Spring Boot application.

Для создания образа приложения, использующего InstantOn, необходимо либо запустить привилегированный контейнер, либо предоставить инструменту сборки образов необходимые Linux capabilities, позволяющие создавать контрольные точки.

Включение сrac-1.3 в Liberty

В Liberty мы можем выбрать только необходимые нам компоненты. Для использования org.crac в Liberty, необходимо в конфигурацию Liberty добавить crac-1.3. В данном случае можно скопировать файл src/main/liberty/config/crac.xml в образ контейнера с помощью следующей команды в Dockerfile:

COPY src/main/liberty/config/crac.xml /config/configDropins/defaults

Включаем crac-1.3 в файле crac.xml конфигурации Liberty:




    
        crac-1.3
    

Сборка образа с помощью Podman

Podman позволяет при сборке образа указать Linux capabilities, необходимые  для создания контрольной точки приложения, что позволит запустить checkpoint.sh с помощью команды RUN в Dockerfile. Это последняя инструкция в Dockerfile.podman:

...
RUN configure.sh
RUN checkpoint.sh afterAppStart

Для сборки образа используем следующую команду с указанием необходимых capabilities:

sudo podman build \
  -f Dockerfile.podman \
  -t springboot \
  --cap-add=CHECKPOINT_RESTORE \
  --cap-add=SYS_PTRACE\
  --cap-add=SETPCAP \
  --security-opt seccomp=unconfined .

Также вы можете запустить скрипт scripts/build-instanton-podman.sh из примеров.

Последний этап сборки образа — запуск checkpoint.sh с параметром afterAppStart. В результате контрольная точка создается после запуска приложения. О других вариантах создания контрольной точки смотрите в документации.

При запуске приложения вы увидите следующий результат:

[AUDIT   ] CWWKZ0001I: Application thin-guide-spring-boot-0.1.0 started in 3.880 seconds.
[AUDIT   ] CWWKC0451I: A server checkpoint "afterAppStart" was requested. When the checkpoint completes, the server stops.
2023-09-06T21:06:18.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping Spring-managed lifecycle beans before JVM checkpoint
2023-09-06T21:06:18.767Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147483647
2023-09-06T21:06:18.768Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Bean 'applicationTaskExecutor' completed its stop procedure
2023-09-06T21:06:18.769Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147482623
2023-09-06T21:06:18.771Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Bean 'webServerGracefulShutdown' completed its stop procedure
2023-09-06T21:06:18.771Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147481599
2023-09-06T21:06:18.796Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Bean 'webServerStartStop' completed its stop procedure
2023-09-06T21:06:18.796Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase -2147483647
2023-09-06T21:06:18.797Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Bean 'springBootLoggingLifecycle' completed its stop procedure
[2/2] COMMIT springboot

По логам видно, что приложение останавливалось для создания контрольной точки. Теперь у вас есть образ контейнера приложения под названием springboot.

Сборка образа с помощью Docker

В настоящее время Docker не позволяет при сборке образа указать Linux capabilities. По этой причине мы не можем запустить checkpoint.sh при выполнении docker build. Вместо этого будем использовать трехэтапную сборку образа:

  1. Соберем образ без слоя InstantOn.

  2. Запустим из полученного образа контейнер и создадим контрольную точку приложения.

  3. Сохраним контейнер с контрольной точкой в новый InstantOn-образ с помощью commit.

Выполните эти три этапа сборки, запустив скрипт scripts/build-instanton-docker.sh. Вывод при сборке через Docker похож на вывод Podman. В логе вы увидите сообщения от lifecycle-бинов. 

Запуск приложения

И Podman, и Docker используют одинаковые параметры для запуска:

Файлы run-instanton-podman.sh и run-instanton-docker.sh:

[sudo podman or docker] run \
  --rm \
  -p 9080:9080 \
  --cap-add=CHECKPOINT_RESTORE \
  --cap-add=SETPCAP \
  --security-opt seccomp=unconfined \
  springboot

Для запуска можно использовать данную команду или один из скриптов: scripts/run-instanton-podman.sh или scripts/run-instanton-docker.sh.

При запуске вы увидите следующий вывод:

[AUDIT   ] Launching defaultServer (Open Liberty 23.0.0.10-beta/wlp-1.0.81.cl230920230904-1158) on Eclipse OpenJ9 VM, version 17.0.7+7 (en_US)
2023-09-07T15:22:52.683Z  INFO 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Restarting Spring-managed lifecycle beans after JVM restore
2023-09-07T15:22:52.684Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase -2147483647
2023-09-07T15:22:52.684Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Successfully started bean 'springBootLoggingLifecycle'
2023-09-07T15:22:52.685Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147481599
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://e93ebe585ce3:9080/
2023-09-07T15:22:52.759Z  INFO 118 --- [ecutor-thread-1] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 106109 ms
2023-09-07T15:22:52.762Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Successfully started bean 'webServerStartStop'
2023-09-07T15:22:52.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147482623
2023-09-07T15:22:52.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Successfully started bean 'webServerGracefulShutdown'
2023-09-07T15:22:52.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147483647
2023-09-07T15:22:52.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Successfully started bean 'applicationTaskExecutor'
2023-09-07T15:22:52.764Z  INFO 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor  : Spring-managed lifecycle restart completed in 80 ms
[AUDIT   ] CWWKC0452I: The Liberty server process resumed operation from a checkpoint in 0.263 seconds.
[AUDIT   ] CWWKZ0001I: Application thin-guide-spring-boot-0.1.0 started in 0.265 seconds.
[AUDIT   ] CWWKF0012I: The server installed the following features: [crac-1.3, expressionLanguage-5.0, pages-3.1, servlet-6.0, springBoot-3.0, ssl-1.0, transportSecurity-1.0, websocket-2.1].
[AUDIT   ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.277 seconds.

Обратите внимание на последнее сообщение »… server started in 0.277 seconds». Время запуска 0,277 секунды включает в себя как время, необходимое criu для восстановления Java-процесса, так и время, необходимое Liberty для правильного восстановления runtime-состояния для безопасного запуска приложения после восстановления. В результате мы получили более чем десятикратное ускорение запуска по сравнению с исходными 5,5+ сек. без использования InstantOn.

Резюме

Open Liberty InstantOn представляет собой единую среду выполнения для развертывания облачных приложений с быстрым запуском. Liberty InstantOn можно использовать как с приложениями, использующими открытые стандарты, такими как Jakarta EE и MicroProfile, так и с приложениями на Spring, использующими последние версии Spring Boot и Spring Framework, в которых реализована поддержка org.crac

У Open Liberty есть следующие преимущества:

  • Доступ к полноценной платформе Java SE без каких-либо компромиссов. Для быстрого запуска нет необходимости изменять код приложения под окружение, как, например, при нативной компиляции.

  • Оптимизированный Liberty runtime обеспечивает высокую производительность и использует меньше памяти по сравнению с другими средами выполнения.

  • Расширенные возможности JIT-компиляции при развертывании в облаке (Semeru Cloud Compiler).

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

  • Использование production-ready образов Open Liberty позволяет придерживаться лучших практик по оптимизации и безопасности контейнеров, таких как отсутствие запуска приложения в контейнере от root и отказ от привилегированных контейнеров.

Образы InstantOn-приложений готовы к развертыванию в публичных облаках, таких как AWS EKS и Azure AKS. Быстрое время запуска, обеспечиваемое Liberty InstantOn, делает его идеальной платформой для создания бессерверных приложений, в том числе основанных на SpringBoot.

В заключение приглашаем всех желающих на открытое занятие «Разработка REST-клиентов на Spring», которое пройдет 14 ноября. Записаться можно на странице курса по Spring.

© Habrahabr.ru