探索Docker容器的文件系统


651

我注意到docker,我需要了解容器内部发生的情况或其中存在的文件。一个示例是从docker索引下载图像-您不知道该图像包含什么,因此无法启动该应用程序。

理想的情况是能够使用它们或等效方法。是否有工具可以做到这一点,或者我对docker的构想在认为我应该能够做到这一点上是错误的。


13
在泊坞窗的最新版本,这样的事情是可能的:docker exec <container> bash。因此,您只需打开容器内的外壳。
dashohoxha,2016年

7
只有在容器内安装了bash时,才能在容器上运行bash
Christopher Thomas

7
同样,您可以执行:docker exec <container> ls <dir path>docker exec <container> cat <file path>。对于bash,请添加-it选项。
Noam Manos


3
@ChristopherThomas,完全是。因此,我发现唯一可靠的方法就是使用docker image save image_name > image.tar@ Gaurav24的响应中所示的方法。
Jaime Hablutzel

Answers:


736

UPDATE
最简单的方法:使用docker exec

Docker 1.3或更高版本支持exec行为与相似的命令nsenter。该命令可以在已运行的容器中运行新进程(容器必须已运行PID 1进程)。您可以运行/bin/bash以探索容器状态:

docker exec -t -i mycontainer /bin/bash

请参阅Docker命令行文档

替代方法1
快照

您可以通过以下方式评估容器文件系统:

# find ID of your running container:
docker ps

# create image (snapshot) from container filesystem
docker commit 12345678904b5 mysnapshot

# explore this filesystem using bash (for example)
docker run -t -i mysnapshot /bin/bash

这样,您可以在准确的时间评估运行中的容器的文件系统。容器仍在运行,不包括将来的更改。

您可以稍后使用(不影响正在运行的容器的文件系统!)删除快照:

docker rmi mysnapshot

备用方法2
SSH

如果需要连续访问,可以将sshd安装到您的容器中并运行sshd守护程序:

 docker run -d -p 22 mysnapshot /usr/sbin/sshd -D

 # you need to find out which port to connect:
 docker ps

这样,您可以使用ssh运行您的应用程序(连接并执行所需的操作)。

更新:替代方法3
nsenter

使用nsenter,请参阅https://web.archive.org/web/20160305150559/http://blog.docker.com/2014/06/why-you-dont-need-to-run-sshd-in-docker/

简短的版本是:使用nsenter,您可以将shell放入现有容器中,即使该容器未运行SSH或任何特殊用途的守护程序


6
但是请注意,如果需要访问文件,请使用“ docker cp”命令。用法:docker cp CONTAINER:PATH HOSTPATH将文件/文件夹从容器文件系统复制到主机路径。路径是相对于文件系统根目录的。#> docker cp 7bb0e258aefe:/ etc / debian_version。#> docker cp blue_frog:/ etc / hosts。
Amos Folarin 2014年

4
选项4非常重要,应将其移至顶部并重命名Option 1
自变形图片

