Le framework Quarkus regroupe, uniformise et simplifie le développement Java. A mes yeux, il représente l’avenir de la plateforme Java.

Cet article démontre comment Quarkus simplifie la gestion des applications dites de « nouvelles générations » en mettant à profit Docker, un packaging universel et standard, et Kubernetes, l’orchestrateur de ces applications.

Je vous montrerai comment, en quelques commandes, une application Java Quarkus peut être mise à disposition dans un cluster Kubernetes. Pour cet exemple, je construirai une des applications quickstart de Quarkus pour la déploier vers mon cluster local microk8s sous Ubuntu.

Mon Objectif est de 10 secondes pour passer du code Java à l’exécutable géré par Kubernetes !

JDK pour l’application Native

Le TRES gros avantage de Quarkus est de construire des applications natives. C’est à dire, plus légères et plus rapides à démarrer. Sous Docker et Kubernetes, c’est un argument de poids.

Quelques pré-requis sont nécessaires:

Le JDK utilisé sera alors celui de GraalVM:

java -version

openjdk version "11.0.6" 2020-01-14
OpenJDK Runtime Environment GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02)
OpenJDK 64-Bit Server VM GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02, mixed mode, sharing)

Sous Ubuntu 19.10, il faut ajouter une bibliothèque zip particulière pour la compilation via gcc:

sudo apt install zlib1g-dev

Installation microk8s

Microk8s est une solution équivalente à minikube, exceptée qu’elle est native, intégrée et légère (sans machine virtuelle).

sudo snap install microk8s --classic
microk8s.start

Quelques addons sont utiles:

microk8s enable ingress registry storage dashboard

Sous microk8S, le dashboard se lance avec les commandes:

echo "Get admin token"
token=$(microk8s kubectl -n kube-system get secret | grep default-token | cut -d " " -f1)
microk8s kubectl -n kube-system describe secret $token

echo "dashboard url: https://localhost:10443"
microk8s kubectl port-forward -n kube-system service/kubernetes-dashboard 10443:443

Récupération de l’application QuickStart de Quarkus

L’application est en Java et piloté par Maven. Les prérequis sont alors:

  • maven en version > 3.6.1
  • JDK > 11 (GraalVM sera utilisé)

La création est issue de l’artefact maven de quarkus. 2 modules sont ajoutés:

  • kubernetes,
  • container-image-docker.
mvn io.quarkus:quarkus-maven-plugin:1.3.2.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=kubernetes-quickstart \
    -DclassName="org.acme.rest.GreetingResource" \
    -Dpath="/greeting" \
    -Dextensions="kubernetes, container-image-docker"

L’application prend alors la forme suivante avec:

  • un fichier pom.xml complet,
  • les Dockerfile dans src/main/docker
  • les classes Java dans src/main/java

La compilation est standard avec maven.

mvn compile

L’exécution locale est rapide avec Quarkus:

mvn quarkus:dev

Pour notre déploiement Kubernetes, le fichier de paramètres Quarkus ( src/main/resources/application.properties ) est enrichi avec:

  • une publication dans le registre des images docker,
  • un déploiement dans microk8s.
# Configuration file
# key = value

#optional, default to the system user name
quarkus.container-image.group=org.acme
quarkus.container-image.push=true
quarkus.container-image.build=true

# Registry Microk8s
%dev.quarkus.container-image.registry=${K8S_REGISTRY_URL}
%dev.quarkus.container-image.insecure=true
%dev.quarkus.container-image.username=${K8S_REGISTRY_USERNAME}
%dev.quarkus.container-image.password=${K8S_REGISTRY_PASSWORD}

# tests readiness kubernetes
quarkus.kubernetes.readiness-probe.initial-delay=10s
quarkus.kubernetes.readiness-probe.period=20s

# Exposition via le node
quarkus.kubernetes.service-type=NodePort

# Deploy to Kubernetes
%dev.quarkus.kubernetes.deploy=true

Pour ne pas rendre dépendant le code avec le poste du développeur, les variables d’environnement sont positionnées dans mon ~/.profile .

# graalvm installé dans /opt/graalvm-ce
export JAVA_HOME=/opt/graalvm-ce
export GRAALVM_HOME=/opt/graalvm-ce
export PATH=$JAVA_HOME/bin:$PATH


