Spring boot container runs locally but not on EC2 - java

I have a spring boot microservice in a docker container. The container runs locally just fine but it doesn't on EC2. My local Java version is 12. My local docker version is 18.06.1-ce, same as the EC2 instance docker version.
The dockerfile is as follows
FROM openjdk:12-alpine
VOLUME /tmp
COPY target/my-api-0.0.1.jar /app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
when I try to run this container on EC2 I get the error:
Error: Invalid or corrupt jarfile /app.jar
EC2's Java version is 1.7.0_231. But I imagine that since I'm using Java 12 in my docker container the container would execute the jar inside it in a java 12 environment.
I don't know why I'm still getting the "invalid or corrupt jar" error.
I have done mvn clean and mvn package before building the docker container locally.
Any help? Thanks!

Related

Quarkus application deployed on Heroku gives Error R10 (Boot Timeout)

I'm having issues deploying a Quarkus 1.10 application to Heroku as a Docker image.
The same application, using SpringBoot and a similar Docker Image boots successfully, but somehow Quarkus triggers the infamous R10 Boot Timeout error due to bad bind of $PORT, even when I see that the boot times are really small (2 seconds vs. 4.5 of the SpringBoot version).
If I start the image locally, it works perfectly without issues.
My final Docker Image is like this (omitting the Multi-stage build steps for brevity):
FROM gcr.io/distroless/java:11
ENV QUARKUS_MAILER_FROM=${EMAIL_USERNAME} \
QUARKUS_MAILER_USERNAME=${EMAIL_USERNAME} \
QUARKUS_MAILER_PASSWORD=${EMAIL_PASSWORD}
EXPOSE 8080
COPY --from=backend /usr/src/app/target/*-runner.jar /usr/app/app.jar
COPY --from=backend /usr/src/app/target/lib /usr/app/lib
ENTRYPOINT [ "java", "-jar" ]
CMD ["/usr/app/app.jar", "-Dquarkus.http.host=0.0.0.0", "-Dquarkus.http.port=${PORT}"]
I'm using the commands to deploy the application:
heroku container:push web
heroku container:release web
I don't see where the error is. I've also tried to remove the EXPOSE directive from the Dockerfile but that's not the cause of error.
I've solved the issue, which is really dumb.
Modifying the ENTRYPOINT and the CMD sections of the Dockerfile as follows:
ENTRYPOINT [ "java" ]
CMD ["-Dquarkus.http.host=0.0.0.0", "-Dquarkus.http.port=${PORT}", "-jar", "/usr/app/app.jar"]
it works. The problem is, the system properties have to be passed before the -jar parameter, otherwise Quarkus doesn't pick the right value for ${PORT}

Bean lifecycle in Spring Boot 2.1 and Java 11

My project is moving from Spring Boot 2.0.4 with Java 8 to Spring Boot 2.1.0 with Java 11. When the application was built with Spring Boot 2.0.4 and Java 8 and run in Docker / Docker Compose, the #PostConstruct-annotated method was called, but after the move to Spring Boot 2.1.0 and Java 11 the #PreDestroy-annotated method is no longer called.
I have tried switching from annotations to implementing InitializingBean and DisposableBean as described here, but the DisposableBean.destroy method is not called.
I have also tried adding a dependency to javax.annotation-api version 1.3.2, with the same result.
How to reproduce:
Create a minimal Spring application with a lifecycle bean:
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
#Component
public class Life implements InitializingBean, DisposableBean {
#Override
public void destroy() throws Exception {
System.out.println("--- Life.shutdown");
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("--- Life.startup");
}
}
Start the Spring application from the target subfolder:
cd target
java -jar demo-0.0.1-SNAPSHOT.jar
When the application is stopped using Ctrl+C, the DisposableBean.destroy is called.
Return to the parent folder:
cd ..
Start the Spring application using Maven:
mvn spring-boot:run
When the application is stopped using Ctrl+C, the DisposableBean.destroy is called.
Dockerfile:
FROM openjdk:11.0.1-jre-slim
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT java -jar /app.jar
Build, run, and stop Docker image:
docker build -t demo .
docker run -p 8080:8080 demo
docker ps
docker stats 3ca5b804ab13
docker stop 3ca5b804ab13
docker logs 3ca5b804ab13
When the application is stopped using docker stop, the DisposableBean.destroy is not called.
docker-compose.yml:
demo:
image: demo
ports:
- '8080:8080'
Run Docker image using Docker Compose (simulating OpenShift):
docker-compose up
docker-compose down
demo_demo_1 exited with code 137
When the application is stopped using docker-compose down, the DisposableBean.destroy is not called.
I suspect that Docker is trying a SIGTERM before it issues a SIGKILL, because there is a 10-second delay before the container is killed.
There are many places where the setup can go wrong.
First I suggest to identify whether java/spring part have some issues or it a docker/environment related issue. From the question it sounds like its java related, but in reality I suspect its not in java/spring.
So, mvn spring-boot:run works as expected, and I see that you package the spring boot application as jar (app.jar) likely with a spring boot plugin. This is also a place where things potentially can go wrong, because spring boot uses a special classloader to load things in runtime.
So in order to fully eliminate the "java/spring" part navigate to your target directory and run java -jar app.jar (make sure that java 11 is installed on your local machine of course). If it doesn't work - investigate java /spring part, otherwise proceed with docker part.
The chances are that the application will work as expected.
Now, as for docker setup.
After running docker compose and seeing that it fails,
You can use the following commands:
docker ps -a // -a flag to see container ids of containers that were stopped for whatever reason as well.
Now get find the Id of the java process that exited and examine its logs:
docker logs <ID_OF_THE_EXTED_CONTAINER_GOES_HERE>
Now the chances are that the application context fails to start (maybe network related issue or something, here it's really hard to tell without seeing an actual log) and hence the issue.
Another possible issue is that the application is "too heavy" (by this I mean that it exceeds some quotas imposed on docker container).
You can run docker stats <CONTAINER_ID> command to see its memory / cpu usage in real time or gather metrics from within the application.
I think I found the solution (in this blog entry): Use exec form instead of shell form in the Dockerfile so that the SIGTERM that Docker issues hits the java process instead of the bash process (which doesn't forward signals to any child processes).
Shell form (executed with a /bin/sh -c shell):
ENTRYPOINT java -jar /app.jar
Exec form (executed without a shell):
ENTRYPOINT ["java", "-jar", "/app.jar"]

How to accelerate Docker container boot time?

I am new to containerizing apps using Docker. I could deploy a container including a war file. The war is basically a JAVA web application/servlet that sends back a video file upon receiving the request from end-user. The app deployment using docker was a success and app works fine. However I have some issues regarding its boot time.
From the moment that I create the container by hitting command docker run -it -d -p 8080:8080 surrogate, it takes about 5-6 minutes for the container to become operational, meaning that the first 5-6 minute of the container lifetime, it is not responding to end-user requests, and after that it works fine. Is there any way to accelerate this boot time?
Dockerfile includes:
FROM tomcat:7.0.72-jre7
ADD surrogate-V1.war /usr/local/tomcat/webapps/
CMD ["catalina.sh", "run"]
WORKDIR "/usr/local/tomcat/"
RUN wget https://www.dropbox.com/s/1r8awydc05ra8wh/a.mp4?dl=1
RUN cp a.mp4\?dl\=1 lego.mp4
(Posted on behalf of the OP).
First get rid of -d in the "docker run" command to see what is going on in the background. I noticed the war deployment phase is taking so long (around 15-20 minutes!!!)
The reason in my case was that the tomcat version in the Dockerfile was different from the Tomcat version in the environment from which I exported the web application as WAR. (How to check JRE version: in terminal enter: JAVA -version, checking the Tomcat version: from eclipse, when you are exporting, it shows the version).
In my case in Dockerfile, I had :
FROM tomcat:7.0.72-jre7
I changed it to:
FROM tomcat:6.0-jre7
It now takes less than 10 seconds!
In a nutshell, make sure that the Tomcat version and JRE versions in the Dockerfile are the same as the environment from which you exported the Java web application as WAR.

How to build a Docker container for JAVA web application

I was trying to build a JAVA web application using Docker. I was making a docker container to deploy and run the application. I am beginner. So I started with small POC for java application(jar) which was working fine. I made some changes for JAVA web application(war) and created a Dockerfile for the project which is as follows :
Dockerfile
---------------------------------------------------
FROM java:8
RUN apt-get update
RUN apt-get install -y maven
WORKDIR /code
ADD pom.xml /code/pom.xml
ADD src/main/webapp/WEB-INF/web.xml /codes/rc/main/webapp/WEB-INF/web.xml
RUN ["mvn", "dependency:resolve"]
ADD src /code/src
RUN ["mvn", "package"]
CMD ["usr/lib/jvm/java-8-openjdk-amd64/bin/java", "-war", "target/techpoint.war"]
----------------------------------------------------
Build was successful but when I run the application - It says
"Unrecognized option: -war | Error: Could not create the Java Virtual Machine | Error: A fatal exception has occurred. Program will exit"
And when I replaced "-war" with "-jar" - It says "no main manifest attribute, in target/myapp.war"
Can somebody tell me how can I make JAVA web application (war) compatible with Docker deployment process. That means what should be the actual Dockerfile (with commands) to make possible to build and run the application?
You need a web server or an application server container like tomcat or Jboss (and many others) to deploy and run your java based web application. Your "techpoint.war" files need to be copied to the specific folder depends on each web server. For example, if you are using Tomcat then you can copy it to the /webapps folder. Tomcat will extract and deploy the war file.
You can add the following to your DockerFile.
FROM tomcat:8.5.11-jre8
COPY /<war_file_location>/techpoint.war /usr/local/tomcat/webapps/techpoint.war
You can build the image using docker build command and start the container from the created image.
docker build -t techpoint.
docker run -it --rm -p 8091:8080 techpoint
Now Tomcat will extract and deploy your war file.How to access the deployed application depends on the webroot of your application. For example,
http://<ip_address>:8091/techpoint/index.html

Execute Heroku Cedar Stack into Docker Container

I would like to setup a Docker container using the following image: https://github.com/heroku/stack-images
I have installed the image inside Docker using
docker pull heroku/cedar:14
Which steps are required to start a Docker container that works in the same way Heroku does?
Communicate via Heroku ToolBelt cli in order to start and scale the application
Deploy applications using git and build using Java BuildPack
I've found an approach where you can turn an Heroku application into a Docker container but it is not the solution i'm looking for:
http://www.centurylinklabs.com/heroku-on-docker/
Checkout the Dokku project. It utilizes a docker project called buildstep to run Heroku buildpacks in a Cedar-like environment.
Have fun!

Categories

Resources