Контейнеры
Контейнер — способ упаковать приложение вместе со всем, что нужно для запуска: Java, библиотеками, настройками. Образ (image) — шаблон контейнера, его собирают один раз и запускают где угодно: на ноутбуке, сервере, в Kubernetes. Самый распространённый инструмент — Docker. Quarkus готовит проект к контейнерам с первой минуты: генератор уже положил Dockerfile для разных вариантов сборки.
Готовые Dockerfile
| Файл | Что упаковывает |
|---|---|
src/main/docker/Dockerfile.jvm | Папку quarkus-app на JVM — основной вариант |
src/main/docker/Dockerfile.legacy-jar | Старый формат jar |
src/main/docker/Dockerfile.native | Нативный файл для Linux |
src/main/docker/Dockerfile.native-micro | Нативный файл на минимальном образе |
Главное из Dockerfile.jvm:
FROM registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]Базовый образ уже содержит Java 25. Папки quarkus-app копируются отдельными слоями: библиотеки в lib меняются редко, поэтому при пересборке Docker берёт этот слой из кеша. Приложение работает от пользователя 185, а не от администратора.
Сборка и запуск образа
Команды записаны в комментарии в начале того же файла:
./mvnw package
docker build -f src/main/docker/Dockerfile.jvm -t quarkus/blog-jvm .
docker run -i --rm -p 8080:8080 quarkus/blog-jvmСначала Maven собирает target/quarkus-app, затем Docker упаковывает его в образ quarkus/blog-jvm, и контейнер запускается с пробросом порта 8080. После запуска API доступно по тому же адресу http://localhost:8080/posts.
Для нативного варианта: ./mvnw package -Dnative -Dquarkus.native.container-build=true, затем docker build -f src/main/docker/Dockerfile.native -t quarkus/blog .. Такой образ стартует за миллисекунды и занимает заметно меньше места.
Настройки контейнера
Образ один для всех окружений, а различия передают переменными окружения через -e:
docker run -i --rm -p 8080:8080 \
-e BLOG_TITLE="Блог Анны" \
-e QUARKUS_DATASOURCE_JDBC_URL=jdbc:h2:mem:blog \
quarkus/blog-jvmЗдесь база H2 работает в памяти контейнера. В реальном проекте сюда передают адрес PostgreSQL, логин и пароль — и в образе не остаётся ни одного секрета.
Сборка образа без Dockerfile
Quarkus умеет собирать образ сам, как часть package. Для этого есть расширения container-image-docker, container-image-podman и container-image-jib (Jib собирает образ даже без установленного Docker):
./mvnw quarkus:add-extension -Dextensions="container-image-jib"
./mvnw package -Dquarkus.container-image.build=trueИмя образа берётся из groupId, artifactId и версии проекта; его можно поменять настройками quarkus.container-image.*. А расширение kubernetes дополнительно сгенерирует манифесты для Kubernetes с подключёнными проверками здоровья из урока о /q/health.
Частая ошибка
docker build не собирает Java-код — он только копирует готовую папку target/quarkus-app. Если забыть ./mvnw package или выполнить mvn clean перед сборкой образа, Docker сообщит, что не нашёл target/quarkus-app/lib. А если код изменился, но package не запускали, в образ попадёт старая версия. Всегда собирайте приложение перед docker build. Файл .dockerignore из генератора пропускает в Docker только папку target, поэтому исходники в образ не попадают.