The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Criando um executável nativo

Este guia inclui:

  • Compilar a aplicação para um executável nativo

  • Empacotar o executável nativo em um container

  • Debugando um executável nativo

Este guia utiliza como base a aplicação desenvolvida no Guia de Iniciação.

GraalVM

A criação de um executável nativo requer o uso de uma distribuição do GraalVM. Há três distribuições: Oracle GraalVM Community Edition (CE), Oracle GraalVM Enterprise Edition (EE) e Mandrel. As diferenças entre as distribuições Oracle e Mandrel são as seguintes:

  • O Mandrel é uma distribuição downstream do Oracle GraalVM CE. O principal objetivo do Mandrel é fornecer uma maneira de criar executáveis nativos projetados especificamente para dar suporte ao Quarkus.

  • As versões Mandrel são criadas a partir de uma base de código derivada da base de código do Oracle GraalVM CE, com apenas pequenas alterações, mas algumas exclusões significativas que não são necessárias para os aplicativos nativos do Quarkus. Eles suportam os mesmos recursos para criar executáveis nativos que o Oracle GraalVM CE, sem alterações significativas na funcionalidade. Notavelmente, eles não incluem suporte para programação poliglota. O motivo dessas exclusões é oferecer um melhor nível de suporte para a maioria dos usuários do Quarkus. Essas exclusões também significam que o Mandrel oferece uma redução considerável no tamanho de sua distribuição quando comparado ao Oracle GraalVM CE/EE.

  • O Mandrel foi desenvolvido de forma ligeiramente diferente do Oracle GraalVM CE, usando o projeto OpenJDK padrão. Isso significa que ele não se beneficia de alguns pequenos aprimoramentos que a Oracle adicionou à versão do OpenJDK usada para criar seus próprios downloads do GraalVM. Esses aprimoramentos são omitidos porque o OpenJDK upstream não os gerencia e não pode garantir eles. Isso é particularmente importante quando se trata de conformidade e segurança.

  • O Mandrel é recomendado para a criação de executáveis nativos voltados para ambientes em contêineres do Linux. Isso significa que os usuários do Mandrel são incentivados a usar contêineres para criar seus executáveis nativos. Se estiver criando executáveis nativos para o macOS, considere o uso do Oracle GraalVM, pois o Mandrel não está voltado para essa plataforma no momento. É possível criar executáveis nativos diretamente no Linux ou Windows rodando diretamente no hardware, com detalhes disponíveis no LEIAME do Mandrel e nos lançamentos do Mandrel .

Pré-requisitos

Para concluir este guia, você precisa:

Suporte à compilação nativa em C

O que significa ter um ambiente de desenvolvimento em C?

  • No Linux, é necessário o GCC e os headers glibc e zlib. Exemplos de distribuições comuns:

    # dnf (rpm-based)
    sudo dnf install gcc glibc-devel zlib-devel libstdc++-static
    # Debian-based distributions:
    sudo apt-get install build-essential libz-dev zlib1g-dev
  • O XCode fornece as dependências necessárias no macOS:

    xcode-select --install
  • No Windows, terá de instalar Visual Studio 2017 Visual C++ Build Tools

Configurando a GraalVM

If you cannot install GraalVM, you can use a multi-stage Docker build to run Maven inside a Docker container that embeds GraalVM. There is an explanation of how to do this at the end of this guide.

Version 22.3 is required. Using the community edition is enough.

  1. Instale o GraalVM se ainda não o fez. Existem algumas opções para isso:

  2. Configurar o runtime environment. Defina a variável de ambiente GRAALVM_HOME para o diretório de instalação do GraalVM, por exemplo:

    export GRAALVM_HOME=$HOME/Development/graalvm/

    No macOS (não suportado pelo Mandrel), aponte a variável para o subdiretório Home:

    export GRAALVM_HOME=$HOME/Development/graalvm/Contents/Home/

    No Windows, você terá que ir até o Painel de Controle para definir as suas variáveis de ambiente.

    A instalação através do scoop irá fazer tudo por você.

  3. (Only for Oracle GraalVM CE/EE) Install the native-image tool using gu install:

    ${GRAALVM_HOME}/bin/gu install native-image

    Some previous releases of GraalVM included the native-image tool by default. This is no longer the case; it must be installed as a second step after GraalVM itself is installed. Note: there is an outstanding issue using GraalVM with macOS Catalina.

  4. (Opcional) Defina a variável de ambiente JAVA_HOME para o diretório de instalação do GraalVM.

    export JAVA_HOME=${GRAALVM_HOME}
  5. (Opcional) Adicione o diretório bin GraalVM bin no PATH

    export PATH=${GRAALVM_HOME}/bin:$PATH
Issues using GraalVM with macOS Catalina

GraalVM binaries are not (yet) notarized for macOS Catalina as reported in this GraalVM issue. This means that you may see the following error when using gu:

“gu” cannot be opened because the developer cannot be verified

Use o seguinte comando para excluir recursivamente o atributo estendido com.apple.quarantine no diretório de instalação do GraalVM como uma solução alternativa:

xattr -r -d com.apple.quarantine ${GRAALVM_HOME}/../..

Solução

