QuarkusSeniorCoding

Как собрать нативный исполняемый файл Quarkus и каковы ограничения нативной компиляции?

Нативный бинарник собирается командой ./mvnw package -Pnative или с флагом -Dquarkus.native.container-build=true (без локального GraalVM). Ограничения: нет полной рефлексии, нет динамических прокси без регистрации, долгая сборка, нет Java agents.

Сборка нативного исполняемого файла Quarkus

Предварительные требования

Вариант 1 — локальный GraalVM:

sdk install java 21.0.3-graalce
java -version
# OpenJDK 64-Bit GraalVM CE 21.0.3+7

Вариант 2 — container build (рекомендуется для CI):

# Docker или Podman должны быть доступны
docker info

Команды сборки

# Локальный GraalVM
./mvnw package -Pnative

# Через Docker (использует quay.io/quarkus/ubi-quarkus-native-image)
./mvnw package -Pnative \
  -Dquarkus.native.container-build=true \
  -Dquarkus.native.container-runtime=docker

# Для ARM (Apple Silicon, Graviton)
./mvnw package -Pnative \
  -Dquarkus.native.container-build=true \
  -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:22.3-java17-aarch64

# Результат
./target/app-1.0.0-SNAPSHOT-runner

Dockerfile для нативного образа

FROM quay.io/quarkus/ubi-quarkus-native-image:22.3-java21 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -Pnative -Dquarkus.native.container-build=false

FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /app
COPY --from=build /app/target/*-runner /app/application
EXPOSE 8080
USER 1001
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

Настройка через application.properties

# Heap для native-image процесса (не приложения)
quarkus.native.native-image-xmx=8g

# Включить отладочные символы (для perf)
quarkus.native.debug.enabled=false

# Дополнительные флаги GraalVM
quarkus.native.additional-build-args=\
    -H:+ReportExceptionStackTraces,\
    --initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG

# Уровень оптимизации (O3 медленнее собирается)
quarkus.native.optimization-level=2

Ограничения нативной компиляции

1. Рефлексия

// Нужна явная регистрация
@RegisterForReflection(targets = {MyDto.class, AnotherDto.class})
public class ReflectionConfig {}

// Или через META-INF/native-image/reflect-config.json
// (генерируется агентом GraalVM: -agentlib:native-image-agent)

2. Динамические прокси

@RegisterForProxy(interfaces = {MyService.class})
public class ProxyConfig {}

3. Ресурсные файлы

# Включить ресурсы в бинарник
quarkus.native.resources.includes=templates/**,messages/*.properties

4. Диагностика с GraalVM Agent

# Запустить приложение с агентом для генерации конфигов рефлексии
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image \
  -jar target/quarkus-app/quarkus-run.jar
# Прогнать тесты/запросы, затем остановить — агент сгенерирует json-файлы

Подводные камни

  • Static initializer порядок — код в static-блоках, обращающийся к env vars или сети, выполняется во время сборки, а не запуска; используйте --initialize-at-run-time.
  • Сторонние библиотеки — не все библиотеки имеют native-совместимые конфиги; проверяйте https://quarkus.io/guides/native-reference перед добавлением зависимости.
  • Время сборки в CI — без кэширования слоёв Docker каждая сборка занимает 5–15 минут; кэшируйте ~/.m2 и Docker-слои в GitHub Actions/GitLab CI.
  • Кросс-компиляция — бинарник собранный на x86_64 не запустится на ARM без rebuild; используйте QEMU-эмуляцию или нативный ARM-runner в CI.
  • java.lang.Thread и virtual threads — Project Loom virtual threads в native поддерживаются с GraalVM 21+, но не все библиотеки с ними совместимы.
  • Нет JVM flags в runtime — -Xmx, -XX:+UseG1GC не применимы; управление памятью через -R:MaxHeapSize=256m при сборке или через env MALLOC_ARENA_MAX.
  • Log4j/Logback в native — нужны дополнительные рефлексионные конфиги; Quarkus рекомендует jboss-logmanager (встроен).

Common mistakes

  • Путать термин «native executable build» с соседним механизмом Quarkus.
  • Не называть границу lifecycle, transaction, thread или request для «native executable build».
  • Игнорировать production-эффекты «native executable build»: latency, SQL shape, memory, security или observability.

What the interviewer is testing

  • Попросить объяснить механизм «native executable build» на минимальном примере.
  • Проверить, видит ли кандидат failure mode и диагностику для «native executable build».
  • Уточнить, какие настройки или API меняют «native executable build» в реальном сервисе.

Sources

Related topics