Why is my docker CI image not reproducible / running everywhere - java

I have a Dockerfile for doing CI.
It uses the contents of a third party tarball which in-turn includes parts of Java Runtime (yes its ugly).
$ git clone xxx
$ cd xxx
$ docker build .
During execution the Dockerfile on ONE host requires ".../jre/.../server/libjvm.so" and executed on ANOTHER host requires ".../jre/.../client/libjvm.so" from that tarball.
The Docker version is everywhere 1.7.1
Nothing is ADDED to the container besides the git repo folder (./) and the tarball.
How is this possible?
Are there any shared environment variables implicitly passed to docker?
This is how the Dockerfile looks like:
FROM ubuntu:14.04
...
WORKDIR /
RUN wget http://SOME-URL TOOL-PACKAGE
RUN tar xf TOOL-PACKAGE
...
# setup some envs
ENV
# extend PATH
ENV PATH $PATH: ...
...
COPY ./ src
WORKDIR src
# use tool to generate some input files
RUN SOME-TOOL-BINARY-WHICH-USES-JRE
# continue build with make
RUN make

When you have the possibility to modify the java execution in your build process you could pass the -client or -server parameter explicitly to choose whether the client or server JVM should be used.
For details you could have a look at this other stackoverflow question.

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.

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"]

ADD failed: stat /var/lib/docker/tmp/docker-builderXYZ/myapp.jar: no such file or directory

I put the Dockerfile into the project root.
meaning there's a ./target directory and therein, maven generates a spring-boot-web-0.0.1-SNAPSHOT.jar file.
I now want to add that to a docker image:
FROM centos
RUN yum install -y java # `-y` defaults questions to 'yes'
VOLUME /tmp # where Spring Boot will store temporary files
WORKDIR / # self-explanatory
ADD /target/spring-boot-web-0.0.1-SNAPSHOT.jar myapp.jar # add fat jar as "myapp.jar"
RUN sh -c 'touch ./myapp.jar' # updates dates on the application (important for caching)
EXPOSE 8080 # provide a hook into the webapp
# run the application; the `urandom` gets tomcat to start faster
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/myapp.jar"]
This ADD fails:
ADD failed: stat /var/lib/docker/tmp/docker-builder119635304/myapp.jar: no such file or directory
The solution seems to be moving the comments to their own lines as they will break the commands if they're in the same line as them.
This Dockerfile works prefectly fine:
# a linux runtime environment
FROM centos
# install java; `-y` defaults questions to 'yes'
RUN yum install -y java
# where Spring Boot will store temporary files
VOLUME /tmp
# self-explanatory
WORKDIR /
# add fat jar as "myapp.jar"
ADD /target/spring-boot-web-0.0.1-SNAPSHOT.jar myapp.jar
# updates dates on the application (important for caching)
RUN sh -c 'touch ./myapp.jar'
# provide a hook into the webapp
EXPOSE 8080
# run the application; the `urandom` gets tomcat to start faster
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/myapp.jar"]

How to make curl available in Docker image based java:8-jdk-alpine and keep the image clean?

We are having java code that runs curl command to fetch the some result.
We have built a jar file and the jar file executes fine
Now, when we try to dokerize the java program (using jar) and run the application in docker we get this error:
errorjava.io.IOException: Cannot run program "curl": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at com.ps.api.common.CoreAPI_Spec.executeCoreAPI(CoreAPI_Spec.java:295)
at com.ps.api.common.CoreAPI_Spec.getAccessTokens(CoreAPI_Spec.java:319)
Dockerfile used :
FROM ubuntu:16.04
MAINTAINER niro;
# Install prerequisites
RUN apt-get update && apt-get install -y \
curl
FROM java:8-jdk-alpine
# Set the working directory to /app
WORKDIR /Users/******/Desktop/CoreAPI_Jar
# Copy the current directory contents into the container at /app
ADD *******_Automation-0.0.1-SNAPSHOT-jar-with-dependencies.jar ******_Automation-0.0.1-SNAPSHOT-jar-with-dependencies.jar
# Run app.py when the container launches
CMD ["java", "-jar", "******-0.0.1-SNAPSHOT-jar-with-dependencies.jar"]
The Java base image you are using is Alpine Linux one and curl package also needs to be downloaded from there. Here is Dockerfile I have used for Production deployments.
FROM openjdk:8-jre-alpine
RUN apk add --update \
curl \
&& rm -rf /var/cache/apk/*
Update 05/2019
As of Alpine Linux 3.3 there exists a new --no-cache option for apk. It allows users to install packages with an index that is updated and used on-the-fly and not cached locally:
FROM openjdk:8-jre-alpine
RUN apk --no-cache add curl
This avoids the need to use --update and remove /var/cache/apk/* when done installing packages.
Reference -
https://github.com/gliderlabs/docker-alpine/blob/master/docs/usage.md and Thank you #Daniel for the comment.
Your example dockerfile contains multiple FROM statements. This is valid but as the documentation says each FROM clears the state from previous instructions. And so the fresh installed curl is wiped after the second FROM.
Most languages have readily available HTTP clients these days; you should almost never be calling out to curl from a program in a language more sophisticated than a shell script. java.net.URLConnection has been a part of Java since Java 1.0 and (without knowing why you're trying to shell out for this) it's almost definitely the right tool here.
Assuming you control the executeCoreAPI method from your backtrace, you should change it to use the built-in Java HTTP client, and just delete all of the Dockerfile parts that try to install curl.

Deploying Java app to Docker image

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"]

Categories