export K8S_REGISTRY_URL=localhost:32000
export K8S_REGISTRY_USERNAME=admin
export K8S_REGISTRY_PASSWORD=U2VRb0xFUHByWkJCYTlHSzhTYit2OUJnLzVnZzRzaEVyR05WdGxWZWtIQT0K

Pour obtenir le mot de passe de l’admin microk8s, lancer:

microk8s config

Du Build au Run

Avec maven, et en quelques secondes je l’espère, l’application sera:

  • compilée
  • testée
  • dockerisée
  • déployée
./mvnw package -Dquarkus.profile=dev
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------< org.acme:kubernetes-quickstart >-------------------
[INFO] Building kubernetes-quickstart 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ kubernetes-quickstart ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ kubernetes-quickstart ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ kubernetes-quickstart ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /media/emmanuel/Data/Users/emman/GitHub/EnterpriseFlowsRepository/kubernetes-quickstart/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ kubernetes-quickstart ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ kubernetes-quickstart ---
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.rest.GreetingResourceTest
2020-04-24 11:49:20,423 INFO  [io.quarkus] (main) Quarkus 1.3.2.Final started in 1.647s. Listening on: http://0.0.0.0:8081
2020-04-24 11:49:20,435 INFO  [io.quarkus] (main) Profile test activated. 
2020-04-24 11:49:20,435 INFO  [io.quarkus] (main) Installed features: [cdi, kubernetes, resteasy, smallrye-health]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.056 s - in org.acme.rest.GreetingResourceTest
2020-04-24 11:49:21,607 INFO  [io.quarkus] (main) Quarkus stopped in 0.040s
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ kubernetes-quickstart ---
[INFO] Building jar: /media/emmanuel/Data/Users/emman/GitHub/EnterpriseFlowsRepository/kubernetes-quickstart/target/kubernetes-quickstart-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- quarkus-maven-plugin:1.3.2.Final:build (default) @ kubernetes-quickstart ---
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeploy] Found kubernetes server.
[INFO] [io.quarkus.container.image.docker.deployment.DockerBuild] Docker daemon found! Version:'19.03.6'
[INFO] [org.jboss.threads] JBoss Threads version 3.0.1.Final
[INFO] Initializing dekorate session.
[INFO] Default s2i build generator....
[INFO] Registering s2i handler!
[INFO] Registering s2i handler!
[INFO] Generating manifests.
[INFO] Processing kubernetes configuration.
[INFO] Processing openshift configuration.
[INFO] Processing s2i configuration.
[INFO] [io.quarkus.deployment.pkg.steps.JarResultBuildStep] Building thin jar: /media/emmanuel/Data/Users/emman/GitHub/EnterpriseFlowsRepository/kubernetes-quickstart/target/kubernetes-quickstart-1.0-SNAPSHOT-runner.jar
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Building docker image for jar.
[INFO] Closing dekorate session.
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Sending build context to Docker daemon  38.45MB
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] 
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 1/11 : FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 91d23a64fdf2
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 2/11 : ARG JAVA_PACKAGE=java-11-openjdk-headless
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Using cache
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 64eced5f31c3
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 3/11 : ARG RUN_JAVA_VERSION=1.3.5
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Using cache
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> fab815ca4c05
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 4/11 : ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Using cache
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> dc03c98b6d80
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 5/11 : RUN microdnf install curl ca-certificates ${JAVA_PACKAGE}     &amp;&amp; microdnf update     &amp;&amp; microdnf clean all     &amp;&amp; mkdir /deployments     &amp;&amp; chown 1001 /deployments     &amp;&amp; chmod "g+rwX" /deployments     &amp;&amp; chown 1001:root /deployments     &amp;&amp; curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh     &amp;&amp; chown 1001 /deployments/run-java.sh     &amp;&amp; chmod 540 /deployments/run-java.sh     &amp;&amp; echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Using cache
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 42a066b1a4b8
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 6/11 : ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Using cache
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> ee2babb06268
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 7/11 : COPY target/lib/* /deployments/lib/
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Using cache
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> c8324c5043c3
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 8/11 : COPY target/*-runner.jar /deployments/app.jar
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 3dd1e2850c3d
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 9/11 : EXPOSE 8080
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Running in 8534f450d2af
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Removing intermediate container 8534f450d2af
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 5f2d92f24c0a
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 10/11 : USER 1001
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Running in 5aba5171c48a
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Removing intermediate container 5aba5171c48a
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 1fa84efdf3a3
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 11/11 : ENTRYPOINT [ "/deployments/run-java.sh" ]
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Running in 6c2f4f7a9c39
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Removing intermediate container 6c2f4f7a9c39
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> a967a9f991ef
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Successfully built a967a9f991ef
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Successfully tagged localhost:32000/org.acme/kubernetes-quickstart:1.0-SNAPSHOT
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Pushed container image localhost:32000/org.acme/kubernetes-quickstart:1.0-SNAPSHOT (a967a9f991ef)

[INFO] [io.quarkus.deployment.util.ExecUtil] WARNING! Using --password via the CLI is insecure. Use --password-stdin.
[INFO] [io.quarkus.deployment.util.ExecUtil] WARNING! Your password will be stored unencrypted in /home/emmanuel/.docker/config.json.
[INFO] [io.quarkus.deployment.util.ExecUtil] Configure a credential helper to remove this warning. See
[INFO] [io.quarkus.deployment.util.ExecUtil] https://docs.docker.com/engine/reference/commandline/login/#credentials-store
[INFO] [io.quarkus.deployment.util.ExecUtil] 
[INFO] [io.quarkus.deployment.util.ExecUtil] Login Succeeded
[INFO] [io.quarkus.deployment.util.ExecUtil] The push refers to repository [localhost:32000/org.acme/kubernetes-quickstart]
[INFO] [io.quarkus.deployment.util.ExecUtil] e6fe0f7c809e: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] f9e7240da8bc: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] fa99692bd6e0: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] eddba477a8ae: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] f80c95f61fff: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] f9e7240da8bc: Mounted from org.enterpriseflowsrepository/kubernetes-quickstart
[INFO] [io.quarkus.deployment.util.ExecUtil] fa99692bd6e0: Mounted from org.enterpriseflowsrepository/kubernetes-quickstart
[INFO] [io.quarkus.deployment.util.ExecUtil] eddba477a8ae: Mounted from org.enterpriseflowsrepository/kubernetes-quickstart
[INFO] [io.quarkus.deployment.util.ExecUtil] f80c95f61fff: Mounted from org.enterpriseflowsrepository/kubernetes-quickstart
[INFO] [io.quarkus.deployment.util.ExecUtil] e6fe0f7c809e: Pushed
[INFO] [io.quarkus.deployment.util.ExecUtil] 1.0-SNAPSHOT: digest: sha256:96463f867a58c9fcdeafed31b1a49cb433aaeeb8b92c79ddcc935427d970e244 size: 1370
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Successfully pushed docker image localhost:32000/org.acme/kubernetes-quickstart:1.0-SNAPSHOT
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Deploying to kubernetes server: https://127.0.0.1:16443/ in namespace: default.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Applied: ServiceAccount kubernetes-quickstart.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Applied: Service kubernetes-quickstart.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Applied: Deployment kubernetes-quickstart.
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 3307ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  10.377 s
[INFO] Finished at: 2020-04-24T11:49:26+02:00
[INFO] ------------------------------------------------------------------------

Objectif atteint: 10 secondes 377 pour le déploiement en JVM !

Pour le déploiement de l’application native, c’est toujours plus long avec la compilation C++.

./mvnw package -Dquarkus.profile=dev -Pnative
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------< org.acme:kubernetes-quickstart >-------------------
[INFO] Building kubernetes-quickstart 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ kubernetes-quickstart ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ kubernetes-quickstart ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ kubernetes-quickstart ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /media/emmanuel/Data/Users/emman/GitHub/EnterpriseFlowsRepository/kubernetes-quickstart/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ kubernetes-quickstart ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ kubernetes-quickstart ---
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.rest.GreetingResourceTest
2020-04-24 11:50:43,775 INFO  [io.quarkus] (main) Quarkus 1.3.2.Final started in 1.652s. Listening on: http://0.0.0.0:8081
2020-04-24 11:50:43,789 INFO  [io.quarkus] (main) Profile test activated. 
2020-04-24 11:50:43,790 INFO  [io.quarkus] (main) Installed features: [cdi, kubernetes, resteasy, smallrye-health]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.35 s - in org.acme.rest.GreetingResourceTest
2020-04-24 11:50:45,222 INFO  [io.quarkus] (main) Quarkus stopped in 0.025s
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ kubernetes-quickstart ---
[INFO] 
[INFO] --- quarkus-maven-plugin:1.3.2.Final:build (default) @ kubernetes-quickstart ---
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeploy] Found kubernetes server.
[INFO] [io.quarkus.container.image.docker.deployment.DockerBuild] Docker daemon found! Version:'19.03.6'
[INFO] [org.jboss.threads] JBoss Threads version 3.0.1.Final
[INFO] Initializing dekorate session.
[INFO] Default s2i build generator....
[INFO] Registering s2i handler!
[INFO] Registering s2i handler!
[INFO] Generating manifests.
[INFO] Processing kubernetes configuration.
[INFO] Processing openshift configuration.
[INFO] Processing s2i configuration.
[INFO] [io.quarkus.deployment.pkg.steps.JarResultBuildStep] Building native image source jar: /media/emmanuel/Data/Users/emman/GitHub/EnterpriseFlowsRepository/kubernetes-quickstart/target/kubernetes-quickstart-1.0-SNAPSHOT-native-image-source-jar/kubernetes-quickstart-1.0-SNAPSHOT-runner.jar
[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] Building native image from /media/emmanuel/Data/Users/emman/GitHub/EnterpriseFlowsRepository/kubernetes-quickstart/target/kubernetes-quickstart-1.0-SNAPSHOT-native-image-source-jar/kubernetes-quickstart-1.0-SNAPSHOT-runner.jar
[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] Running Quarkus native-image plugin on GraalVM Version 20.0.0 CE
[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] /opt/graalvm-ce/bin/native-image -J-Dsun.nio.ch.maxUpdateArraySize=100 -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Dvertx.logger-delegate-factory-class-name=io.quarkus.vertx.core.runtime.VertxLogDelegateFactory -J-Dvertx.disableDnsResolver=true -J-Dio.netty.leakDetection.level=DISABLED -J-Dio.netty.allocator.maxOrder=1 -J-Duser.language=fr -J-Dfile.encoding=UTF-8 --initialize-at-build-time= -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy$BySpaceAndTime -H:+JNI -jar kubernetes-quickstart-1.0-SNAPSHOT-runner.jar -H:FallbackThreshold=0 -H:+ReportExceptionStackTraces -H:-AddAllCharsets -H:-IncludeAllTimeZones -H:EnableURLProtocols=http -H:NativeLinkerOption=-no-pie --no-server -H:-UseServiceLoaderFeature -H:+StackTrace kubernetes-quickstart-1.0-SNAPSHOT-runner
[INFO] Closing dekorate session.
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]    classlist:   4 255,10 ms,  1,20 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]        (cap):     608,30 ms,  1,20 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]        setup:   1 795,57 ms,  1,20 GB
11:50:56,763 WARN  [io.qua.config] Unrecognized configuration key "quarkus.kubernetes.deploy" was provided; it will be ignored
11:50:57,912 INFO  [org.jbo.threads] JBoss Threads version 3.0.1.Final
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]   (typeflow):  11 103,82 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]    (objects):   9 953,20 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]   (features):     472,34 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]     analysis:  22 871,09 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]     (clinit):     559,14 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]     universe:   1 530,25 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]      (parse):   2 262,97 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]     (inline):   2 687,83 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]    (compile):  17 613,33 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]      compile:  24 100,53 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]        image:   2 635,47 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]        write:     466,05 ms,  3,50 GB
[kubernetes-quickstart-1.0-SNAPSHOT-runner:9370]      [total]:  57 964,73 ms,  3,50 GB
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Starting docker image build
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Sending build context to Docker daemon  38.42MB
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] 
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 1/7 : FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 91d23a64fdf2
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 2/7 : WORKDIR /work/
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Using cache
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 266580c50552
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 3/7 : COPY target/*-runner /work/application
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> 003d5815bf58
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 4/7 : RUN chmod 775 /work /work/application   &amp;&amp; chown -R 1001 /work   &amp;&amp; chmod -R "g+rwX" /work   &amp;&amp; chown -R 1001:root /work
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Running in a8184a71d700
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Removing intermediate container a8184a71d700
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> b6441c524c98
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 5/7 : EXPOSE 8080
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Running in 8f22a357211c
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Removing intermediate container 8f22a357211c
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> f260e7963c2a
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 6/7 : USER 1001
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Running in cc9bf41bb3ff
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Removing intermediate container cc9bf41bb3ff
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> f0cf1cccd9bc
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Step 7/7 : CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> Running in 2e2907d7882b
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Removing intermediate container 2e2907d7882b
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor]  ---> ad17a18ac0d4
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Successfully built ad17a18ac0d4
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Successfully tagged localhost:32000/org.acme/kubernetes-quickstart:1.0-SNAPSHOT
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Pushed container image localhost:32000/org.acme/kubernetes-quickstart:1.0-SNAPSHOT (ad17a18ac0d4)

[INFO] [io.quarkus.deployment.util.ExecUtil] WARNING! Using --password via the CLI is insecure. Use --password-stdin.
[INFO] [io.quarkus.deployment.util.ExecUtil] WARNING! Your password will be stored unencrypted in /home/emmanuel/.docker/config.json.
[INFO] [io.quarkus.deployment.util.ExecUtil] Configure a credential helper to remove this warning. See
[INFO] [io.quarkus.deployment.util.ExecUtil] https://docs.docker.com/engine/reference/commandline/login/#credentials-store
[INFO] [io.quarkus.deployment.util.ExecUtil] 
[INFO] [io.quarkus.deployment.util.ExecUtil] Login Succeeded
[INFO] [io.quarkus.deployment.util.ExecUtil] The push refers to repository [localhost:32000/org.acme/kubernetes-quickstart]
[INFO] [io.quarkus.deployment.util.ExecUtil] 992987415cb5: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] 5ed0ef1a3c14: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] 3352c134f5b6: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] eddba477a8ae: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] f80c95f61fff: Preparing
[INFO] [io.quarkus.deployment.util.ExecUtil] eddba477a8ae: Layer already exists
[INFO] [io.quarkus.deployment.util.ExecUtil] f80c95f61fff: Layer already exists
[INFO] [io.quarkus.deployment.util.ExecUtil] 3352c134f5b6: Mounted from org.enterpriseflowsrepository/kubernetes-quickstart
[INFO] [io.quarkus.deployment.util.ExecUtil] 5ed0ef1a3c14: Pushed
[INFO] [io.quarkus.deployment.util.ExecUtil] 992987415cb5: Pushed
[INFO] [io.quarkus.deployment.util.ExecUtil] 1.0-SNAPSHOT: digest: sha256:0d05b40a370fef0176d85c5f88f6d5f9d0d4f527156aef691c1589645626113d size: 1368
[INFO] [io.quarkus.container.image.docker.deployment.DockerProcessor] Successfully pushed docker image localhost:32000/org.acme/kubernetes-quickstart:1.0-SNAPSHOT
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Deploying to kubernetes server: https://127.0.0.1:16443/ in namespace: default.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Applied: ServiceAccount kubernetes-quickstart.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Applied: Service kubernetes-quickstart.
[INFO] [io.quarkus.kubernetes.deployment.KubernetesDeployer] Applied: Deployment kubernetes-quickstart.
[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 65764ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:13 min
[INFO] Finished at: 2020-04-24T11:51:52+02:00
[INFO] ------------------------------------------------------------------------

Objectif manqué: 73 secondes du code Java à l’application native déployée !

L’image est bien référencée par docker

docker images

REPOSITORY                                                            TAG                 IMAGE ID            CREATED             SIZE
localhost:32000/org.acme/kubernetes-quickstart                        1.0-SNAPSHOT        a4f564df6d3a        8 minutes ago       340MB

Sous Kubernetes, l’application quickstart-kubernetes est disponible:

Stabilisation des URL

L’application déployée est disponible sur le port suivant (ici 32534):

microk8s.kubectl get service

NAME                    TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes              ClusterIP      10.152.183.1     <none>        443/TCP          23h
kubernetes-quickstart   LoadBalancer   10.152.183.209   <pending>     8080:32534/TCP   30m

Pour éviter de modifier à chaque déploiement les ports, il est nécessaire de déclarer un service ingress comme LoadBalancer pour appeler la même adresse.

Pour cela, ajouter le fichier src/main/kubernetes/ingress.yaml avec:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kubernetes-quickstart-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
        - path: /greeting
          backend:
            serviceName: kubernetes-quickstart
            servicePort: 8080

Ce déploiement est à faire 1 seule fois. Chaque nouvelle compilation quarkus viendra remplacer le service ‘kubernetes-quarkus’ du serviceName:

microk8s.kubectl apply -f src/main/kubernetes/

L’application est maintenant disponible sur l’URL: https://localhost/greeting