Recomendamos que siga as instruções nos passos seguintes e que prepare a aplicação passo a passo. No entanto, pode ir diretamente para o exemplo completo.

Clone o repositório Git: git clone https://github.com/quarkusio/quarkus-quickstarts.git, ou baixe um arquivo.

A solução está localizada no diretório getting-started.

Desenvolvendo um executável nativo

O executável nativo da nossa aplicação conterá o código da aplicação, as bibliotecas necessárias, as APIs Java e uma versão reduzida de uma VM. A base menor da VM melhora o tempo de inicialização da aplicação e cria um espaço menor em disco.

Criando um executável nativo

Se gerou a aplicação do tutorial anterior, pode encontrar no pom.xml o seguinte profile:

<profiles>
    <profile>
        <id>native</id>
        <properties>
            <quarkus.package.type>native</quarkus.package.type>
        </properties>
    </profile>
</profiles>

Você pode fornecer opções personalizadas para o comando native-image usando a propriedade <quarkus.native.additional-build-args> . Várias opções podem ser separadas por vírgula.

Outra possibilidade é incluir a propriedade de configuração quarkus.native.additional-build-args no seu application.properties.

You can find more information about how to configure the native image building process in the Configuração do executável nativo section below.

Usamos um perfil porque, como você verá em breve, o empacotamento do executável nativo leva alguns minutos. Você poderia simplesmente passar -Dquarkus.package.type=native como uma propriedade na linha de comando, mas é melhor usar um perfil, pois isso permite que os testes de imagem nativa também sejam executados.

Criar um executável nativo utilizando:

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.package.type=native
Problemas com o empacotamento no Windows

The Microsoft Native Tools for Visual Studio must first be initialized before packaging. You can do this by starting the x64 Native Tools Command Prompt that was installed with the Visual Studio Build Tools. At x64 Native Tools Command Prompt you can navigate to your project folder and run mvnw package -Pnative.

Outra solução é escrever um script para fazer isso para você:

cmd /c 'call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat" && mvn package -Pnative'

Além dos arquivos normais, a construção também produz target/getting-started-1.0.0-SNAPSHOT-runner . Você pode executá-lo usando: ./target/getting-started-1.0.0-SNAPSHOT-runner .

Java preview features

O código Java que depende de recursos preview requer atenção especial. Para produzir um executável nativo, isso significa que o sinalizador --enable-preview precisa ser passado para a invocação da imagem nativa subjacente. Você pode fazer isso prefixando o sinalizador com -J e passando-o como argumento adicional de construção nativa: -Dquarkus.native.additional-build-args=-J—​enable-preview .

Buildando executáveis nativos totalmente estáticos

O suporte a executáveis nativos totalmente estáticos é experimental.

On Linux it’s possible to package a native executable that doesn’t depend on any system shared library. There are some system requirements to be fulfilled and additional build arguments to be used along with the native-image invocation, a minimum is -Dquarkus.native.additional-build-args="--static","--libc=musl".

A compilação de binários totalmente estáticos é feita através de um link estático com o musl em vez de glibc e não deve ser usada em produção sem testes rigorosos.

Testando o executável nativo

Produzir um executável nativo pode gerar alguns problemas e, por isso, também é uma boa ideia executar alguns testes na aplicação em execução no arquivo nativo. O raciocínio é explicado no Guia de testes.

To see the GreetingResourceIT run against the native executable, use ./mvnw verify -Pnative:

$ ./mvnw verify -Pnative
...
[getting-started-1.0.0-SNAPSHOT-runner:18820]     universe:     587.26 ms
[getting-started-1.0.0-SNAPSHOT-runner:18820]      (parse):   2,247.59 ms
[getting-started-1.0.0-SNAPSHOT-runner:18820]     (inline):   1,985.70 ms
[getting-started-1.0.0-SNAPSHOT-runner:18820]    (compile):  14,922.77 ms
[getting-started-1.0.0-SNAPSHOT-runner:18820]      compile:  20,361.28 ms
[getting-started-1.0.0-SNAPSHOT-runner:18820]        image:   2,228.30 ms
[getting-started-1.0.0-SNAPSHOT-runner:18820]        write:     364.35 ms
[getting-started-1.0.0-SNAPSHOT-runner:18820]      [total]:  52,777.76 ms
[INFO]
[INFO] --- maven-failsafe-plugin:2.22.1:integration-test (default) @ getting-started ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.quickstart.GreetingResourceIT
Executing [/data/home/gsmet/git/quarkus-quickstarts/getting-started/target/getting-started-1.0.0-SNAPSHOT-runner, -Dquarkus.http.port=8081, -Dtest.url=http://localhost:8081, -Dquarkus.log.file.path=build/quarkus.log]
2019-04-15 11:33:20,348 INFO  [io.quarkus] (main) Quarkus 999-SNAPSHOT started in 0.002s. Listening on: http://[::]:8081
2019-04-15 11:33:20,348 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy-reactive]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.387 s - in org.acme.quickstart.GreetingResourceIT
...

By default, Quarkus waits for 60 seconds for the native image to start before automatically failing the native tests. This duration can be changed using the quarkus.test.wait-time system property. For example, to increase the duration to 300 seconds, use: ./mvnw verify -Pnative -Dquarkus.test.wait-time=300.

