如何在Docker容器内获取磁盘使用情况

3
我已经使用--privileged标志启动了容器,据我所知,所有磁盘都应该在容器内可用,这在某种程度上是正确的,但我无法读取它们的大小。
主机(Ubuntu)上的lsblk
sda                     8:0    1  59,6G  0 disk  
└─sda1                  8:1    1  59,6G  0 part  /media/mauz/ESD-ISO
nvme0n1               259:0    0 953,9G  0 disk  
├─nvme0n1p1           259:1    0   512M  0 part  /boot/efi
├─nvme0n1p2           259:2    0   732M  0 part  /boot
└─nvme0n1p3           259:3    0 952,7G  0 part  
  └─nvme0n1p3_crypt   253:0    0 952,6G  0 crypt 
    ├─vgubuntu-root   253:1    0 930,4G  0 lvm   /
    └─vgubuntu-swap_1 253:2    0   976M  0 lvm   [SWAP]

在容器(Alpine)中使用lsblk命令:
sda           8:0    1  59.6G  0 disk 
└─sda1        8:1    1  59.6G  0 part 
nvme0n1     259:0    0 953.9G  0 disk 
├─nvme0n1p1 259:1    0   512M  0 part 
├─nvme0n1p2 259:2    0   732M  0 part 
└─nvme0n1p3 259:3    0 952.7G  0 part

这两个输出都是从loop设备中剥离出来的,但是你可以看到,两个设备都被识别了。

现在,如果我在主机上运行df命令:

Filesystem                1K-blocks      Used Available Use% Mounted on
tmpfs                       3261580      2564   3259016   1% /run
/dev/mapper/vgubuntu-root 959200352 137078032 773327904  16% /
tmpfs                      16307884    215740  16092144   2% /dev/shm
tmpfs                          5120         4      5116   1% /run/lock
/dev/nvme0n1p2               721392    364788    304140  55% /boot
/dev/nvme0n1p1               523248     76232    447016  15% /boot/efi
tmpfs                       3261576       140   3261436   1% /run/user/1000
/dev/sda1                  62519040  23118848  39400192  37% /media/mauz/ESD-ISO

在容器内部:

Filesystem           1K-blocks      Used Available Use% Mounted on
overlay              959200352 137078188 773327748  15% /
tmpfs                    65536         0     65536   0% /dev
shm                      65536         0     65536   0% /dev/shm
/dev/mapper/vgubuntu-root
                     959200352 137078188 773327748  15% /app
/dev/mapper/vgubuntu-root
                     959200352 137078188 773327748  15% /etc/os-release
/dev/mapper/vgubuntu-root
                     959200352 137078188 773327748  15% /etc/resolv.conf
/dev/mapper/vgubuntu-root
                     959200352 137078188 773327748  15% /etc/hostname
/dev/mapper/vgubuntu-root
                     959200352 137078188 773327748  15% /etc/hosts

在第二个 df 输出中,一些驱动器的显示是不正确的。有没有办法让 df 显示正确的输出,即使在容器内部也是如此?

或者,还有其他方法可以从主机获取正确的磁盘大小和使用情况吗?


好的,那么我该如何使它们相同呢?/dev/sda似乎已经挂载(lsblk),只是df没有对其进行任何操作。如果您确实知道一些内容,那么能否详细说明一下会很好。@Philippe - MauriceNino
我该如何读取未挂载驱动器的磁盘大小呢?我需要所有磁盘的大小,因为我正在开发一种监视单个节点资源的仪表板。这是一个开源项目,因此安装的便捷性是其中一个重要的卖点 - 这就是为什么它需要被docker化的原因。@Philippe - MauriceNino
这可能不是最适合这种应用程序的方式,但它是唯一可行的解决方案,因此我将使用docker来完成它。目前,我正在手动传递所有挂载的卷,但我希望有一个更清晰的解决方案。@Philippe - MauriceNino
所有增加太多开销的东西都不可行,所以不幸的是,这对我的问题不是一个好的解决方案。@Philippe - MauriceNino
2个回答

2
使用nsenter命令,这个命令应该能够实现你想要的功能:
docker run -it --rm --privileged --pid host ubuntu nsenter -t 1 -m -u -n -i bash

# --privileged : run privileged
# --pid host   : shares host's process id namespace

# nsenter - run program with namespaces of other processes
# -t 1        : Specify process 1 to get contexts from
# -m -u -n -i : Share mount, UTS, network, IPC namespace.

