简体   繁体   中英

Docker doesn't create files in specified volume

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.

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 the docker 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.

File 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 .

File 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.

File 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.

File 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.

File 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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM