Reputation: 165
I created this little demo program to show the problem I'm having.
public class DemoApplication {
public static void main(String[] args) {
create(".", "1");
create("", "2");
create("app/usr", "3");
create("/usr/app", "4");
create("usr/app", "5");
}
public static void create(String location, String name) {
try {
File myObj = new File(location+ "/" + name + ".txt");
if (myObj.createNewFile()) {
System.out.println("File created: " + myObj.getName());
} else {
System.out.println("File already exists.");
}
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
}
}
I'm using this Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} /usr/app/demo.jar
WORKDIR /usr/app/
VOLUME /usr/app/
ENTRYPOINT ["java","-jar","demo.jar"]
these commands to build the container
mvn clean package
docker build -t please/work .
and last but not least this command to run the container
docker run please/work -v /root/hayasaka:/usr/app/
I've also tried using this
docker run please/work -v /root/hayasaka:/
but in both cases no files get created at /root/hayasaka
This is the console output I get when running the container
File created: 1.txt
File created: 2.txt
An error occurred.
java.io.IOException: No such file or directory
at java.io.UnixFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:1012)
at com.example.demo.DemoApplication.create(DemoApplication.java:23)
at com.example.demo.DemoApplication.main(DemoApplication.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:109)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
File created: 4.txt
An error occurred.
java.io.IOException: No such file or directory
at java.io.UnixFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:1012)
at com.example.demo.DemoApplication.create(DemoApplication.java:23)
at com.example.demo.DemoApplication.main(DemoApplication.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:109)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
In theory 1.txt or 2.txt should be created in the specified volume. Oh, also I created the project using the Spring initializer, as the real project also was created using that tool. As optional dependencies I only selected the Developer tools and I did not change anything in the pom.xml file.
Upvotes: 1
Views: 2744
Reputation: 4220
EDIT: To make this answer complete, I am adding what is already mentioned in a comment on the question. The fact that the
-v
switch on thedocker run
command is not positioned correctly.
The overarching reason that your execution is not behaving as expected here, is simply that the -v /some/path
switch is appended to the end of the docker run
command, after the image name.
docker run --help
produces this input syntax description:
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Here it states that [OPTIONS]
must be provided before the name of the image. All option switches are preceeded with a single or double -
, and for most cases follwed by a parameter to the switch. And so the docker
binary will identify the first argument to the docker run
commnand, that is not preceeded with -
as the name of the image.
Arguments follwing the name of the image, will be interpreted as an overriding command ([COMMAND] [ARG...]
), and be appended to the ENTRYPOINT
defined in the Dockerfile
from which the image was built.
You have defined the ENTRYPOINT
:
ENTRYPOINT ["java","-jar","demo.jar"]
And given that the first example execution you provide is this:
docker run please/work -v /root/hayasaka:/usr/app/
The resulting command executed in the container will then be this:
java -jar demo.jar -v /root/hayasaka:/usr/app/
This is of course not your intention. And if the program probably does not expect any arguments, it will simply disregard them.
Here's an overview of your input and the outcomes.
1.txt
create(".", "1");
This will become ./1.txt
, or in absolute terms /usr/app/1.txt
, which is a fine and valid path. The file 1.txt
will be created in the working directory of the java process, which in turn is the working directory of the user that initiates the java program, which you have set in the Dockerfile
to be /usr/app
.
2.txt
create("", "2");
This will create the file /2.txt
, a file in the root of the filesystem in the container. given that only the directory /usr/app
is volume mapped, this file will not be visible from outside the container.
3.txt
create("app/usr", "3");
This would create the file app/usr/3.txt
, which is a location relative to the working directory of the java process. The absolute path is /usr/app/app/usr/3.txt
. This fails, most likely due to the missing intermediate directory structure app/usr
. Use this approach to resolve the issue:
if (!myObj.getParentFile().exists()) {
myObj.getParentFile().mkdirs();
That will create the missing intermediate directories.
4.txt
create("/usr/app", "4");
This will create the file /usr/app/4.txt
, an absolute path that exists, since the docker build will create it with the given Dockerfile
definition. No problems here.
5.txt
create("usr/app", "5")
This attempts to create the file usr/app/5.txt
, which like the file 3.txt
is a location relative to the working directory of the java process. The absolute path is /usr/app/usr/app/5.txt
It will fail for the same reasons that 3.txt
fails.
I hope this provides a good overview!
Upvotes: 2