Deploying Java app to Docker image - java

I have an executable JAR that is normally executed like so:
java -jar myapp.jar
I would like to "Dockerize" this app by placing it in a container, say, under /~/myapp, and then configure the container to always run this app (using the above command) when the container starts up.
Using this sample Dockerfile as a starting point, what entries do I need to add in order to get Docker to position myapp.jar correctly in the file system, and to run it at startup?
Assume that by the time I run Docker to build the image, the binary will be located under build/distributions like so:
myapp/
src/
build.gradle
Dockerfile
build/distributions/
myapp.jar

Here is a simple example of what you are requesting. This assumes you are running docker build . from /myapp/src/ and that the application is running in the foreground of the container.
# Use Ububtu 14.04 as our base O/S
FROM ubuntu:14.04
# Set our working directory
WORKDIR /
# Update the repositories and then install java
RUN apt-get update && install -y default-jre
# Copy the application from its folder to our image
# Assumes docker build is run from /myapp/src
ADD /build/distributions/myapp.jar /myapp.jar
# Run the app when the container is executed.
CMD ["java", "-jar myapp.jar"]

Related

gradle build image using a different version than the one mentioned in docker file

I have java 13 installed on my machine and I have a project where I mentioned java 11 in the Dockerfile, so what should happen here is that when I build the docker image it should be built on top of java 11.
but surprisingly I get this error when running the container com/example/Application has been compiled by a more recent version of the Java Runtime.
The Dockerfile:
FROM openjdk:11.0.2-jdk
# Unpack distribution tar
ADD /distributions/application.tar /
RUN mkdir /src
RUN mkdir /src/main
RUN mkdir /src/main/resources
RUN mkdir /src/main/resources/ssl
ADD ./main/resources/ssl/keystore.p12 /src/main/resources/ssl/keystore.p12
# create JAR with unversioned name
RUN cp /application/lib/application-*.jar /application/lib/application.jar
ENTRYPOINT java -jar /application/lib/application.jar
Does anyone have an explanation for this?
You can use something similar to this:
FROM eclipse-temurin:16.0.2_7-jdk-centos7 AS builder
VOLUME /tmp
COPY . .
WORKDIR /
RUN ./gradlew assemble
FROM eclipse-temurin:16.0.2_7-jdk-centos7
WORKDIR /
COPY --from=builder build/libs build/libs
RUN ls -lah
RUN jar -xvf build/libs/*.jar
COPY build/libs/BOOT-INF/lib app/lib
COPY build/libs/META-INF/ app/META-INF
COPY build/libs/BOOT-INF/classes app/
RUN rm -rf build/libs
ENTRYPOINT ["java", "-cp", "app:app/lib/*", "com.example.springtest.SpringTestApplication"]
which effectively is a multi stage docker file that builds the image internally at the docker container. This means that your choice of Java version for building is locked down and does not get affected by what you run on your local machine. However, as mentioned before there are a few caveats here:
Developing against a newer Java version and then attempting to target an older one can lead to compatibility issues.
Always re-building the project in order to produce a Docker image can affect performance negatively (image what would happen if you were to run this at a CI level).
Thus based on all the above, I would suggest to align your development environment with what you are targeting as a deployment. This is turn would allow you to build the application locally and then simply proceed into copying the necessary artifacts/assets into the created container.

Docker image does not rebuild after code change

I am playing around with a docker project that builds and starts with
docker run -p 8888:8888 -v /$(pwd)/example/proto:/proto <image-name>
Inside it is a gradle based java application, about which I would like to get to know somewhat more, so I started to modify its source, adding some logs etc.
I tried to rebuild and rerun the docker image the above way but the results of my modifications don't seem to visible, the logs aren't printed etc.
I removed the image with docker rmi, but after every rebuild it seems to be the same image is being created. docker images always shows it is created 3 weeks ago and the image id is always the same
Checking on the application level the build directory contains the newly compiled java classes, so apparently on that level my changes are in effect, but it seems docker still uses the old code
Any help would be appreciated
Updated: Dockerfile
FROM gradle:7.0.0-jdk11 as cache
RUN mkdir -p /home/gradle/cache_home
RUN mkdir -p /proto
RUN touch /proto/any.proto
ENV GRADLE_USER_HOME /home/gradle/cache_home
COPY build.gradle /home/gradle/java-code/
COPY gradle.properties /home/gradle/java-code/
WORKDIR /home/gradle/java-code
RUN gradle build -i --no-daemon || return 0
FROM gradle:7.0.0-jdk11 as runner
COPY --from=cache /home/gradle/cache_home /home/gradle/.gradle
COPY . /usr/src/java-code/
WORKDIR /usr/src/java-code
EXPOSE 8888
ENTRYPOINT ["gradle", "bootRun", "-i"]
A docker build will send your local changes to your local docker deamon to be built into an image.
cd projectWithDockerfile
docker build -f ./Dockerfile -t me/gradlethingy .
docker run -p 8888:8888 -v /$(pwd)/example/proto:/proto me/gradlethingy
Without the build I'm guessing you are pulling in their <image-name> from the net each time.

gu No such file or directory

I'm building a docker image out of a micronaut application.
But whenever I run the docker build command
docker build -f Dockerfile -t micronaut .
I get this error
/bin/sh: /bin/gu: No such file or directory
Here's the content of my docker file anyway:
FROM oracle/graalvm-ce:20.0.0-java11 as graalvm
RUN $GRAALVM_HOME/bin/gu install native-image
COPY . /home/app/micronautguide
WORKDIR /home/app/micronautguide
RUN $GRAALVM_HOME/bin/native-image --no-server -cp build/libs/complete-*-all.jar
FROM frolvlad/alpine-glibc
RUN apk update && apk add libstdc++
EXPOSE 8080
COPY --from=graalvm /home/app/micronautguide/micronautguide /micronautguide/micronautguide
ENTRYPOINT ["/micronautguide/micronautguide", "-Xmx68m"]
Though by running gu command from the terminal works.
Your context does not contain RUN $GRAALVM_HOME/bin/gu . What is $GRAAL_VM_HOME? Whatever this variable is, it is set as null. Also, $GRAALVM_HOME/bin/gu needs to be part of docker image.
$GRAALVM_HOME does not exists in the oracle/graalvm-ce:20.0.0-java11 container. Thus, make suer to specify the right path. In this case it is /bin/gu
I think $GRAALVM_HOME is a variable you use in the local machine and gu tool is already installed and available at /bin in the docker image. So I have kept the $GRAALVM_HOME unchanged in the second build stage.
So, the Dockerfile should be like below,
FROM oracle/graalvm-ce:20.0.0-java11 as graalvm
RUN /bin/gu install native-image
COPY . /home/app/micronautguide
WORKDIR /home/app/micronautguide
RUN /bin/native-image --no-server -cp build/libs/complete-*-all.jar
FROM frolvlad/alpine-glibc
RUN apk update && apk add libstdc++
EXPOSE 8080
COPY --from=graalvm /home/app/micronautguide/micronautguide /micronautguide/micronautguide
ENTRYPOINT ["/micronautguide/micronautguide", "-Xmx68m"]

Simple Docker container dies immediatelly after docker run command

I have a Dockerfile which looks like this:
FROM alpine:3.9
RUN apk add --update openjdk8
RUN mkdir /var/generator/
COPY generator.jar /var/generator
EXPOSE 8080
ENTRYPOINT [ "/bin/sh" ]
Dockerfile is inside generator/ folder. I am building it using:
docker build -t generator generator/
It builds successfully:
Successfully built 878e81f622cc
Successfully tagged generator:latest
but when I am trying to run this image with
docker run -d -p 8080:8080 generator
it dies immediately. docker logs gives no output.
What is wrong with my Dockerfile? Why is the container dying?
Try to run the JAR. Currently, it just runs sh command and exits. Make it something as below to run the JAR in foreground -
FROM alpine:3.9
RUN apk add --update openjdk8
RUN mkdir /var/generator/
COPY generator.jar /var/generator
EXPOSE 8080
ENTRYPOINT ["java","-jar","/var/generator/generator.jar"]
Beside your entrypoint is wrong (sh exits immediately) I would also recommend to start with an appropriate base image instead of starting with alpine and installing the openjdk package. Since you want to run a java application just use the JRE and not a full JDK and start the application as a foreground process.
Here's a minimal version which is also more efficient in disksize as the image will be smaller.
FROM openjdk:8-jre-alpine
COPY generator.jar /opt/generator.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/opt/generator.jar"]

Docker Springboot not running

I am new to docker,
I have pre cooked a docker image(updated and installed Java and other dependancies) and stored it on my GitHub repo,
I have stored a simple hello world Spring Boot application on an AWS S3 bucket,
I want to my DockerFile -
1. Get the docker image from my GitHub repo
2. Do an update patch
3. Set my working to directory to /home/ubuntu
4. Download application from S3 bucket using wget(it's publicly accessible)
5. run the application inside the container
After which I will run the image.
Command to build -
docker build -t someTag .
Command to run -
docker run -p 9090:8090 someTag
My java application jar that will be downloded is - docker.jar
And the application runs on port 8080
I have the following Dockerfile -
FROM someRepoHere
WORKDIR /home/ubuntu
RUN apt-get update
RUN cd /home/ubuntu
VOLUME /home/ubuntu
RUN wget S3BucketLocationHere
#RUN nohup java -jar docker.jar &
# Expose the default port
EXPOSE 8080
#Old command - CMD nohup java -jar docker.jar &
CMD ["java", "-jar", "docker.jar"]
The DockerFile is able to successfully build the image but,
My application is unreachable, It did not run inside the container.
Locally if I wget my application and run the nohup command, the application responds successfully.
Your command being run is what controls the existence of the container, when it exits/returns, the container exits and stops. Therefore you need to run your command in the foreground. When you are in an interactive shell in a container, that command is your shell. The command you've listed uses a shell, but that shell exits when it runs out of commands to process and nothing is running in the foreground:
CMD nohup java -jar docker.jar &
The string syntax will run the command with /bin/sh -c "nohup java ...".
A better option is to run with json syntax if you don't need a shell, and run your java app in the foreground, avoid the nohup and background syntax:
CMD ["java", "-jar", "docker.jar"]
A few more comments on the provided Dockerfile:
WORKDIR /home/ubuntu
RUN apt-get update
That only creates a cache inside your container that will become stale and result in cache misses if you try to use it in the future. This doesn't upgrade any packages if that's what you intended. That line should be removed.
RUN cd /home/ubuntu
This makes no filesystem changes, and will have no impact on the resulting image. The current shell state is lost after the RUN line exits, including the current directory and any variables you set. This line should be removed.
VOLUME /home/ubuntu
From this line forward, changes to /home/ubuntu will be lost. You'll only see anonymous volumes created as a result unless you specify a volume at runtime at the same location. You likely don't want the above volume line because it will break things like the next line.
RUN wget S3BucketLocationHere
This line has been obfuscated but I suspect you are outputting in /home/ubuntu because of the value of WORKDIR. Anything created here will be lost because of the VOLUME line above.

Categories