This procedure was formerly accomplished using the @NativeImageTest annotation. @NativeImageTest is considered deprecated in favor of @QuarkusIntegrationTest which provides a superset of the testing capabilities of @NativeImageTest. More information about @QuarkusIntegrationTest can be found in the Testing Guide.

Profiles

Por padrão, os testes de integração build e run são feitos usando o profile prod.

You can override the profile the executable runs with during the test using the quarkus.test.native-image-profile property. Either by adding it to application.properties or by appending it to the command line: ./mvnw verify -Pnative -Dquarkus.test.native-image-profile=test. Your %test. prefixed properties will be used at the test runtime.

You can override the profile the executable is built with and runs with using the quarkus-profile=test property, e.g. ./mvnw clean verify -Pnative -Dquarkus-profile=test. This might come handy if there are test specific resources to be processed, such as importing test data into the database.

quarkus.native.resources.includes=version.txt
%test.quarkus.native.resources.includes=version.txt,import-dev.sql
%test.quarkus.hibernate-orm.database.generation=drop-and-create
%test.quarkus.hibernate-orm.sql-load-script=import-dev.sql

Com o exemplo mencionado acima em seu application.properties , o banco de dados gerenciado do Hibernate ORM será preenchido com dados de teste durante a execução do teste no modo JVM e durante a execução do teste no modo nativo. O executável de produção conterá apenas o recurso version.txt , sem dados de teste supérfluos.

The executable built with -Dquarkus-profile=test is not suitable for production deployment. It contains your test resources files and settings. Once the testing is done, the executable would have to be built again, using the default, prod profile.

Java preview features

Java preview features

O código Java que depende de recursos preview requer atenção especial. Para testar um executável nativo, isso significa que o indicador --enable-preview precisa ser passado para o plug-in Surefire. Adicionar <argLine>--enable-preview</argLine> à sua seção configuration é uma maneira de fazer isso.

Excluindo testes ao executar como um executável nativo

Ao executar testes dessa forma, as únicas coisas que realmente são executadas nativamente são os endpoints da aplicação, que só podem ser testados por meio de chamadas HTTP. Seu código de teste não é realmente executado nativamente, portanto, se você estiver testando um código que não chama seus endpoints HTTP, provavelmente não é uma boa ideia executá-los como parte dos testes nativos.

Se você compartilhar sua classe de teste entre a JVM e as execuções nativas, como aconselhamos acima, poderá marcar determinados testes com a anotação @DisabledOnIntegrationTest para ignorá-los ao testar uma imagem nativa.

Usar @DisabledOnIntegrationTest também desativará o teste em todas as instâncias de teste de integração, incluindo o teste da aplicação no modo JVM, em uma imagem de contêiner e em uma imagem nativa.

Testar um executável nativo existente

It is also possible to re-run the tests against a native executable that has already been built. To do this run ./mvnw test-compile failsafe:integration-test -Pnative. This will discover the existing native image and run the tests against it using failsafe.

Se o processo não conseguir encontrar a imagem nativa por algum motivo ou se você quiser testar uma imagem nativa que não esteja mais no diretório de destino, poderá especificar o executável com a propriedade de sistema -Dnative.image.path= .

Criando um executável Linux sem o GraalVM instalado

Antes de prosseguir, certifique-se de ter um ambiente de tempo de execução de contêiner em funcionamento (Docker, podman). Se usar o Docker no Windows, compartilhe a unidade do seu projeto nas configurações de compartilhamento de arquivos do Docker Desktop e reinicie o Docker Desktop.

Muitas vezes, é necessário apenas criar um executável Linux nativo para o aplicativo Quarkus (por exemplo, para ser executado em um ambiente de contêiner) e evitar o trabalho de instalar a versão adequada do GraalVM para realizar essa tarefa (por exemplo, em ambientes de CI, é prática comum instalar o mínimo de software possível).

Para isso, o Quarkus oferece uma maneira muito conveniente de criar um executável nativo do Linux, aproveitando um tempo de execução de contêiner, como o Docker ou o podman. A maneira mais fácil de realizar essa tarefa é executar:

CLI
quarkus build --native --no-tests -Dquarkus.native.container-build=true
# The --no-tests flag is required only on Windows and macOS.
Maven
./mvnw install -Dnative -DskipTests -Dquarkus.native.container-build=true
Gradle
./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true

Por padrão, o Quarkus detecta automaticamente o tempo de execução do contêiner. Se quiser selecionar explicitamente o tempo de execução do contêiner, você pode fazer isso com:

Para o Docker:

CLI
quarkus build --native -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=docker
Maven
./mvnw install -Dnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=docker
Gradle
./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=docker

Para o podman:

CLI
quarkus build --native -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman
Maven
./mvnw install -Dnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman
Gradle
./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman

These are normal Quarkus config properties, so if you always want to build in a container it is recommended you add these to your application.properties in order to avoid specifying them every time.

Se vir o seguinte erro de caminho inválido para o JAR da sua aplicação ao tentar criar um executável nativo utilizando uma build em contêiner, mesmo o JAR ter sido compilado com sucesso, é muito provável que esteja utilizando um daemon remoto para o tempo de execução do contêiner.

