1

我创建了这个小演示程序来显示我遇到的问题。

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();
    }
}

}

我正在使用这个 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"]

这些命令来构建容器

mvn clean package
docker build -t please/work .

最后但并非最不重要的是这个命令来运行容器

docker run please/work -v /root/hayasaka:/usr/app/

我也试过用这个

docker run please/work -v /root/hayasaka:/

但在这两种情况下,都不会在 /root/hayasaka 创建文件

这是我在运行容器时得到的控制台输出

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)

理论上应该在指定卷中创建1.txt或2.txt。哦,我也使用 Spring 初始化程序创建了项目,因为实际项目也是使用该工具创建的。作为可选依赖项,我只选择了开发工具,我没有更改 pom.xml 文件中的任何内容。

4

1 回答 1

2

编辑:为了使这个答案完整,我添加了在对该问题的评论中已经提到的内容。-v该命令上的开关docker run未正确定位的事实。

您的执行在这里没有按预期运行的首要原因只是-v /some/path开关附加到docker run命令的末尾,在图像名称之后。

docker run --help生成此输入语法描述:

Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

这里它指出[OPTIONS]必须在图像名称之前提供。所有选项开关都以 single 或 double-开头,并且在大多数情况下,后面是开关的参数。因此docker二进制文件将识别命令的第一个参数,该参数前面docker run没有作为图像-的名称。

图像名称后面的参数将被解释为覆盖命令 ( [COMMAND] [ARG...]),并附加到构建图像的ENTRYPOINT定义中。Dockerfile

您已定义ENTRYPOINT

ENTRYPOINT ["java","-jar","demo.jar"]

鉴于您提供的第一个示例执行是这样的:

docker run please/work -v /root/hayasaka:/usr/app/

在容器中执行的结果命令将是这样的:

java -jar demo.jar -v /root/hayasaka:/usr/app/

这当然不是你的本意。如果程序可能不期望任何参数,它会简单地忽略它们。

以下是您的输入和结果的概述。

文件1.txt

    create(".", "1");

这将成为./1.txt,或绝对而言/usr/app/1.txt,这是一条良好且有效的路径。该文件1.txt将在 java 进程的工作目录中创建,该目录又是启动 java 程序的用户的工作目录,您在Dockerfileto 中设置了该文件/usr/app

文件2.txt

    create("", "2");

这将创建文件/2.txt,容器中文件系统根目录中的文件。鉴于只有目录/usr/app是卷映射的,因此从容器外部看不到该文件。

文件3.txt

    create("app/usr", "3");

这将创建文件app/usr/3.txt,该文件是相对于 java 进程的工作目录的位置。绝对路径是/usr/app/app/usr/3.txt。这失败了,很可能是由于缺少中间目录结构app/usr。使用此方法解决问题:

    if (!myObj.getParentFile().exists()) {
        myObj.getParentFile().mkdirs();

这将创建缺少的中间目录。

文件4.txt

    create("/usr/app", "4");

这将创建 file /usr/app/4.txt,一个存在的绝对路径,因为 docker build 将使用给定的Dockerfile定义创建它。这里没有问题。

文件5.txt

    create("usr/app", "5")

这会尝试创建文件usr/app/5.txt,就像文件3.txt是相对于 java 进程的工作目录的位置一样。绝对路径是/usr/app/usr/app/5.txt它会因为失败的相同原因而3.txt失败。

我希望这提供了一个很好的概述!

于 2020-06-21T19:20:44.707 回答