当前位置: 首页 > 科技观察

在容器的文件系统中查找文件的五种快速方法

时间:2023-03-15 08:20:11 科技观察

如果您经常使用容器,那么在某些时候您可能想要查看正在运行的容器的文件系统。也许容器行为不正常,你想阅读一些日志,也许你想检查容器内的一些配置文件......或者,也许,像我一样,你想在该容器中的二进制文件上放置一些eBPF探测器(稍后详细说明)。不管是什么原因,在这篇文章中,我们将介绍一些可用于检查容器中文件的方法。我们将从查看容器文件系统的简单且通常推荐的方法开始,并讨论为什么它们并不总是有效。接下来,我们将对Linux内核如何管理容器文件系统有一个基本的了解,我们将使用它以一种不同但仍然简单的方式检查文件系统。方法1:执行到容器中如果您快速搜索一下如何检查容器的文件系统,您会发现一个常见的解决方案是使用Docker命令:dockerexec-itmycontainer/bin/bash这是一个很好的起点.如果它满足您的所有需求,您应该继续使用它。然而,这种方法的一个缺点是它需要容器内存在一个外壳。如果容器中没有/bin/bash、/bin/sh或其他shell,此方法将不起作用。例如,我们为Pixie项目构建的许多容器都是基于distroless的,并且不包含用于保持图像较小的shell。在这些情况下,这种方法不起作用。即使shell可用,您也无法访问您习惯使用的所有工具。因此,如果容器中没有安装grep,那么你也无法访问grep。这是寻找更好工作的另一个原因。方法二:使用nsenter如果深入研究,您会发现容器进程与Linux主机上的任何其他进程一样,但在命名空间中运行以将它们与系统的其余部分隔离开来。所以你可以使用nsenter命令进入目标容器的命名空间,使用类似这样的东西:#GetthehostPIDoftheprocessinthecontainerPID=$(dockercontainerinspectmycontainer|jq'.[0].State.Pid')#Usensentertogointothecontainer'smountnamespace.sudonsenter-m-t$PID/bin/bash进入目标进程的挂载(-m)命名空间(-t$PID),运行/bin/bash。进入挂载命名空间本质上意味着我们获得了容器所见的文件系统视图。这种方法似乎比docker的exec方法更有前途,但也有类似的问题:它需要将/bin/bash(或其他shell)包含在目标容器中。如果我们输入的不是挂载命名空间,我们仍然可以访问主机上的文件,但是因为我们在执行/bin/bash(或其他shell)之前进入挂载命名空间,如果挂载命名空间中没有shell,我们是倒霉。方法三:使用dockercopy解决这个问题的另一种方法是简单地将相关文件复制到宿主机上,然后使用复制的文件。要从正在运行的容器中复制选定的文件,您可以使用:dockercpmycontainer:/path/to/filefile您还可以使用以下方法对整个文件系统进行快照:dockerexportmycontainer-ocontainer_fs.tar这些命令使您可以在容器运行时检查文件当您可能没有shell或您需要的工具时,这些命令是对前两种方法的巨大改进。方法四:查找主机上的文件系统复制方法解决了我们的许多问题,但是如果您要监视日志文件怎么办?或者,如果您尝试将eBPF探测器部署到容器中的文件怎么办?在这些情况下,复制将不起作用。我们想直接从主机访问容器的文件系统。容器的文件应该在主机的文件系统中,但是在哪里呢?Docker的检查命令给了我们一个线索:dockercontainerinspectmycontainer|jq'.[0].GraphDriver'这给了我们:{"Data":{"LowerDir":"/var/lib/docker/overlay2/63ec1a08b063c0226141a9071b5df7958880aae6be5dc9870aff179it/ab3:/var/lib/docker/overlay2/524a0d000817a3c20c5d32b79c6153aea545ced8eed7b78ca25e0d74c97efc0d/diff","MergedDir":"/var/lib/docker/overlay2/63ec1a08b063c0226141a9071b5df7958880aae6be5dc9870a279a13ff7134ab/merged","UpperDir":"/var/lib/docker/overlay2/63ec1a08b063c0226141a9071b5df7958880aae6be5dc9870a279a13ff7134ab/diff","WorkDir":"/var/lib/docker/overlay2/63ec1a08b063c0226141a9071b5df7958880aae6be5dc9870a279a13ff7134ab/work"},"Name":"overlay2"}我们来分析一下:LowerDir:包含容器中所有层的文件系统,最后一层除了UpperDir:最上层容器的文件系统。这也是反映任何运行时修改的地方。MergedDir:文件系统所有层的组合视图。WorkDir:用于管理文件系统的内部工作目录。基于overlayfs的容器文件系统结构。因此,要查看容器中的文件,只需查看MergedDir路径即可。sudols/var/lib/docker/overlay2/63ec1a08b063c0226141a9071b5df7958880aae6be5dc9870a279a13ff7134ab/merged如果您想了解有关文件系统如何工作的更多详细信息,可以查看MartinHeinz关于覆盖文件系统的博客文章:https://martinheinz.dev/blog/44。方法五:/proc//root把最好的留到最后,有一种更简单的方法可以从主机上找到容器的文件系统。使用容器内进程的主机PID,您可以简单地运行:sudols/proc//rootLinux已经为您提供了进程挂载命名空间的视图。此时,您可能会想:我们为什么不采用这种方法并将其变成一篇单行博客文章呢?但这全都与旅程有关,对吗?奖励:/proc//mountinfo对于好奇,方法4中讨论的有关容器覆盖文件系统的所有信息也可以直接从Linux/proc文件系统中找到。如果您查看/proc//mountinfo,您将看到如下内容:236314700:90//rw,relatimemaster:91-overlayoverlayrw,lowerdir=/var/lib/docker/overlay2/l/YZVAVZS6HYQHLGEPJHZSWTJ4ZU:/var/lib/docker/overlay2/l/ZYW5O24UWWKAUH6UW7K2DGV3PB,upperdir=/var/lib/docker/overlay2/63ec1a08b063c0226141a9071b5df7958880aae6be5dc9870a279a13ff7134ab/diff,workdir=/var/lib/docker/overlay2/63ec1a08b063c0226141a9071b5df7958880aae6be5dc9870a279a13ff7134ab/work236423630:93//procrw,nosuid,nodev,noexec,relatime-procprocrw236523630:94//devrw,nosuid-tmpfstmpfsrw,size=65536k,mode=755,inode64...这里可以看到容器挂载了一个overlay文件系统作为root。它还报告与dockerinspect报告相同类型的信息,包括容器文件系统的LowerDir和UpperDir。它不直接显示MergedDir,但您可以直接使用UpperDir并将diff更改为merged,这样您就可以看到容器的文件系统。我们如何在Pixie使用它在这篇博客的开头,我提到了Pixie项目如何需要将eBPF探测器放在容器上。为什么以及如何?Pixie内部的Stirling模块负责收集可观测数据。由于它是k8s原生的,因此收集的大部分数据来自在容器中运行的应用程序。Stirling还使用eBPF探测器从其监控的进程中收集数据。例如,Stirling在OpenSSL上部署eBPF探测器来跟踪加密消息(如果您想了解更多详细信息,请参阅SSLTracing博客[1])。由于每个容器都捆绑了自己的OpenSSL和其他库,因此Stirling部署的任何eBPF探测器都必须位于容器内的文件上。因此,Stirling使用本文讨论的技术在K8s容器中找到感兴趣的库,然后将eBPF探测器从主机部署到这些二进制文件上。下图概述了在另一个容器中部署eBPF探测器的工作原理。Stirling通过挂载主机文件系统,然后在主机上找到目标容器文件系统,在其他容器上部署eBPF探针。总之,我希望您下次需要检查容器中的文件时尝试使用这些技巧。一旦体验到不受容器有无外壳限制的自由,你可能再也回不去了。只需访问/proc//root!