Error: Invalid Path entry getting-started-1.0.0-SNAPSHOT-runner.jar
Caused by: java.nio.file.NoSuchFileException: /project/getting-started-1.0.0-SNAPSHOT-runner.jar

Neste caso, utilize o parâmetro -Dquarkus.native.remote-container-build=true ao invés de -Dquarkus.native.container-build=true.

O motivo para isso é que o driver do build local é executado através do -Dquarkus.native.container-build=true que utiliza irá montar volumes para tornar o JAR disponível na build do contêiner, mas os volumes montados não funcionam com daemons remotos. O driver que faz a build do contêiner remoto copia apenas os arquivos necessários para montar ele. Observe que, embora o driver remoto também funcione com daemons locais, o driver local deve ser preferido no caso local porque a montagem é geralmente mais eficiente do que a cópia.

Building with Mandrel requires a custom builder image parameter to be passed additionally:

CLI
quarkus build --native -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:22.3-java17
Maven
./mvnw install -Dnative -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:22.3-java17
Gradle
./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:22.3-java17

Observe que o comando acima aponta para um indicador flutuante. É altamente recomendável usar o indicador flutuante para que a imagem do construtor permaneça atualizada e segura. Se for absolutamente necessário, você pode codificar para um indicador específico (veja aqui os indicadores disponíveis), mas esteja ciente de que não receberá atualizações de segurança dessa forma e não há suporte para isso.

Criando um contêiner

Utilizar as extensões dos container-image

A maneira mais fácil de criar uma container-image a partir da sua aplicação Quarkus é utilizar uma das extensões de imagem de contêiner.

Se uma dessas extensões estiverem presente, então a criação de uma imagem de contêiner para o executável nativo é executar um único comando:

./mvnw package -Pnative -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true
  • quarkus.native.container-build=true permite criar um executável Linux sem que o GraalVM esteja instalado (e só é necessário se não tiver o GraalVM instalado localmente ou se o seu sistema operacional local não for Linux)

Se estiver executando um daemon Docker remoto, você terá que substituir quarkus.native.container-build=true por quarkus.native.remote-container-build=true.

  • quarkus.container-image.build=true instrui o Quarkus para criar um container-image utilizando o artefato final da aplicação (que, neste caso, é o executável nativo)

Consulte o Guia do container-image para obter mais informações.

Utilizando a micro imagem base manualmente

É possível executar a aplicação em um contêiner usando o JAR produzido pelo Quarkus Maven Plugin. No entanto, nesta seção, vamos nos concentrar na criação de uma imagem de contêiner usando o executável nativo produzido.

Processo de conteinerização

When using a local GraalVM installation, the native executable targets your local operating system (Linux, macOS, Windows etc). However, as a container may not use the same executable format as the one produced by your operating system, we will instruct the Maven build to produce an executable by leveraging a container runtime (as described in this section):

O executável produzido será um executável Linux de 64 bits, portanto, dependendo do seu sistema operacional, ele pode não ser mais executável. No entanto, isso não é um problema, pois vamos copiá-lo para um contêiner. A geração do projeto forneceu um Dockerfile.native-micro no diretório src/main/docker com o seguinte conteúdo:

FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
Quarkus Micro Image?

O Quarkus Micro Image é uma pequena imagem de contêiner que fornece o conjunto certo de dependências para executar sua aplicação nativa. Ela é baseada no UBI Micro. Essa imagem base foi adaptada para funcionar perfeitamente em contêineres.

Você pode ler mais sobre as imagens UBI em:

As imagens UBI podem ser utilizadas sem qualquer limitações.

Esta página explica como extender a imagem quarkus-micro quando a sua aplicação tem requisitos específicos.

Depois, se não tiver deletado o executável nativo criado, pode construir a imagem docker com:

docker build -f src/main/docker/Dockerfile.native-micro -t quarkus-quickstart/getting-started .

E, finalmente, execute-o com:

docker run -i --rm -p 8080:8080 quarkus-quickstart/getting-started

Utilizando manualmente a imagem base mínima

A geração do projeto também forneceu um Dockerfile.native na pasta src/main/docker com o seguinte conteúdo:

FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6
WORKDIR /work/
COPY target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

A imagem mínima da UBI é maior do que a micro mencionada acima. Ela contém mais utilitários, como o gerenciador de pacotes microdnf .

Utilizar uma compilação do Docker multi-stage

A seção anterior mostrou como criar um executável nativo usando o Maven ou o Gradle, mas isso exige que o executável nativo tenha sido criado primeiro. Além disso, esse executável nativo deve ser um executável Linux de 64 bits.

Talvez você queira criar o executável nativo diretamente em um contêiner sem ter um contêiner final que contenha as ferramentas de criação. Essa abordagem é possível com uma compilação do Docker em vários estágios:

  1. O primeiro estágio faz o build do executável nativo utilizando o Maven ou o Gradle

  2. O segundo estágio é uma imagem mínima que copia o executável nativo produzido

Antes de construir uma imagem de contêiner a partir dos Dockerfiles mostrados abaixo, é necessário atualizar o arquivo .dockerignore, uma vez que este filtra tudo exceto o diretório target. Para fazer o build dentro de um contêiner, é necessário copiar o diretório src. Portanto, edite seu .dockerignore e remova a linha *.