5
@JanusTroelsen如果没有外壳,则可以安装它-例如,在用于linux的dockerfile中(确实没有外壳),方法:(RUN apk update && apk add bash大小:
〜4MB

2
根据我自己的经验,Docker exec的局限性在于该命令必须添加到正在运行的容器上或作为一种入口点。因此,停止的容器不在此方法的范围内。
Webwoman

1
要使用Window的linux shell,请使用docker exec -t -i mycontainer /bin/sh
Jason Masters

266

更新:探索中!

此命令应让您探索正在运行的docker容器

docker exec -it name-of-container bash

docker-compose中的等效项为:

docker-compose exec web bash

(在这种情况下,web是服务名称,默认情况下它具有tty。)

一旦进入内部,请执行以下操作:

ls -lsa

或任何其他bash命令,例如:

cd ..

此命令应让您浏览docker映像

docker run --rm -it --entrypoint=/bin/bash name-of-image

进入内部后,请执行以下操作:

ls -lsa

或任何其他bash命令,例如:

cd ..

-it交互式……和tty 的代表。


此命令应让您检查正在运行的docker容器或映像

docker inspect name-of-container-or-image

您可能想要这样做,并找出是否存在任何bashsh在那里。在json返回中查找入口点或cmd。

请参阅docker exec文档

请参阅docker-compose exec文档

请参阅docker inspect文档


1
这非常有用,谢谢!我需要将docker图像文件结构中包含的文件拖放到应用程序中,但是除非以GUI格式打开它,否则这是不可能的。知道我该如何解决吗?
Arkya Chatterjee

2
很明显,这仅适用于已安装bash的容器。
软件工程师

2
对于希望在Windows Container / Powershell上执行此操作的人员,命令为docker exec -ti <name> powershellsource
ssell

1
@ssell由于某种原因,我的容器/图像没有Powershell,因此可以使用docker exec -ti <name> cmd。对于像我这样的其他新手,请确保使用来自docker ps(例如070494393ca5)的容器实例名称,而不是您为其分配的可读名称。
Simon_Weaver

1
在图像方面的PowerShell github.com/aspnet/aspnet-docker/issues/362 -如果你只需要卷曲在Windows图片:blogs.technet.microsoft.com/virtualization/2017/12/19/...
Simon_Weaver

162

万一您的容器停下来或没有外壳(例如安装指南中hello-world提到的容器,或非alpine traefik),则这可能是探索文件系统的唯一可能方法。

您可以将容器的文件系统归档到tar文件中:

docker export adoring_kowalevski > contents.tar

或列出文件:

docker export adoring_kowalevski | tar t

请注意,根据映像,可能要花费一些时间和磁盘空间。


12
我只想列出未安装标准UNIX工具的容器的内容。export上面示例的变化很明显:docker export adoring_kowalevski | tar tf -
berto

3
谨防警告:这可能会导出大量数据(> GB)并花费很长时间。
文斯·鲍德伦

5
@berto并不是说这很麻烦,但是您不必f -在命令末尾使用,默认情况下tar会从标准输入中读取。简单地docker export adoring_kowalevski | tar t工作。
肖恩·布卡特

越简单越好;太棒了,谢谢你的提示!🙌🏽–
berto

1
@ShaunBouckaert的默认值tar f取决于一个人的配置。一部分是TAPE环境变量。其他作为构建的一部分受到控制。最终结果是,永远不要假设它读取stdin或写入stdout,而始终明确声明它。
roaima

42

容器的文件系统位于docker的数据文件夹中,通常位于/ var / lib / docker中。为了启动和检查正在运行的容器文件系统,请执行以下操作:

hash=$(docker run busybox)
cd /var/lib/docker/aufs/mnt/$hash

现在,当前的工作目录是容器的根目录。


3
但是,这将不包括任何已装入的卷。
hwjp

34

创建容器之前:

如果您要探索安装在容器内的图像的结构,则可以

sudo docker image save image_name > image.tar
tar -xvf image.tar

这将使您可以看到图像的所有层及其在json文件中存在的配置的可见性。

创建容器后:

为此,上面已经有很多答案。我这样做的首选方式是-

docker exec -t -i container /bin/bash


这里应该提到的是,只有在与映像具有相同体系结构的机器上进行操作时,才可以在容器内运行bash。如果您在PC上尝试浏览树莓派的图像文件系统,则bash技巧将不起作用。
Maxim Kulkin

@MaximKulkin真的吗?如果容器是Linux,则主机是什么,如果bash可用,也没有关系。也许您在考虑Windows容器?
托尔比约恩Ravn的安徒生

26

当容器真正启动时,最受支持的答案对我有用,但是当无法运行时,例如,您想从容器中复制文件,这在以前为我节省了时间:

docker cp <container-name>:<path/inside/container> <path/on/host/>

多亏了docker cp(link),您可以直接从容器进行复制,因为它是文件系统的任何其他部分。例如,恢复容器内的所有文件:

mkdir /tmp/container_temp
docker cp example_container:/ /tmp/container_temp/

请注意,您无需指定要递归复制。


6
为什么没有更多的+1!绝对是最好的方法
Nicholas DiPiazza'Mar

这比通过tar导出更简单。我必须使用-L通过符号链接访问文件。无需运行容器!
MKaama

17

在运行Docker 1.3.1的Ubuntu 14.04上,我在主机上的以下目录中找到了容器根文件系统:

/var/lib/docker/devicemapper/mnt/<container id>/rootfs/

完整的Docker版本信息:

Client version: 1.3.1
Client API version: 1.15
Go version (client): go1.3.3
Git commit (client): 4e9bbfa
OS/Arch (client): linux/amd64
Server version: 1.3.1
Server API version: 1.15
Go version (server): go1.3.3
Git commit (server): 4e9bbfa

就像魅力一样工作:name = <名称> dockerId = $(docker inspect -f {{.Id}} $ name)/ var / lib / docker / devicemapper / mnt / $ dockerId / rootfs /
Florent

3
不幸的是,使用Ubuntu 16.10和docker 1.12.1时,情况不再如此(没有devicemapper目录)。该文件位于下/var/lib/docker/overlay/<a sha256 apparently/<upper or merged>/...。我不确定在那里访问文件的便携性/安全性
WoJ

1
从1.10开始,Docker引入了一种新的内容可寻址存储模型,该模型不使用随机生成的UUID,就像以前的层和容器标识符一样。在新模型中,这被层ID的安全内容哈希替换。因此,此方法将不再起作用。
Artem Dolobanko

这不是可移植的,并且在很大程度上取决于存储驱动程序的选择。direct-lvm例如,不确定该解决方案是否适用。
rustyx

14

尝试使用

docker exec -it <container-name> /bin/bash

可能没有执行bash。为此,您可以使用

docker exec -it <container-name> sh

12

我使用了另一个与aufs / devicemapper无关的dirty俩。

我看一下容器正在运行的命令,例如docker ps ,如果它是一个apache或java我只是执行以下操作:

sudo -s
cd /proc/$(pgrep java)/root/

瞧,你在容器里。

基本上,您可以将root cd放入/proc/<PID>/root/文件夹,只要该进程由容器运行即可。当心使用该模式的符号链接毫无意义。


有关此方法的其他信息,请访问:superuser.com/a/1288058/195840
Eduardo Lucio,

12

投票最多的答案是好的,除非您的容器不是实际的Linux系统。

许多容器(尤其是基于go的容器)没有任何标准二进制文件(no /bin/bash/bin/sh)。在这种情况下,您将需要直接访问实际的容器文件:

奇迹般有效:

name=<name>
dockerId=$(docker inspect -f {{.Id}} $name)
mountId=$(cat /var/lib/docker/image/aufs/layerdb/mounts/$dockerId/mount-id)
cd /var/lib/docker/aufs/mnt/$mountId

注意:您需要以root身份运行。


这不再起作用。devicemapper文件夹不存在。
0xcaff

如果答案过时的人将它们清理干净,那就太好了
Matthew Purdon

2
我更新了命令以匹配新的docker存储结构。
佛罗伦萨

10

在我的情况下,除了,容器中没有任何外壳支持sh。所以,这就像一个魅力

docker exec -it <container-name> sh


5

这将启动映像的bash会话:

泊坞窗运行--rm -it --entrypoint = / bin / bash


1
当默认入口点不运行时,这很有用
解析此

4

对我来说,这很好用(由于最后的注释指出了目录/ var / lib / docker /):

chroot /var/lib/docker/containers/2465790aa2c4*/root/

在这里,2465790aa2c4是正在运行的容器的短ID(由docker ps显示),后跟一个星号。


4

在较新版本的Docker上,您可以运行 docker exec [container_name]在容器内运行shell的容器

因此,要获取容器中所有文件的列表,只需运行 docker exec [container_name] ls


1
我试过了,但是没有用。上面的Khalil Gharbaoui的建议奏效了。
尼克,

那对我有用。您也可以尝试使用容器ID代替图像名称
Diwann

4

对于docker aufs驱动程序:

该脚本将找到容器根目录(在docker 1.7.1和1.10.3上测试)

if [ -z "$1" ] ; then
 echo 'docker-find-root $container_id_or_name '
 exit 1
fi
CID=$(docker inspect   --format {{.Id}} $1)
if [ -n "$CID" ] ; then
    if [ -f  /var/lib/docker/image/aufs/layerdb/mounts/$CID/mount-id ] ; then
        F1=$(cat /var/lib/docker/image/aufs/layerdb/mounts/$CID/mount-id)
       d1=/var/lib/docker/aufs/mnt/$F1
    fi
    if [ ! -d "$d1" ] ; then
        d1=/var/lib/docker/aufs/diff/$CID
    fi
    echo $d1
fi

4

现有的答案都无法解决容器退出(且无法重新启动)和/或未安装任何外壳(例如,无坚硬的外壳)的情况。只要您具有对Docker主机的root访问权限,此方法就可以工作。

为了进行真正的手动检查,请先找出层ID:

docker inspect my-container | jq '.[0].GraphDriver.Data'

在输出中,您应该看到类似

"MergedDir": "/var/lib/docker/overlay2/03e8df748fab9526594cfdd0b6cf9f4b5160197e98fe580df0d36f19830308d9/merged"

导航到此文件夹(作为根目录)以找到容器文件系统的当前可见状态。


3

这个答案将帮助那些想要探索docker卷文件系统的人(像我本人),即使该容器未运行。

列出正在运行的Docker容器:

docker ps

=>容器ID“ 4c721f1985bd”

查看本地物理机上的Docker卷安装点(https://docs.docker.com/engine/tutorials/dockervolumes/):

docker inspect -f {{.Mounts}} 4c721f1985bd

=> [{/ tmp / container-garren / tmp true rprivate}]

这告诉我,本地物理机目录/ tmp / container-garren映射到/ tmp docker卷目标。

知道本地物理机目录(/ tmp / container-garren)意味着我可以探索文件系统,无论Docker容器是否正在运行。这对帮助我弄清楚即使在容器未运行后,有些残留数据也不应该持久存在至关重要。


1
这只会在容器中找到作为卷安装的本地目录,但不允许访问容器的整个文件系统。
Bojan Komazec,

3

另一个技巧是使用原子工具执行以下操作:

mkdir -p /path/to/mnt && atomic mount IMAGE /path/to/mnt

Docker映像将被挂载到/ path / to / mnt,以供您检查。


但是您需要具有特制的容器才能工作,对吗?也许您应该将其添加为警告,因为大多数人都无法将其作为解决方案出售给他们的团队/公司...
Angelos Pikoulas 18-10-10

3

仅适用于LINUX

我使用的最简单方法是使用proc dir,该容器必须处于运行状态才能检查docker容器文件。

  1. 找出容器的进程ID(PID)并存储到某个变量中

    PID = $(docker inspect -f'{{.State.Pid}}'your-container-name-here)

  2. 确保容器进程正在运行,并使用变量名进入容器文件夹

    cd / proc / $ PID / root

如果您只想通过使用此长命令来查找目录而不查找PID号,

cd /proc/$(docker inspect -f '{{.State.Pid}}' your-container-name-here)/root

提示:

进入容器后,您所做的一切都会影响容器的实际过程,例如停止服务或更改端口号。

希望能帮助到你

注意:

此方法仅在容器仍在运行时才起作用,否则,如果容器已停止或删除,则该目录将不再存在


2

我了解容器内部发生的事情的首选方式是:

  1. 暴露-p 8000

    docker run -it -p 8000:8000 image
    
  2. 在其中启动服务器

    python -m SimpleHTTPServer
    

2

对于已经运行的容器,您可以执行以下操作:

dockerId=$(docker inspect -f {{.Id}} [docker_id_or_name])

cd /var/lib/docker/btrfs/subvolumes/$dockerId

您需要是root用户才能进入该目录。如果您不是root用户,请在运行命令之前尝试'sudo su'。

编辑:在v1.3之后,请参阅Jiri的答案-更好。


4
我强烈偏爱“ sudo -i”而不是“ sudo su”,因为没有理由运行一个suid程序来启动另一个suid程序来启动一个shell。切掉中间人。:)
dannysauer 2014年

您的回答很好,只有路径没有。您应该使用Piercebot的路径。
佛罗伦萨

2

如果您使用的是Docker v19.03,请按照以下步骤操作。

# find ID of your running container:

  docker ps

# create image (snapshot) from container filesystem

  docker commit 12345678904b5 mysnapshot

# explore this filesystem 

  docker run -t -i mysnapshot /bin/sh

1

如果您使用的是AUFS存储驱动程序,则可以使用我的docker-layer脚本查找任何容器的文件系统根(mnt)和读写层:

# docker-layer musing_wiles
rw layer : /var/lib/docker/aufs/diff/c83338693ff190945b2374dea210974b7213bc0916163cc30e16f6ccf1e4b03f
mnt      : /var/lib/docker/aufs/mnt/c83338693ff190945b2374dea210974b7213bc0916163cc30e16f6ccf1e4b03f

编辑2018-03-28:
docker-layer已由docker-backup取代


1

docker exec命令在运行中的容器中运行一个命令可以在多种情况下帮助。

用法:docker exec [OPTIONS]容器命令[ARG ...]

在正在运行的容器中运行命令

选项:
  -d,--detach分离模式:在后台运行命令
      --detach-keys string覆盖分离序列的键序列
                             容器
  -e,-env列表设置环境变量
  -i,--interactive即使未连接也保持STDIN打开
      --privileged为命令赋予扩展权限
  -t,--tty分配伪TTY
  -u,--user字符串用户名或UID(格式:
                             [:])
  -w,--workdir字符串容器内的工作目录

例如 :

1)在bash中访问正在运行的容器文件系统:

docker exec -it containerId bash 

2)以root身份访问bash到正在运行的容器文件系统中,以具有必需的权限:

docker exec -it -u root containerId bash  

这对于以根用户身份在容器中进行一些处理特别有用。

3)在bash中访问具有特定工作目录的正在运行的容器文件系统:

docker exec -it -w /var/lib containerId bash 

0

您可以使用以下命令在容器内运行bash: $ docker run -it ubuntu /bin/bash

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.