Debug Quarkus app packaged with quarkus-container-image-jib - quarkus

I would like to run the same image in our dev, staging and production environments. For our dev environment I would like to be able to connect a debugger.
I build the image for our Quarkus app like this (mvn package):
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-jib</artifactId>
</dependency>
...
</dependencies
<properties>
<quarkus.container-image.build>true</quarkus.container-image.build>
<quarkus.jib.ports>8080,5005</quarkus.jib.ports>
<quarkus.container-image.image>...</quarkus.container-image.image>
...
</properties>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>1.12.1.Final</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
Is it possible to start the application in debug mode while otherwise running with prod profile? Passing JAVA_OPTIONS=-Ddebug=true via an environment variable to the container causes a Exception in thread "main" java.nio.file.NoSuchFileException: /work/lib/deployment/deployment-class-path.dat.
If not, what would be the appropriate way to accomplish such a setup?

There are a few ways to do that, but they all rely on the fact that in Quarkus you can control Jib to use whatever launch script you want for the container image.
By default the container-image is created with a minimal java -jar ... style ENTRYPOINT, but that can be changed using the quarkus.jib.jvm-entrypoint.
If you use the default base image which already contains a run-java.sh script that provides a host of options (see https://hub.docker.com/r/fabric8/java-alpine-openjdk11-jre#startup-script-run-javash) then what you are trying to accomplish could be done by setting the following in application.properties:
quarkus.jib.jvm-entrypoint=/deployments/run-java.sh
quarkus.jib.environment-variables."JAVA_APP_DIR"=/work # this is needed so the script knows where the Quarkus jar is
Then launch the application using:
docker run --rm -p 8080:8080 -p 5005:5005 -e JAVA_DEBUG=true gandrian/getting-started:1.0.0-SNAPSHOT
Now the application will have the debug port open (but won't suspend) and you can connect to it with a debugger

It is possible to make the same Quarkus image open a debug port in your Kubernetes Deployment, i.e. without rebuilding the image only for debugging.
When using JIB with a Red Hat UBI base image, e.g. quarkus.jib.base-jvm-image=registry.access.redhat.com/ubi8/openjdk-11-runtime:1.14 , this works by overriding the container command in your Deployment K8S descriptor like this:
containers:
- name: your-app
image: your-app-image
command: ["java"]
args: ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", -Djava.util.logging.manager=org.jboss.logmanager.LogManager", "-jar", "quarkus-run.jar"]
This overrides the Docker image's Entrypoint, which looks like this (gleaned from docker inspect):
"Entrypoint": [
"java",
"-Djava.util.logging.manager=org.jboss.logmanager.LogManager",
"-jar",
"quarkus-run.jar"
],
This might work for other base images and container builders other than JIB as well, if the Entrypoint is the same.
For the records, the Quarkus image Entrypoint with JIB seems to be determined programmatically here: https://github.com/quarkusio/quarkus/blob/c28a72b63104d8856fac1481b107c9f9ff3e7f1a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibProcessor.java#L390

Related

Dockerfile "VOLUME" equivalent when using Spring Boot Paketo Buildpack

I'm currently working on migrating the containerization of Spring Boot App from Dockerfile file to the Spring Boot Maven Plugin build-image.
Now I am wondering how to configure a volume in this scenario. The equivalent to having a VOLUME ["/var/store"] declartion in the Dockerfile. I already Googled for a while, help appreciated. THX!
It depends on the purpose.
If you want to add a volume mount when the buildpacks are running, then you would add a <binding> to your pom.xml.
https://docs.spring.io/spring-boot/docs/2.5.2/maven-plugin/reference/htmlsingle/#build-image.customization
Volume bind mounts that should be mounted to the builder container when building the image. The bindings will be passed unparsed and unvalidated to Docker when creating the builder container.
Bindings must be in one of the following forms:
<host source path>:<container destination path>[:<options>]
<host volume name>:<container destination path>[:<options>]
Ex: results in /host/workspace being mounted into /workspace when the buildpacks execute
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<bindings>
<binding>/host/workspace:/workspace</binding>
</bindings>
</image>
</configuration>
</plugin>
</plugins>
</build>
</project>
This would be the same as using the pack build --volume flag, if one is using the pack cli instead of Spring Boot's Maven plugin.
You can bind volumes when you run your application. That simply uses the standard tools and arguments for your container runtime. For example, you can docker run -v and map in a volume.
If you want the specific behavior of the VOLUME entry in a Dockerfile (which doesn't actually do 1 or 2 above), that's not exposed for images created using Buildpacks, which is what Spring Boot is using. If this is what you want, I would encourage you to read this SO post on volumes and reconsider if you really need it at all.

Spring Boot Cloud Native Buildpacks on Heroku?

I configured my Spring Boot project to use cloud Native Buildpacks to build its docker image as below:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>my-image</name>
</image>
</configuration>
</plugin>
</plugins>
</build>
The resulting Docker image works fine, but I would like to deploy it on Heroku.
I pushed it to the Heroku Container Registry and tried to release it as explained below:
https://devcenter.heroku.com/articles/container-registry-and-runtime#building-and-pushing-image-s
https://devcenter.heroku.com/articles/container-registry-and-runtime#releasing-an-image
When I run:
heroku container:release web --app my-app
I get the following error:
▸ Expected response to be successful, got 404
By googling the error, it seems that it is due to the fact that the resulting Docker image uses
ENTRYPOINT instead of CMD to start the application, as explained in the links below:
https://github.com/grandnode/grandnode/issues/563
https://github.com/heroku/cli/issues/1081
https://devcenter.heroku.com/articles/container-registry-and-runtime#dockerfile-commands-and-runtime
Is it possible to configure the Spring Boot Buildpack in order to use CMD instead of ENTRYPOINT? Or any other solution to deploy the resulting Docker image on Heroku?

Docker for local development with spring boot

I want to use docker with a spring boot application in my development environment.
For production I first generate the war file using mvn package then I build an image using this dockerfile :
FROM tomcat:9.0-jre8-alpine
COPY target/backend-0.0.1-SNAPSHOT.war $CATALINA_HOME/webapps/api.war
But for dev purpose I want to be able to check my changes when I edit my code and not have to redo mvn package then build the image then run the container. Changes made to the code can be watched using spring boot devtools so that my app is recompiled every time I make changes to the source code.
But then I thought to use an image, still with tomcat, and setup a volume. But I don't know which files I have to watch. Is it the folder target or some specific files inside it ? And to which folder inside my image do I link the volume to ? Something like $CATALINA_HOME/webapps I presume.
If anyone can help me to point me in the right direction it would be greatly appreciated ? Thanks.
I managed to do it using a Maven Docker image. mapping the source code using volumes, and setting the working directory so Maven can find the pom.xml. In your docker-compose.yml:
version: '3.1'
services:
backend:
image: maven:3.6.3-jdk-8
command: mvn spring-boot:run
ports:
- 8080:8080
- 8085:8085
volumes:
- .:/usr/src/mymaven:rw
working_dir: /usr/src/mymaven
Make sure you have the boot tools enabled in your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
And if you need, enable the remote debugger:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.3.RELEASE</version>
<configuration>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8085
</jvmArguments>
</configuration>
</plugin>
Then you can attach your code editor to the Docker container:
https://code.visualstudio.com/Docs/editor/debugging#_launch-versus-attach-configurations

How to build the docker image using jib-maven-plugin, but not push by default?

I have a simple SpringBoot application and I want to build docker image using Jib Maven plugin.
Following is my plugin configuration:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>2.1.0</version>
<configuration>
<from>
<image>openjdk:11-jdk-slim</image>
</from>
<to>
<image>username/appname</image>
<tags>
<tag>latest</tag>
<tag>${project.version}</tag>
</tags>
</to>
<container>
<mainClass>demo.Application</mainClass>
<ports>
<port>8080</port>
<port>8787</port>
</ports>
</container>
</configuration>
</plugin>
I just want to build the image locally and run it. I don't want to build and push to docker registry in one go.
When I run the command mvn jib:build it is automatically getting pushed to DockerHub using my credentials from Docker config (/Users/username/.docker/config.json).
Is there a way I can disable push and another goal just to push the image to registry?
Since you said jib:dockerBuild is not an option, the closest workaround is jib:buildTar; the goal creates a local tarball at target/jib-image.tar (path configurable with <outputPaths><tar>). Running jib:buildTar (or any jib:... goals) for the first time will build and cache everything necessary to build an image. Therefore, subsequent jib:build runs will be no-op in terms of building layers. It will only need to send layers missing in a remote registry.
Of course, one downside of the workaround is that it creates an unnecessary tarball, which may be large.
Unrelated to you question, you don't need to set <tag>latest</tag>, because the target image reference <image>username/appname<image> already implies <image>username/appname:latest<image>. The <tags> configuration is for pushing additional tags on top of <to><iamge>.
From JIB documentation Jib Maven Plugin, you can run
mvn jib:dockerBuild
This will push an image to a Docker daemon after building.
If you are using podman in mac or windows (with wsl2)...
specify path where podman command can be found
mvn jib:dockerBuild -Djib.dockerClient.executable=$(which podman)
I just checked and it is possible to have the image built by Jib locally. First make sure that your Docker daemon is running locally. And then do it like this:
<to>
<image><your-local-image-name></image>
</to>
I guess yours might not have worked because your Docker daemon wasn't running or your image name started with your username, which made Jib think that you actually want to push the image to Docker Hub.

How to automatic deploy spring boot in jenkin and put images to docker

I using jenkins spring boot and docker in my app. I want deploy spring boot in jenkin and put jar when deploy into docker and start it automatic. I reference to here :
https://denisdbell.wordpress.com/2017/08/26/automated-deployment-jenkins-docker-spring-boot/
But i have a problem. It deploy success but don't run jar in docker. When i type docker - ps it show me jar and i must run it manually. I want when jenkin deploy it automatic put images into docker and run it automatic.
I have two question:
- In my project spring boot, i need put docker in root project ?
- How to jenkin deploy and put images to docker and run automatic jar when jenkin deploy
- When i have mutiple modules, how to i specific copy only jar modules i need deploy and copy to docker and run it.
Thanks you so much help me
Question 1:- Yes you need to add it to the root folder.
Question 2:- You have to use the dockerfile-maven-plugin to push/pull images and use the shell commands from Jenkins to run the same.
Add the SCM GIT, Stash, Hg as this
<scm>
<connection>scm:git:ssh://git#guthub.com/yourproject.git</connection>
<developerConnection>scm:git:ssh://git#guthub.com/yourproject.git[push=]scm:git:ssh://git#guthub.com/yourproject.git</developerConnection>
<tag>HEAD</tag>
</scm>
Add the plugin as
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.3</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>${docker.image.prefix}/yourproject-${project.artifactId}
</repository>
<tag>${project.version}</tag>
</configuration>
In this while building your jar pass the arguments
mvn clean install -DskiptTests -Ddocker.image.prefix=<your docker repo url>
This command would automatically push the latest project version docker image to the repository.
Use the Shell commands to fetch this image and start the docker from the shell.

Resources