我添加了其他标志,因为我认为您可能正在监视除挂载点以外的其他资源。 - Philippe
是的,我只是想了解你在做什么。当我在容器中执行此操作并输入“ls”时,我可以看到主机所有文件。但之后我就无法再次执行我的应用程序了。有没有办法将主机挂载到应用程序上下文中? - MauriceNino
抱歉,我的Linux及其命令的知識非常有限。我需要一種從應用程序內部訪問df結果的方法。我的應用程序沒有任何花俏的操作,只需要在相同的上下文中運行(如果有意義的話?)。 - MauriceNino
以上命令应该可以工作,请尝试构建您的 Node.js 应用程序并运行它。 - Philippe
事实上,我现在所询问的只是比当前问题多一层而已,我并没有想到这会成为一个问题。但是我在这里只得到了两个答案(还有悬赏),所以我不认为我会在另一个问题中得到答案。 - MauriceNino
显示剩余7条评论

2
“没有一个‘合理’的解决方案可以实现你想要的,但让我解释一下为什么。

你谈论了‘磁盘使用情况’,但实际上并不存在所谓的磁盘使用情况。就磁盘本身而言,根本不存在‘使用情况’这个概念。你寻找的是文件系统磁盘使用情况,这是根本不同的东西。

为了知道文件系统的‘已用’和‘可用’空间,你需要挂载它。这允许内核处理文件系统元数据,然后可用于确定空闲和已用的文件系统块。如果不挂载文件系统,则内核无法获取此信息(因此对于例如df是不可用的)。”

为了让Docker正常工作,容器必须使用与主机不同的挂载命名空间。这样做的核心原因是,通常情况下容器不能安全地共享与主机相同的挂载点。例如,如果主机上的/和容器中的/指向同一个挂载点,那么一旦容器启动,它很可能会触及不应该触及的敏感文件而破坏系统。因此,默认情况下,Docker会将容器“隔离”在自己的挂载命名空间中,以便它们只能看到它们需要的挂载点,并且由于上述原因,没有避免这种隔离的选项。
您可以通过读取可用块设备的原始数据(而无需挂载它们),并在容器中使用一些专门的工具解析文件系统元数据(如果有的话)来获取此信息,但这是一个棘手的解决方案,因为基本上需要每种可能的文件系统类型都有一个工具。也可以参见Unix & Linux SE上的未挂载分区中的空闲空间
您还可以使用绑定挂载,允许主机和容器共享挂载点,但这必须针对每个挂载点进行操作,例如:
docker run --mount readonly,type=bind,source=/media/mauz/ESD-ISO,target=/container/path ...
$ df
...
/dev/sda1                  62519040  23118848  39400192  37% /container/path
...

您说现在您正在手动挂载所有卷,因此我认为这与您目前正在做的事情没有区别。除了相当丑陋外,这种解决方案还有一个限制,即无法处理主机上设备或挂载点的更改(例如,如果添加并挂载新设备)。
我能看到的唯一“真正”的解决方案是在主机上运行一些应用程序,定期提取所需信息并将其传递给容器内部运行的应用程序。

感谢您详细的回答。我已经考虑过使用工具来读取未挂载的磁盘,但是我甚至无法找到每种文件系统类型的工具。您的第二个建议基本上就是我现在正在做的事情。我指示我的用户使用-v /mnt:/mnt/host_mnt:ro-v /media:/mnt/host_media:ro来处理最常见的挂载点(不确定是否100%正确),但正如您所说,这并不是非常一致的,因为如果用户决定在其他地方挂载设备,则不会显示。但是我认为在主机上运行一个应用程序甚至更加丑陋。 - MauriceNino
如果没有更多的答案,我会授予你奖励金,因为这似乎有点不可能。 - MauriceNino
@MauriceNino 嗯,根据使用情况,告诉用户“此工具仅监视您在启动之前选择的卷,并且不会监视新挂载的卷”或类似内容可能是有意义的,因此您当前的解决方案仍然是有意义的。 - Marco Bonelli
是的,这正是我现在正在做的事情。引用“需要在/media:/mnt/host_media:ro/mnt:/mnt/host_mnt:ro上挂载卷以读取所有驱动器的使用统计信息。如果您的驱动器挂载在其他位置,则需要使用以下格式传递该驱动器路径:-v /{path}:/mnt/host_{path}:ro。” - MauriceNino

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