Spring Boot Cloud Native Buildpacks on Heroku? - spring-boot

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?

Related

CA error when create docker image with spring-native

I'm trying to create my first "native java app" using spring-native. I modify my pom adding this
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.10.5</version>
</dependency>
and this ( in the plugin part )
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
</plugin>
If I run "mvn clean package" everythng works fine; but when I try "spring-boot:build-image" I get this error (the part of the picture that you can't see says "x509: certificate signed by unknown authority"):
I already tried to add to intellij the certs (image below) of the site but I get the same error.
Any suggestion?
The attempt to download from https://github.com/graalvm/graalvm-ce-builds/releases is happening inside a Docker container that runs the Cloud Native Buildpacks builder and buildpacks. Certificate errors like this can happen when the Docker container is behind a corporate HTTP proxy that uses custom CA certificates. There is a Paketo buildpacks issue and a Spring Boot issue that cover similar errors.
Adding certificates to a JDK trust store will not fix the issue. Certificates must be provided to the builder container when it is launched. This is covered in the Paketo documentation and in the Spring Boot documentation, but it is a little difficult to understand exactly how to configure certificates.
As an example:
First create a bindings directory in the root of your project structure (at the same level as the project src directory) and copy the custom certificate to that directory (where my-custom-certificate.crt is a CA certificate in PEM format):
$ mkdir -p bindings/certificates
$ echo "ca-certificates" > bindings/certificates/type
$ cp /some/path/to/my-custom-certificate.crt bindings/certificates/my-custom-certificate.crt
$ tree bindings
bindings
├── certificates
│   ├── my-custom-certificate.crt
│   └── type
Then configure the Spring Boot Maven plugin to provide the binding to the Paketo CNB builder when the image is built:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
<bindings>
<binding>${basedir}/bindings/certificates:/platform/bindings/ca-certificates</binding>
</bindings>
</image>
</configuration>
</plugin>
Note that the bindings configuration of the Spring Boot Maven plugin requires Spring Boot version 2.5.0 or greater.

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.

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

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

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.

Automatic update spring boot docker app using ansible

We plan to release spring boot application to customer. In corrent process, every time we release a new version, we have to uninstall the rpm and re install using rpm.
We want to move towards auto update of our application whenever there is a new version available. Essentially customer does not have to deal with updating the applications.
Instead of rpm, we are thinking about docker image, packaged with all dependencies.
. How do achieve this functionality?
Based on what I have read so far, if we package we use ansible + docker to deploy the application, , ansible (using watch tower or custom code) will ping an IP and when discovers a new version, will stop the application, pull the application from destination and then deploy and start.
Is my understanding correct?
Steps to automate deployment
Docker
Create application and dockerise it with any JDK docker image. We have maven package to dockerise application.
Add Plugin to pom.xml
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.10</version>
<configuration>
<imageName>job-demand-service-analytics-processor</imageName>
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
OR
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>${jib-maven-plugin.version}</version>
<configuration>
<from>
<image>adoptopenjdk:11-jre-hotspot</image>
</from>
<to>
<image>websockethandler:latest</image>
</to>
<container>
<entrypoint>
<shell>sh</shell>
<option>-c</option>
<arg>chmod +x /entrypoint.sh && sync && /entrypoint.sh</arg>
</entrypoint>
<ports>
<port>8090</port>
</ports>
<environment>
<SPRING_OUTPUT_ANSI_ENABLED>ALWAYS</SPRING_OUTPUT_ANSI_ENABLED>
<APP_SLEEP>0</APP_SLEEP>
<JWT_SECRET_KEY_BASE64>""</JWT_SECRET_KEY_BASE64>
..........
</environment>
<useCurrentTimestamp>true</useCurrentTimestamp>
</container>
</configuration>
</plugin>
</plugins>
There are many options to dockerise your Spring application
Git
Push your code to git server like Bitbucket, Gitlabs, Github and so on.
Create a master branch for production releases and develop branch for development.
Jenkins
Trigger a jenkins job to create a docker image when you commit or merge changes from develop to master when feature is commited to develop.This is based on the hooks we add at git server.
If the docker image created successfully trigger the job which deploys.
Reverse Proxy or Load Balancer
To achive zero downtime, use load balnacer(reverse proxy like NGINX with upstream) running your container in multiple replicas of the container.
This applies for any application. If you have special requirement, update your question with the basic example code and will update the answer with Dockerising and automation steps.

Resources