Esta construção em vários estágios pode ser realizada da seguinte forma:

Exemplo de Dockerfile para fazer o build com o Maven:

## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi-quarkus-graalvmce-builder-image:22.3-java17 AS build
COPY --chown=quarkus:quarkus mvnw /code/mvnw
COPY --chown=quarkus:quarkus .mvn /code/.mvn
COPY --chown=quarkus:quarkus pom.xml /code/
USER quarkus
WORKDIR /code
RUN ./mvnw -B org.apache.maven.plugins:maven-dependency-plugin:3.1.2:go-offline
COPY src /code/src
RUN ./mvnw package -Pnative

## Stage 2 : create the docker final image
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
COPY --from=build /code/target/*-runner /work/application

# set up permissions for user `1001`
RUN chmod 775 /work /work/application \
  && chown -R 1001 /work \
  && chmod -R "g+rwX" /work \
  && chown -R 1001:root /work

EXPOSE 8080
USER 1001

CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
This multi-stage Docker build copies the Maven wrapper from the host machine. The Maven wrapper (or the Gradle wrapper) is a convenient way to provide a specific version of Maven/Gradle. It avoids having to create a base image with Maven and Gradle. To provision the Maven Wrapper in your project, use: mvn -N org.apache.maven.plugins:maven-wrapper-plugin:3.1.0:wrapper.

Salve esse arquivo em src/main/docker/Dockerfile.multistage, uma vez que não está incluído no startup rápido.

Exemplo de Dockerfile para build com o Gradle:

## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi-quarkus-graalvmce-builder-image:22.3-java17 AS build
USER root
RUN microdnf install findutils
COPY --chown=quarkus:quarkus gradlew /code/gradlew
COPY --chown=quarkus:quarkus gradle /code/gradle
COPY --chown=quarkus:quarkus build.gradle /code/
COPY --chown=quarkus:quarkus settings.gradle /code/
COPY --chown=quarkus:quarkus gradle.properties /code/
USER quarkus
WORKDIR /code
COPY src /code/src
RUN ./gradlew build -Dquarkus.package.type=native

## Stage 2 : create the docker final image
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
COPY --from=build /code/build/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

Se estiver utilizando o Gradle no seu projeto, pode utilizar este exemplo de Dockerfile. Salve-o em src/main/docker/Dockerfile.multistage.

docker build -f src/main/docker/Dockerfile.multistage -t quarkus-quickstart/getting-started .

E, finalmente, execute-o com:

docker run -i --rm -p 8080:8080 quarkus-quickstart/getting-started

Se precisar de suporte SSL no seu executável nativo, pode facilmente incluir as bibliotecas necessárias na sua imagem Docker.

Consulte o nosso guia Usando SSL com executáveis nativos para obter mais informações.

To use Mandrel instead of GraalVM CE, update the FROM clause to: FROM quay.io/quarkus/ubi-quarkus-mandrel-builder-image:22.3-java17 AS build.

Starting with 22.3, Mandrel does not provide a -java11 variant anymore. Use the -java17 image instead.

Usando uma imagem base sem distribuição

O suporte de imagens sem distribuição é experimental.

Se estiver procurando por imagens de contêineres pequenas, a abordagem sem distribuição reduz o tamanho da camada base. A ideia por trás do sem distribuição é o uso de uma imagem base única e mínima que contenha todos os requisitos e, às vezes, até a própria aplicação.

O Quarkus fornece uma imagem base sem distribuição que você pode usar no seu Dockerfile . Você só precisa copiar sua aplicação e pronto:

FROM quay.io/quarkus/quarkus-distroless-image:2.0
COPY target/*-runner /application

EXPOSE 8080
USER nonroot

CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

O Quarkus fornece a imagem quay.io/quarkus/quarkus-distroless-image:2.0 . Ela contém os pacotes necessários para rodar um executável nativo e tem apenas 9 Mb. Basta adicionar sua aplicação sobre essa imagem e você obterá uma imagem de contêiner minúscula.

As imagens sem distribuição não devem ser utilizadas em produção sem um teste rigoroso.

Criar uma imagem scratch

O suporte de imagens scratch é experimental.

O build de binários totalmente linkados estaticamente permite a utilização de uma imagem de rascunho contendo apenas o executável nativo resultante.

Exemplo de Dockerfile de vários estágios para criar uma imagem a partir de scratch:

## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi-quarkus-graalvmce-builder-image:22.3-java17 AS build
USER root
RUN microdnf install make gcc
COPY --chown=quarkus:quarkus mvnw /code/mvnw
COPY --chown=quarkus:quarkus .mvn /code/.mvn
COPY --chown=quarkus:quarkus pom.xml /code/
RUN mkdir /musl && \
    curl -L -o musl.tar.gz https://more.musl.cc/11.2.1/x86_64-linux-musl/x86_64-linux-musl-native.tgz && \
    tar -xvzf musl.tar.gz -C /musl --strip-components 1 && \
    curl -L -o zlib.tar.gz https://www.zlib.net/zlib-1.2.13.tar.gz && \
    mkdir zlib && tar -xvzf zlib.tar.gz -C zlib --strip-components 1 && \
    cd zlib && ./configure --static --prefix=/musl && \
    make && make install && \
    cd .. && rm -rf zlib && rm -f zlib.tar.gz && rm -f musl.tar.gz
ENV PATH="/musl/bin:${PATH}"
USER quarkus
WORKDIR /code
RUN ./mvnw -B org.apache.maven.plugins:maven-dependency-plugin:3.1.2:go-offline
COPY src /code/src
RUN ./mvnw package -Pnative -DskipTests -Dquarkus.native.additional-build-args="--static","--libc=musl"

## Stage 2 : create the final image
FROM scratch
COPY --from=build /code/target/*-runner /application
EXPOSE 8080
ENTRYPOINT [ "/application" ]

As imagens Scratch não devem ser utilizadas em produção sem um teste rigoroso.

As versões de musl e zlib podem precisar serem atualizadas para atender os requisitos do executável de imagem nativa (e UPX se utilizar compressão de imagem nativa).

Compactar imagens nativas

O Quarkus pode compactar o executável nativo produzido usando UPX. Mais detalhes na documentação de Compressão UPX .

Separando a compilação de imagens nativas e Java

In certain circumstances, you may want to build the native image in a separate step. For example, in a CI/CD pipeline, you may want to have one step to generate the source that will be used for the native image generation and another step to use these sources to actually build the native executable. For this use case, you can set the quarkus.package.type=native-sources. This will execute the java compilation as if you had started native compilation (-Pnative), but stops before triggering the actual call to GraalVM’s native-image.

$ ./mvnw clean package -Dquarkus.package.type=native-sources

Após finalizar a compilação, você encontrará o artefato compilado em target/native-sources:

$ cd target/native-sources
$ ls
native-image.args  getting-started-1.0.0-SNAPSHOT-runner.jar lib

From the output above one can see that, in addition to the produced jar file and the associated lib directory, a text file named native-image.args was created. This file holds all parameters (including the name of the JAR to compile) to pass along to GraalVM’s native-image command. If you have GraalVM installed, you can start the native compilation by executing:

$ cd target/native-source
$ native-image $(cat native-image.args)
...
$ ls
native-image.args
getting-started-1.0.0-SNAPSHOT-runner
getting-started-1.0.0-SNAPSHOT-runner.build_artifacts.txt
getting-started-1.0.0-SNAPSHOT-runner.jar

O processo para o Gradle é análogo.

Também é possível executar o processo de compilação num contêiner:

cd target/native-image
docker run \
  -it \
  --rm \
  --v $(pwd):/work (1)
  -w /work (2)
  --entrypoint bin/sh \
  quay.io/quarkus/ubi-quarkus-graalvmce-builder-image:22.3-java17 \ (3)
  -c "native-image $(cat native-image.args) -J-Xmx4g" (4)
1 Monte o diretório raiz target/native-image no diretório do contêiner /work. Assim, o binário gerado também será escrito neste diretório.
2 Mude o diretório de trabalho para /work, que foi montado em <1>.
3 Use the quay.io/quarkus/ubi-quarkus-graalvmce-builder-image:22.3-java17 docker image introduced in Using a multi-stage Docker build to build the native image.
4 Chamar native-image com o conteúdo do arquivo native-image.args como argumentos. Também fornecemos um argumento adicional para limitar a memória máxima do processo a 4 Gigabytes (isto pode variar dependendo do projeto que está sendo construído e da máquina que está sendo usada).

Se você estiver executando em uma máquina Windows, lembre-se de que o binário foi criado em um contêiner docker do Linux. Portanto, o binário não será executável na máquina Windows do hospedeiro.

Uma visão geral de alto nível do que seriam as várias etapas de um pipeline CI/CD é a seguinte:

  1. Registar a saída da etapa que executa o comando ./mvnw …​ (ou seja, o diretório target/native-image) como um artefacto de construção,

  2. Exigir este artefacto no passo que executa o comando native-image …​, e

  3. Registar a saída do passo que executa o comando native-image …​ (ou seja, arquivos que correspondem a target/*runner) como artefacto de build.

O ambiente que executa o passo 1 apenas necessita do Java e Maven (ou Gradle) instalados, enquanto o ambiente que executa o passo 3 apenas necessita de uma instalação GraalVM (incluindo a funcionalidade native-image ).

Dependendo do resultado final desejado do pipeline CI/CD, o binário gerado pode então ser utilizado para criar uma imagem de contêiner.

Debugando um executável nativo

Starting with Oracle GraalVM 20.2 or Mandrel 20.1, debug symbols for native executables can be generated for Linux environments (Windows support is still under development, macOS is not supported). These symbols can be used to debug native executables with tools such as gdb.

Para gerar símbolos de depuração, adicione o sinalizador -Dquarkus.native.debug.enabled=true ao gerar o executável nativo. Você encontrará os símbolos de depuração para o executável nativo em um arquivo .debug ao lado do executável nativo.

The generation of the .debug file depends on objcopy. On common Linux distributions you will need to install the binutils package:

# dnf (rpm-based)
sudo dnf install binutils
# Debian-based distributions
sudo apt-get install binutils

Quando objcopy não está disponível, os símbolos de debug são incorporados no executável.

Além dos símbolos de depuração, a configuração do sinalizador -Dquarkus.native.debug.enabled=true gera um cache de arquivos de origem para todas as classes de tempo de execução do JDK, classes do GraalVM e classes de aplicação resolvidas durante a geração do executável nativo. Esse cache de fontes é útil para ferramentas de depuração nativas, para estabelecer o vínculo entre os símbolos e o código-fonte correspondente. Ele fornece uma maneira conveniente de disponibilizar apenas os códigos-fonte necessários para o depurador/IDE ao depurar um executável nativo.

Fontes para dependências jar de terceiros, incluindo o código-fonte do Quarkus, não são adicionadas ao cache de fontes por padrão. Para incluí-los, certifique-se de invocar mvn dependency:sources primeiro. Essa etapa é necessária para extrair os códigos-fonte dessas dependências e incluí-los no cache de código-fonte.

A cache de fonte está localizado na pasta target/sources.

Se executar gdb a partir de um diretório diferente do target, então as fontes podem ser carregadas ao executar:

directory path/to/target

no prompt gdb.

Ou começar gdb com:

gdb -ex 'directory path/to/target' path/to/target/{project.name}-{project.version}-runner

por exemplo,

gdb -ex 'directory ./target' ./target/getting-started-1.0.0-SNAPSHOT-runner

Para obter um guia mais detalhado sobre o debug de imagens nativas, consulte o Guia de Referência Nativo.

Configuração do executável nativo

Há várias opções de configuração diferentes que podem afetar a forma como o executável nativo é gerado. Elas são fornecidas em application.properties da mesma forma que qualquer outra propriedade de configuração.

As propriedades são apresentadas abaixo:

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Tipo

Padrão

Comma-separated, additional arguments to pass to the build process. If an argument includes the , symbol, it needs to be escaped, e.g. \\,

Environment variable: QUARKUS_NATIVE_ADDITIONAL_BUILD_ARGS

Show more

list of string

If the HTTP url handler should be enabled, allowing you to do URL.openConnection() for HTTP URLs

Environment variable: QUARKUS_NATIVE_ENABLE_HTTP_URL_HANDLER

Show more

booleano

true

If the HTTPS url handler should be enabled, allowing you to do URL.openConnection() for HTTPS URLs

Environment variable: QUARKUS_NATIVE_ENABLE_HTTPS_URL_HANDLER

Show more

booleano

false

The default value for java.awt.headless JVM option. Switching this option affects linking of awt libraries.

Environment variable: QUARKUS_NATIVE_HEADLESS

Show more

booleano

true

Defines the file encoding as in -Dfile.encoding=…​. Native image runtime uses the host’s (i.e. build time) value of file.encoding system property. We intentionally default this to UTF-8 to avoid platform specific defaults to be picked up which can then result in inconsistent behavior in the generated native executable.

Environment variable: QUARKUS_NATIVE_FILE_ENCODING

Show more

string

UTF-8

If all character sets should be added to the native image. This increases image size

Environment variable: QUARKUS_NATIVE_ADD_ALL_CHARSETS

Show more

booleano

false

The location of the Graal distribution

Environment variable: QUARKUS_NATIVE_GRAALVM_HOME

Show more

string

${GRAALVM_HOME:}

The location of the JDK

Environment variable: QUARKUS_NATIVE_JAVA_HOME

Show more

File

${java.home}

The maximum Java heap to be used during the native image generation

Environment variable: QUARKUS_NATIVE_NATIVE_IMAGE_XMX

Show more

string

If the native image build should wait for a debugger to be attached before running. This is an advanced option and is generally only intended for those familiar with GraalVM internals

Environment variable: QUARKUS_NATIVE_DEBUG_BUILD_PROCESS

Show more

booleano

false

If the debug port should be published when building with docker and debug-build-process is true

Environment variable: QUARKUS_NATIVE_PUBLISH_DEBUG_BUILD_PROCESS_PORT

Show more

booleano

true

If isolates should be enabled

Environment variable: QUARKUS_NATIVE_ENABLE_ISOLATES

Show more

booleano

true

If a JVM based 'fallback image' should be created if native image fails. This is not recommended, as this is functionally the same as just running the application in a JVM

Environment variable: QUARKUS_NATIVE_ENABLE_FALLBACK_IMAGES

Show more

booleano

false

If all META-INF/services entries should be automatically registered

Environment variable: QUARKUS_NATIVE_AUTO_SERVICE_LOADER_REGISTRATION

Show more

booleano

false

If the bytecode of all proxies should be dumped for inspection

Environment variable: QUARKUS_NATIVE_DUMP_PROXIES

Show more

booleano

false

If this build should be done using a container runtime. Unless container-runtime is also set, docker will be used by default. If docker is not available or is an alias to podman, podman will be used instead as the default.

Environment variable: QUARKUS_NATIVE_CONTAINER_BUILD

Show more

booleano

If this build is done using a remote docker daemon.

Environment variable: QUARKUS_NATIVE_REMOTE_CONTAINER_BUILD

Show more

booleano

false

The docker image to use to do the image build. It can be one of graalvm, mandrel, or the full image path, e.g. quay.io/quarkus/ubi-quarkus-mandrel-builder-image:22.3-java17.

Environment variable: QUARKUS_NATIVE_BUILDER_IMAGE

Show more

string

${platform.quarkus.native.builder-image}

The container runtime (e.g. docker) that is used to do an image based build. If this is set then a container build is always done.

Environment variable: QUARKUS_NATIVE_CONTAINER_RUNTIME

Show more

docker, podman, unavailable

Options to pass to the container runtime

Environment variable: QUARKUS_NATIVE_CONTAINER_RUNTIME_OPTIONS

Show more

list of string

Enable monitoring options that allow the VM to be inspected at run time.

Environment variable: QUARKUS_NATIVE_MONITORING

Show more

list of MonitoringOption

If full stack traces are enabled in the resulting image

Environment variable: QUARKUS_NATIVE_FULL_STACK_TRACES

Show more

booleano

true

If the reports on call paths and included packages/classes/methods should be generated

Environment variable: QUARKUS_NATIVE_ENABLE_REPORTS

Show more

booleano

false

If exceptions should be reported with a full stack trace

Environment variable: QUARKUS_NATIVE_REPORT_EXCEPTION_STACK_TRACES

Show more

booleano

true

If errors should be reported at runtime. This is a more relaxed setting, however it is not recommended as it means your application may fail at runtime if an unsupported feature is used by accident.

Environment variable: QUARKUS_NATIVE_REPORT_ERRORS_AT_RUNTIME

Show more

booleano

false

Don’t build a native image if it already exists. This is useful if you have already built an image and you want to use Quarkus to deploy it somewhere. Note that this is not able to detect if the existing image is outdated, if you have modified source or config and want a new image you must not use this flag.

Environment variable: QUARKUS_NATIVE_REUSE_EXISTING

Show more

booleano

false

A comma separated list of globs to match resource paths that should be added to the native image. Use slash (/) as a path separator on all platforms. Globs must not start with slash. By default, no resources are included. Example: Given that you have src/main/resources/ignored.png and src/main/resources/foo/selected.png in your source tree and one of your dependency JARs contains bar/some.txt file, with the following configuration quarkus.native.resources.includes = foo/**,bar/**/*.txt the files src/main/resources/foo/selected.png and bar/some.txt will be included in the native image, while src/main/resources/ignored.png will not be included. Supported glob features Feature Description * Matches a (possibly empty) sequence of characters that does not contain slash (/) ** Matches a (possibly empty) sequence of characters that may contain slash (/) ? Matches one character, but not slash [abc] Matches one character given in the bracket, but not slash [a-z] Matches one character from the range given in the bracket, but not slash [!abc] Matches one character not named in the bracket; does not match slash [a-z] Matches one character outside the range given in the bracket; does not match slash {one,two,three} Matches any of the alternating tokens separated by comma; the tokens may contain wildcards, nested alternations and ranges \ The escape character Note that there are three levels of escaping when passing this option via application.properties: . application.properties parser - MicroProfile Config list converter that splits the comma separated list - Glob parser All three levels use backslash (\) as the escaping character. So you need to use an appropriate number of backslashes depending on which level you want to escape. Note that Quarkus extensions typically include the resources they require by themselves. This option is useful in situations when the built-in functionality is not sufficient.

