I am trying to learn my way around Docker. I want to build a container/image for my java application. The Docker file looks like this:
FROM openjdk:7
COPY . C:/Users/name/Documents/NetBeansProjects/project1/src/mainpckg
WORKDIR C:/Users/name/Documents/NetBeansProjects/project1/src/mainpckg
RUN javac Main.java
CMD java Main
And i am calling it like this:
docker build -t my-java-app .
But it gives the following error:
$ docker build -t my-java-app .
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM openjdk:7
---> 4a42f05dc422
Step 2 : COPY . C:/Users/name/Documents/NetBeansProjects/project1
/src/mainpckg
---> Using cache
---> 301de702fad9
Step 3 : WORKDIR C:/Users/name/Documents/NetBeansProjects/project1
s/src/mainpckg
---> Using cache
---> 1868e40b329e
Step 4 : RUN javac Main.java
---> Running in 66d7d769f425
javac: file not found: Main.java
Usage: javac <options> <source files>
use -help for a list of possible options
The command '/bin/sh -c javac Main.java' returned a non-zero code:
2
I also tried the solution given here:
docker run --rm -v /mypathhere/mycode java:7 sh -c "cd mycode; javac mycode.java"
but without any results, i still got this error:
javac: file not found: Main.java
Usage: javac <options> <source files>
use -help for a list of possible options
There is something fishy about C:/. Try following, it must work
FROM java:8
# add the container directory from the host
RUN mkdir /opt/mainpckg
# copy the app to container directory
ADD . /opt/mainpckg
WORKDIR /opt/mainpckg
RUN javac Main.java
CMD java Main
I don't know why you run with -v /mypathhere/mycode, as it creates a data volume which would overlay (temporarily overwrite) anything that was /mypathhere/mycode from the Dockerfile.
So try running without the -v part, in case /mypathhere/mycode is C:/Users/name/Documents/NetBeansProjects/project1 (assuming you are using Docker on Windows with Windows containers)
Related
I have Java app and want to generate docker image, I have shell script like this:
#!/bin/sh
java -version
export APPLICATION_DIR=$PWD
for rJarFile in `ls ${APPLICATION_DIR}/lib/*.jar`
do
export CLASSPATH=$rJarFile:$CLASSPATH
done
export CLASSPATH=$APPLICATION_DIR/classes:$CLASSPATH
java -Xverify:none -Xmx2048m -Djava.awt.headless=true -DFI_IS_CONFIGSER=N -DFICLIENT_APP_PATH=${APPLICATION_DIR} -DFI_APP_NAME=FIONLINE -DFI_BASE_INSTANCE_ID=1 -DPRODUCT_BOOTSTRAP_FILE=${APPLICATION_DIR}/data/BootstrapFile.properties -DFEBA_SYS_PATH=${APPLICATION_DIR}/data
And I try to convert it into Dockerfile like this
# FROM openjdk:8
FROM openjdk:11
RUN javac -version
# Create app directory
WORKDIR /usr/src/app
# Bundle app source
COPY . .
ENV APPLICATION_DIR=/usr/src/app
RUN echo $APPLICATION_DIR
RUN for rJarFile in `ls ${APPLICATION_DIR}/lib/*.jar`; do export CLASSPATH=$rJarFile:$CLASSPATH; done
RUN echo $CLASSPATH
ENV $CLASSPATH=$APPLICATION_DIR/classes:$CLASSPATH
# Run app
ENTRYPOINT ["java", "-Xverify:none", "-Xmx2048m", "-Djava.awt.headless=true", "-DFI_IS_CONFIGSER=N", "-DFICLIENT_APP_PATH=${APPLICATION_DIR} -DFI_APP_NAME=FIONLINE -DFI_BASE_INSTANCE_ID=1", "-DPRODUCT_BOOTSTRAP_FILE=${APPLICATION_DIR}/data/BootstrapFile.properties", "-DFEBA_SYS_PATH=${APPLICATION_DIR}/data"]
It can be generated, but there's an error when I try to run it like this:
Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: process_linux.go:459: container init caused: setenv: invalid argument: unknown
I've also changed this script RUN for rJarFile in `ls ${APPLICATION_DIR}/lib/*.jar`; do export into this RUN for rJarFile in ls ${APPLICATION_DIR}/lib/*.jar; do export CLASSPATH=$rJarFile:$CLASSPATH; done, but none of them working. I don't want to make Dockerfile execute the script. Below is logs when i generate and run it.
You cannot update the classpath as you do with:
ENV $CLASSPATH=$APPLICATION_DIR/classes:$CLASSPATH
instead you can do
ENV CLASSPATH=$APPLICATION_DIR/classes:$CLASSPATH
Also - please consider moving the script into a separate shell script and adding into the container. This would greatly simplify the Dockerfile, for example:
# FROM openjdk:8
FROM openjdk:11
RUN javac -version
# Create app directory
WORKDIR /usr/src/app
# Bundle app source
COPY . .
ENV APPLICATION_DIR=/usr/src/app
RUN echo $APPLICATION_DIR
ENTRYPOINT ["/usr/src/app/start_java.sh"]
and keep your existing script inside start_java.sh
Let's say we have the following Dockerfile for the purpose of creating a java image and compiling two scripts.
FROM openjdk:latest
COPY src JavaDocker
WORKDIR JavaDocker
RUN mkdir -p bin
RUN javac -d bin ./com/myapp/HelloWorld1.java
RUN javac -d bin ./com/myapp/HelloWorld2.java
WORKDIR bin
ENTRYPOINT java
How can I run any of these two scripts that have been compiled?
I'm using the command: docker run myapp-image "com.myapp.Server"
And I get:
Usage: java [options] <mainclass> [args...]
(to execute a class)
or java [options] -jar <jarfile> [args...]
(to execute a jar file)
or java [options] -m <module>[/<mainclass>] [args...]
java [options] --module <module>[/<mainclass>] [args...]
(to execute the main class in a module)
or java [options] <sourcefile> [args]
(to execute a single source-file program)
Arguments following the main class, source file, -jar <jarfile>,
-m or --module <module>/<mainclass> are passed as the arguments to
main class.
I'd suggest building a separate image per application; that can help clarify what the image is supposed to do. I also generally recommend using CMD over ENTRYPOINT.
So a Dockerfile that runs only the first application could look like:
FROM openjdk:latest
# Prefer an absolute path for clarity.
WORKDIR /JavaDocker
# Set up the Java class path.
RUN mkdir bin
ENV CLASSPATH=/JavaDocker/bin
# Use a relative path as the target, to avoid repeating it.
# (If you change the source code, repeating `docker build` will
# skip everything before here.)
COPY src .
# Compile the application.
RUN javac -d bin ./com/myapp/HelloWorld1.java
# Set the main container command.
CMD ["java", "com.myapp.HelloWorld1"]
What if you do have an image that contains multiple applications? If you use CMD here, it's very easy to provide an alternate command when you run the image:
docker run myapp-image \
java com.myapp.HelloWorld2
# Wait, what's actually in this image?
docker run --rm myapp-image \
ls -l bin/com/myapp
I generally recommend reserving ENTRYPOINT for a wrapper script that does some first-time setup, then runs exec "$#" to run a normal CMD. There's an alternate pattern of giving a complete command in ENTRYPOINT, and using CMD to provide its arguments. In both of these cases ENTRYPOINT needs to be JSON-array syntax, not shell syntax.
ENTRYPOINT ["java", "com.myapp.HelloWorld1"] # <-- JSON-array syntax
CMD ["-argument", "to-program-1"]
docker run myapp-image \
-argument=different -options
but it's harder to make that image do something else
docker run \
--entrypoint ls \ # <-- first word of the command is before the image name
myapp-image \
-l bin/com/myapp # <-- and the rest after
docker run \
--entrypoint java \
myapp-image \
com.myapp.HelloWorld2
Your original Dockerfile will probably work if you change the ENTRYPOINT line from shell to JSON-array syntax; using shell syntax will cause the CMD part to be ignored (including a command passed after the docker run image-name). You might find it easier to make one complete application invocation be the default and include the java command if you need to run the other.
I am using GraalVM to create a native image of petclinic in Java SpringBoot
Here is my DockerFile
FROM oracle/graalvm-ce:19.2.1
WORKDIR /opt/graalvm
RUN gu install native-image
COPY ./spring-petclinic/* /usr/local/
RUN native-image -jar /usr/local/spring-petclinic-2.2.0.BUILD-SNAPSHOT.jar
FROM alpine:latest
WORKDIR /usr/local/
COPY --from=0 /opt/graalvm/spring-petclinic-2.2.0.BUILD-SNAPSHOT .
CMD yes
When I am using the image and do a ls -la I see the file spring-petclinic-2.2.0.BUILD-SNAPSHOT which is the native image I want to execute
My problem append when I try to execute de binary.
I get this error message:
sh: ./spring-petclinic-2.2.0.BUILD-SNAPSHOT: not found
I cannot execute a file which exists.
I'm running the docker command in windows command line successfully but when I run the same command in windows-subsystem-for-linux it shows class not found exception.
windows:
docker run -it --cpus 4 -v ${PWD}:/app --workdir /app adoptopenjdk/openjdk11 java -cp C:\path\to\class Helloworld.java
WSL:
docker run -it --cpus 4 -v ${PWD}:/app --workdir /app adoptopenjdk/openjdk11 java -cp /path/to/class Helloworld.java
Expected output:
Hello world!!
Error:
Could not find or load main class Helloworld.java
Caused by: java.lang.ClassNotFoundException: Helloworld.java
It seems like the path may be wrong
You can also access your local machine’s filesystem from within the
Linux Bash shell – you’ll find your local drives mounted under the
/mnt folder. For example, your C: drive is mounted under /mnt/c:
-- https://learn.microsoft.com/en-us/windows/wsl/faq#what-can-i-do-with-wsl
I have docker file
FROM java:8
# Install maven
RUN apt-get update
RUN apt-get install -y maven
WORKDIR /code/
# Prepare by downloading dependencies
#ADD pom.xml /mmt/CouchBaseClient/CB-RestAPI/CacheService/pom.xml
#RUN ["mvn", "dependency:resolve"]
#RUN ["mvn", "verify"]
ADD cacheService-0.0.1-SNAPSHOT.jar /code/cacheService-0.0.1-SNAPSHOT.jar
ADD couchclient-0.0.1-SNAPSHOT.jar /code/couchclient-0.0.1-SNAPSHOT.jar
EXPOSE 4567
CMD ["/usr/lib/jvm/java-8-openjdk-amd64/bin/java", "-jar", "couchclient-0.0.1-SNAPSHOT.jar server cacheService.yml" ]
When I build this file I get the following output
Sending build context to Docker daemon 35.46 MB
Step 1 : FROM java:8
---> 736600fd4ae5
Step 2 : RUN apt-get update
---> Using cache
---> a3466698c29d
Step 3 : RUN apt-get install -y maven
---> Using cache
---> d0fb8e77f89a
Step 4 : WORKDIR /code/
---> Using cache
---> 197735d2da02
Step 5 : ADD cacheService-0.0.1-SNAPSHOT.jar /code/cacheService-0.0.1-SNAPSHOT.jar
---> 9ba30f5a2144
Removing intermediate container bd3c072ebbc6
Step 6 : ADD couchclient-0.0.1-SNAPSHOT.jar /code/couchclient-0.0.1-SNAPSHOT.jar
---> ef59315ed7fe
Removing intermediate container 0da1a69bdb51
Step 7 : EXPOSE 4567
---> Running in a2b32799dd6c
---> 3fb2b534d7c5
Removing intermediate container a2b32799dd6c
Step 8 : CMD /usr/lib/jvm/java-8-openjdk-amd64/bin/java -jar couchclient-0.0.1-SNAPSHOT.jar server cacheService.yml
---> Running in efb44e2bcdb3
---> 56637dfacc0d
Removing intermediate container efb44e2bcdb3
Successfully built 56637dfacc0d
But no directory named code is being made and so no files are being added even though it is giving no compilation error
Used method suggested by #VonC
ENTRYPOINT ["/usr/lib/jvm/java-8-openjdk-amd64/bin/java", "-jar", "couchclient-0.0.1-SNAPSHOT.jar" ]
and then used this command to run the image
docker run <image> -d <arguments>
First, don't forget that ADD <src>... <dest> can invalidate the cache for all following instructions from the Dockerfile if the contents of <src> have changed. See "Best practices" and use COPY instead of ADD.
In both cases (ADD or COPY), if <dest> doesn’t exist, it is created along with all missing directories in its path.
So no mkdir necessary.
COPY cacheService-0.0.1-SNAPSHOT.jar /code/
COPY couchclient-0.0.1-SNAPSHOT.jar /code/
Otherwise, the file cacheService-0.0.1-SNAPSHOT.jar in the folder /code/cacheService-0.0.1-SNAPSHOT.jar/!
Finally, to be sure that the files are where they should be, open a bash:
docker run --rm -it <yourImage> bash
Or, if you have a running container:
docker exec -it <yourContainer> bash
And check what ls /code returns.
Also:
docker run --rm -it --entrypoint /bin/sh <yourImage> -c "ls -alrt"
The OP Legendary Hunter confirms in the comments the files are there.
The issue comes from the CMD which is not fully in exec form.
Each parameter should be in its own quotes:
CMD ["/usr/lib/jvm/java-8-openjdk-amd64/bin/java", "-jar", "couchclient-0.0.1-SNAPSHOT.jar", "server", "cacheService.yml" ]
If the last parameters are grouped together, CMD tries to access the jar file named "couchclient-0.0.1-SNAPSHOT.jar server cacheService.yml", which obvioulsy does not exist.
Hence the error message:
"Error: Unable to access jarfile couchclient-0.0.1-SNAPSHOT.jar server cacheService.yml"
Instead of using CMD, use ENTRYPOINT (with the sa me exec form, each arg in its own double-quotes), and leave CMD undefined.
That way, the arguments you will add to your docker run command will be passed to the ENTRYPOINT (which runs java -jar ...)
Since "server", "cacheService.yml" are the two arguments to be passed to the running container:
ENTRYPOINT ["/usr/lib/jvm/java-8-openjdk-amd64/bin/java", "-jar", "couchclient-0.0.1-SNAPSHOT.jar" ]
Build and then:
docker run --rm -it <image> server cacheService.yml
Once you know it is working, launch it in detached mode:
docker run -d <image> server cacheService.yml
Try this before WORKDIR line:
RUN mkdir /code