Spring boot with docker unable to find valid certification path to requested target error - spring

I'm using spring boot and am trying to set it up with Docker. I've tried everything I could find on google and nothing seems to get me going. I'm running
mvn clean package docker:build
Running this will do the spring-boot tests, run DB migrations, build the JAR, and then when it comes to Building the Docker image, I get the following error:
Failed to execute goal com.spotify:docker-maven-plugin:0.4.9:build (default-cli)
on project app: Exception caught: java.util.concurrent.ExecutionException: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target -> [Help 1]
Here is the Dockerfile I'm using:
FROM java:8-jdk
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/james/.docker/machine/machines/default"
export DOCKER_MACHINE_NAME="default"
EXPOSE 8080
VOLUME /tmp
ADD app-0.0.1-SNAPSHOT.jar app.jar
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
And here is my docker-maven-plugin configuration:
... pom stuff
<docker.image.prefix>jamesone1</docker.image.prefix>
... other pom stufff
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.9</version>
<configuration>
<dockerHost>https://192.168.99.100:2376</dockerHost>
<imageName>${docker.image.prefix}/${project.artifactId}</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>
I'm using the dock for mac & am using a docker-machine with the following env:
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/james/.docker/machine/machines/default"
export DOCKER_MACHINE_NAME="default"
What's going on?! Am I missing something?

fixed this in windows 10 by:
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.13</version>
<configuration>
<imageName>yourImageName</imageName>
<dockerDirectory>src/main/docker</dockerDirectory>
<dockerHost>https://192.168.99.100:2376</dockerHost>
<dockerCertPath>/Users/your_user/.docker/machine/machines/default</dockerCertPath>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
Important are these two tags:
<dockerHost>https://192.168.99.100:2376</dockerHost>
<dockerCertPath>/Users/your_user/.docker/machine/machines/default</dockerCertPath>
I am using a dockerfile, which path you have to define with this tag:
<dockerDirectory>src/main/docker</dockerDirectory>
Now you can build your jar and generate docker image via:
mvn package docker:build
I think on mac just follwing value has to be different:
<dockerCertPath>/Users/your_user/.docker/machine/machines/default</dockerCertPath>

I ended up building the docker image by myself without the plugin:
docker build -f Dockefile .
And my Dockefile (has been renamed):
FROM java:8-jdk
EXPOSE 8080
#VOLUME /tmp
ADD target/app-0.0.1-SNAPSHOT.jar /opt/demo/app-0.0.1-SNAPSHOT.jar
CMD ["java","-jar","/opt/demo/app-0.0.1-SNAPSHOT.jar"]
I then run it like so:
docker run <container id here>
I just couldn't get the mvn plugin to work!
Edit
Furthermore I ended up creating a docker-compose.yml which makes things a lot simpler!!!
You define properties such as the ports you want open, dockerfile location, and run docker-compose, and it'll magically build+run the docker image!
Example docker-compose.yml that I'm using:
version: '2'
services:
web:
build: .
ports:
- "8080:8080"
build references the Dockerfile location. *Note you may need to the Dockerfile+yml file to be in the same location!
ports reference the ports I want open. Now I can goto localhost:8080 and my request will be forwarded to the docker container.
Read more on docker container here:
https://docs.docker.com/compose/gettingstarted/

Related

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

jhipster Unable to change spring run profile to prod - always starts with dev,swagger - Maven as Service

I am doing
./mvnw -Pprod clean verify
And starts as dev and not has prod profile.
Do I have to change something in my pom file?
<id>prod</id>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>target/classes/static/</directory>
</fileset>
</filesets>
</configuration>
</plugin>
To set as a service in a debian server I do:
sudo chmod +x /var/lib/nms-api/n2.jar
sudo chown nmsapi:nmsapi /var/lib/nms-api/n1.jar
sudo ln -s /var/lib/nms-api/n2.jar /etc/init.d/nms2
sudo systemctl enable nms2
sudo service nms2 start
Edit
I am using jhipster
framework https://www.jhipster.tech/production/ they say:
Please note that this JAR file uses the profile we selected when
building it. As it was built using the prod file in the previous
section, it will therefore run with the prod profile.
and the ps -aux says:
/usr/bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar /var/lib/nms-api/n1.jar
Is there a way to set java -Dspring.profiles.active=prod in the line above when staring as a service?
Edit 2
I set the Environment Variable
sudo -i
root#nms-cp01-vm01:~# export SPRING_PROFILES_ACTIVE=prod
and
cat /etc/environment
$ sudo vi /etc/environment
$ echo $SPRING_PROFILES_ACTIVE
prod
$ sudo echo $SPRING_PROFILES_ACTIVE
prod
And can run in prod profile if
/usr/bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar /var/lib/nms-api/n4test.jar
and not in prod profile, but in dev if run as root
sudo /usr/bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar /var/lib/nms-api/n4test.jar
You are confusing maven profiles and spring boot profiles. They are two totally separate concepts. Maven profiles are flags for turning on specific steps during building , whereas a spring profile is a runtime flag to tell spring which set of configuration to apply. For mor information on spring profiles you can see here
Spring profiles can be set through systen properties, environment variables, but also part of your maven build. The first two are much more flexible imo.
System properties
java -Dspring.profiles.active=prod
Environmebt Variables
export SPRING_PROFILES_ACTIVE=prod
As Part of a Maven Build profile
<profiles>
    <profile>
        <id>prod</id>
        <properties>
            <spring.profiles.active>prod</spring.profiles.active>
        </properties>