Environment variable: QUARKUS_NATIVE_RESOURCES_INCLUDES

Show more

list of string

A comma separated list of globs to match resource paths that should not be added to the native image. Use slash (/) as a path separator on all platforms. Globs must not start with slash. Please refer to includes for details about the glob syntax. By default, no resources are excluded. Example: Given that you have src/main/resources/red.png and src/main/resources/foo/green.png in your source tree and one of your dependency JARs contains bar/blue.png file, with the following configuration quarkus.native.resources.includes = **/*.png quarkus.native.resources.excludes = foo/**,**/green.png the resource red.png will be available in the native image while the resources foo/green.png and bar/blue.png will not be available in the native image.

Environment variable: QUARKUS_NATIVE_RESOURCES_EXCLUDES

Show more

list of string

If debug is enabled and debug symbols are generated. The symbols will be generated in a separate .debug file.

Environment variable: QUARKUS_NATIVE_DEBUG_ENABLED

Show more

booleano

false

Generate the report files for GraalVM Dashboard.

Environment variable: QUARKUS_NATIVE_ENABLE_DASHBOARD_DUMP

Show more

booleano

false

The compression level in [1, 10]. 10 means best Higher compression level requires more time to compress the executable.

Environment variable: QUARKUS_NATIVE_COMPRESSION_LEVEL

Show more

int

Allows passing extra arguments to the UPX command line (like --brute). The arguments are comma-separated. The exhaustive list of parameters can be found in https://github.com/upx/upx/blob/devel/doc/upx.pod.

Environment variable: QUARKUS_NATIVE_COMPRESSION_ADDITIONAL_ARGS

Show more

list of string

O que vem a seguir?

Este guia abordou a criação de um executável nativo (binário) para a sua aplicação. Ele fornece uma aplicação que exibe um tempo de inicialização rápido e consome menos memória. No entanto, há muito mais.

Recomendamos continuar a jornada com a implantação no Kubernetes e no OpenShift.