Java应用程序如何知道它正在Docker容器中运行?

5
我已经编写了一个DockerFile来运行我的应用程序(通过Docker)在NAS机器上。Web界面允许用户遍历文件系统树查找音乐文件,但使用Docker时,除了/Music卷是用户实际音乐文件夹的挂载点外,文件系统树都是无关紧要的。
因此,我只想显示/Music文件夹,而不是整个文件系统树,为了做到这一点,应用程序需要知道它实际运行在Docker中,而不是在本地Linux操作系统中。
应用程序如何正确地知道它在Docker中,该应用程序是用Java编写的。

4
这不是重复问题,因为这个答案特别询问如何在Java中进行检查,这一点其他答案没有涉及。 - Paul Taylor
2个回答

14

解决方案

通过 /proc/1/cgroup 检查 init 进程的控制组。

  • 如果它是正常启动的,则所有层次结构都具有 / 的值。
  • 如果它是从 Docker 容器中启动的,则它们具有 /docker/<container_id> 的值。

在 Docker 内部运行时,/proc/1/cgroup 具有类似以下值的内容:

11:perf_event:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
10:memory:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
9:cpuset:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
8:net_cls,net_prio:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
7:pids:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
6:cpu,cpuacct:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
5:blkio:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
4:freezer:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
3:hugetlb:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
2:devices:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249
1:name=systemd:/docker/897df2a033d6ab07c357c1ac1f75741bd16474487de83c6d4d98518e5ef52249

注意: 此处为@JanisKirsteins所提供的信息,如果您在Amazon EC2中运行应用程序,则可能需要将条件更改为line.contains("/ecs"),因为在/proc/1/cgroups中,您会发现类似于以下模式的格式:/ecs/<uuid>/<uuid>


使用Java语言

public static Boolean isRunningInsideDocker() {

        try (Stream < String > stream =
            Files.lines(Paths.get("/proc/1/cgroup"))) {
            return stream.anyMatch(line -> line.contains("/docker"));
        } catch (IOException e) {
            return false;
        }
    }

实时代码检查


更多信息


谢谢,那似乎是正确的答案。 - Paul Taylor
值得注意的是,需要用文件存在检查来包装,例如在Windows上可能没有这个文件。 - Paul Taylor
亲爱的@PaulTaylor,我更新了我的答案,当文件不存在时,它会抛出一个异常,你可以从那里返回false,我提供了两个链接来实时检查代码:其中一个运行在docker中,另一个不运行。 - MohammadReza Alagheband
感谢您在此事上的所有帮助。 - Paul Taylor
这将会忽略在 ECS 中运行的应用程序(其中路径将是 /ecs/<uuid>/<uuid>)。 - Janis Kirsteins
@JanisKirsteins,谢谢您提到这个问题,我之前并不知道,我会更新我的帖子。 - MohammadReza Alagheband

-2

当您运行容器时,请添加volume选项。

docker run -v /Music:/Music <image-name>

冒号右侧是您的应用程序查找目录的位置。我假设它是 /Music。

如果您真的想检查您的应用程序是否正在 Docker 内运行,您可以检查是否存在文件“/.dockerenv”。根据您的问题,您应该知道的一件事是,当您的应用程序在 Docker 内运行时,除非您通过卷授予访问权限,否则它无法访问主机的文件系统。因此,如果您的实际 Linux 机器有一个目录 /Music,则您的应用程序无法访问它。您可以通过 --volume 来提供访问权限。当您在 Docker 内运行应用程序时,您可以将其视为在其他虚拟机或计算机上运行,从而达到 Docker 本身的主要目的:提供隔离。


1
是的,我可以做到,但这不是问题所在。我的应用程序如何知道它正在Docker内运行?它可以检查/Music文件夹是否存在,但真正的Linux机器也可能有/Music文件夹。我想问的是是否有一种标准方法来识别是否在Docker中运行,例如uname是否会告诉你这一点。 - Paul Taylor
更新了答案以回答您的问题。 - techtabu
1
根据链接的答案,/.dockenv 不是一个可靠的解决方案。你对 Docker 的主要用途的理解是错误的,如果 Docker 应用程序无法访问真实的文件系统,它们大多数都没有用处。 - Paul Taylor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接