<!-- The rest of your profile here -->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
...
</build>
    </profile>
</profiles>

dockerizing Spring Boot Application error: Error: Invalid or corrupt jarfile /app.jar

I'm starting working with docker and I'm trying to dockerize my Spring boot Application. I generated this using spring initializr. I'm working with maven. My DockerFile looks like this:
FROM java:8-jdk-alpine
COPY ${JAR_FILE} app.jar
WORKDIR /usr/app
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
It's pretty simple.
I executed the next commands:
docker build -t shortenurl .
I can see the image in the console with docker images:
But when I try to run the image with the command: docker run -p 8080:8080 shortenurl I got this error message: Error: Invalid or corrupt jarfile /app.jar
I've tried different configurations but not pretty sure. Any advice?
Thanks.
This is my plugin pom.xml plugins section:
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.2.3</version>
<configuration>
<imageName>${docker.image.prefix}/${project.artifactId}</imageName>
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
</plugins>
This is my log after the command:docker build -t shortenurl .
$ docker build -t shortenurl .
Sending build context to Docker daemon 32.89MB
Step 1/5 : FROM java:8-jdk-alpine
---> 3fd9dd82815c
Step 2/5 : COPY ${JAR_FILE} app.jar
---> 248aa4be697d
Step 3/5 : WORKDIR /usr/app
---> Running in 5fcd71c548af
Removing intermediate container 5fcd71c548af
---> bc344b970b11
Step 4/5 : EXPOSE 8080
---> Running in 46b4e4f8e9b7
Removing intermediate container 46b4e4f8e9b7
---> 6b4f55a86a23
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
---> Running in 838a6052f4c8
Removing intermediate container 838a6052f4c8
---> 7d7d272ea42d
Successfully built 7d7d272ea42d
Successfully tagged shortenurl:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
You're building with spring-boot-maven-plugin but you're not generating an executable jar. Update your plugin's configuration to:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
and you should be fine.

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.

Cloud Build fails to build the the simple build step with maven

Testing the cloud-build
Part of my cloudbuild.yaml
- name: 'gcr.io/cloud-builders/mvn'
args: ['dockerfile:build']
dockerfile:build perfectly works in bitbucket pipeline, no problem. I use
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>${dockerfile-maven-version}</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>gcr.io/my-project-id/${project.artifactId}</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
But with the cloud-build for this single step I get the error:
[INFO] Step 14/15 : ARG JAR_FILE
[INFO]
[INFO] ---> Using cache
[INFO] ---> 55793de4bb9f
[INFO] [INFO] Step 15/15 : ADD target/${JAR_FILE} /usr/share/$SERVCE_FOLDER_NAME/app.jar
[INFO]
[ERROR] ADD failed: stat /mnt/cache/docker/tmp/docker-builder589658449/target/myappname-0.0.1-SNAPSHOT.jar: no such file or directory
(the JAR_FILE is passed from the maven dockerfile plugin
no such file or directory
Why?.. In the end of the day I juse call dockerfile:build and expect it to be the same as it is when I build it from another pipeline.
My Dockerfile:
FROM openjdk:8-jdk
ENV GOOGLE_APPLICATION_CREDENTIALS=/app/credentials.json
ARG ACTIVE_PROFILES=dev
ENV ACTIVE_PROFILES=$ACTIVE_PROFILES
ARG CREDENTIALS
ARG SERVCE_FOLDER_NAME=myappname-service
ENV SERVCE_FOLDER_NAME=$SERVCE_FOLDER_NAME
#ENTRYPOINT ["/usr/bin/java", "-jar", "/usr/share/$SERVCE_FOLDER_NAME/app.jar"]
ENTRYPOINT ["./entrypoint.sh" ]
WORKDIR /app
EXPOSE 8080
COPY ./.gcloud/credentials.json credentials.json
COPY entrypoint.sh .
#Add Maven dependencies (not shaded into the artifact; Docker-cached)
#ADD target/lib /usr/share/$SERVCE_FOLDER_NAME/lib
ARG JAR_FILE
ADD target/${JAR_FILE} /usr/share/$SERVCE_FOLDER_NAME/app.jar
EntryPoint script is (that is what is mentioned on step 15/15 in the log):
java -Djava.security.egd=file:/dev/./urandom -jar /usr/share/$SERVCE_FOLDER_NAME/app.jar --spring.profiles.active=$ACTIVE_PROFILES
(I did try to pass hard-coded values to $SERVCE_FOLDER_NAME, $ACTIVE_PROFILES - same [it works in bitbucket pipeline])
A few things come to mind,
how are you triggering the builds?
manually with gcloud or api? or automatically with build triggers or the github app?
it seems that the target/ directory might not be present in the remote workspace-- are you ignoring target/ or .jar files anywhere?
the remote workspace might not be getting the target/ directory or .jar files if they are in your .gitignore or .gcloudignore
try making an empty .gcloudignore or temporarily removing target/ and .jar files from .gitignore
relevant links: https://cloud.google.com/sdk/gcloud/reference/topic/gcloudignore, https://github.com/GoogleCloudPlatform/cloud-builders/issues/40
have you tried debugging with cloud-build-local? it allows you to write and explore the workspace locally
https://cloud.google.com/cloud-build/docs/build-debug-locally
https://github.com/GoogleCloudPlatform/cloud-build-local

Resources