探索Docker容器的文件系统

我在使用docker时注意到,我需要了解容器内发生了什么,或者容器中存在什么文件。一个例子是从docker索引下载图像——你不知道图像包含什么,所以不可能启动应用程序。

理想的情况是能够ssh进入它们或等效的东西。有没有工具可以做到这一点,或者我对docker的概念化错误地认为我应该能够做到这一点。

1024304 次浏览

这里有几种不同的方法…

使用docker exec(最简单)

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

docker exec -t -i mycontainer /bin/bash

Docker命令行留档

B)使用Snapshotting

您可以这样评估容器文件系统:

# find ID of your running container:docker ps
# create image (snapshot) from container filesystemdocker commit 12345678904b5 mysnapshot
# explore this filesystem using bash (for example)docker run -t -i mysnapshot /bin/bash

这样,您就可以在精确的时间时刻评估正在运行的容器的文件系统。容器仍在运行,不包括未来的更改。

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

docker rmi mysnapshot

C)使用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运行您的应用程序(连接并执行您想要的内容)。

D)使用nsenter

使用nsenter,请参阅为什么你不需要在Docker容器中运行SSHd

简短的版本是:使用nsenter,您可以将shell放入现有容器,即使该容器不运行SSH或任何类型的专用守护进程

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

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

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

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

dockerId=$(docker inspect -f \{\{.Id}} [docker_id_or_name])
cd /var/lib/docker/btrfs/subvolumes/$dockerId

您需要是root才能cd到该目录。如果您不是root,请在运行命令之前尝试“sudo su”。

编辑:在v1.3之后,看到Jiri的答案-它更好。

对我来说,这个工作得很好(感谢最后的评论指出目录/var/lib/docker/):

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

这里,2465790aa2c4是正在运行的容器的短ID(如dockerps所示),后跟一个星号。

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

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

完整的Docker版本信息:

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

如果您的容器停止或没有shell(例如安装指南中提到的hello-world或非alpinetraefik),这可能是探索文件系统的唯一可能方法。

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

docker export adoring_kowalevski > contents.tar

或者列出文件:

docker export adoring_kowalevski | tar t

请注意,根据图像的不同,它可能需要一些时间和磁盘空间。

我使用的另一个肮脏的伎俩是aufs/devicemapper不可知论者。

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

sudo -scd /proc/$(pgrep java)/root/

瞧,你在容器里。

基本上,只要容器运行该进程,您就可以将root cd作为/proc/<PID>/root/文件夹。注意符号链接在使用该模式时没有意义。

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

许多容器(尤其是基于go的容器)没有任何标准二进制文件(没有/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身份运行它。

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

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

对于docker aufs驱动程序:

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

if [ -z "$1" ] ; thenecho 'docker-find-root $container_id_or_name 'exit 1fiCID=$(docker inspect   --format \{\{.Id}} $1)if [ -n "$CID" ] ; thenif [ -f  /var/lib/docker/image/aufs/layerdb/mounts/$CID/mount-id ] ; thenF1=$(cat /var/lib/docker/image/aufs/layerdb/mounts/$CID/mount-id)d1=/var/lib/docker/aufs/mnt/$F1fiif [ ! -d "$d1" ] ; thend1=/var/lib/docker/aufs/diff/$CIDfiecho $d1fi

了解容器内部发生了什么的首选方法是:

  1. 曝光-p 8000

    docker run -it -p 8000:8000 image
  2. Start server inside it

    python -m SimpleHTTPServer

更新:探索!

这个命令应该让你探索正在运行的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。

注:这个答案依赖于存在的共享工具,但是如果没有bash shell或像ls这样的常见工具,如果您可以访问Dockerfile,您可以首先在图层中添加一个:高山的例子:

RUN apk add --no-cache bash

否则,如果您无法访问Dockerfile,那么只需将文件复制出新创建的容器并通过执行以下操作来查看它们:

docker create <image>  # returns container ID the container is never started.docker cp <container ID>:<source_path> <destination_path>docker rm <container ID>cd <destination_path> && ls -lsah

docker exec留档

docker撰写exec留档

docker检查留档

docker创建留档

这个答案将帮助那些想要探索docker卷文件系统的人(比如我自己),即使容器没有运行。

列出正在运行的docker容器:

docker ps

=>容器ID"4c721f1985bd"

查看本地物理机器上的docker卷挂载点(https://docs.docker.com/engine/tutorials/dockervolumes/):

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

=> [{ /tmp/容器-garren /tmptrue rPrivate}]

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

了解本地物理机目录(/tmp/容器-garren)意味着我可以探索docker容器是否正在运行的文件系统。这对帮助我找出即使容器没有运行也不应该保留的剩余数据至关重要。

投票最多的答案是在容器实际启动时为我工作,但是当它无法运行并且您想从容器中复制文件时,这已经救了我:

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

感谢docker cp(链接),您可以直接从容器中复制,就像它是文件系统的任何其他部分一样。例如,恢复容器内的所有文件:

mkdir /tmp/container_tempdocker cp example_container:/ /tmp/container_temp/

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

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

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

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

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

容器创建之前:

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

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

这将为您提供图像的所有层及其配置的可见性,这些配置存在于json文件中。

创建容器后:

对于这一点,上面已经有很多答案了。我的首选方式这将是-

docker exec -t -i container /bin/bash

尝试使用

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

可能有可能bash没有实现。为此,您可以使用

docker exec -it <container-name> sh

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

# docker-layer musing_wilesrw layer : /var/lib/docker/aufs/diff/c83338693ff190945b2374dea210974b7213bc0916163cc30e16f6ccf1e4b03fmnt      : /var/lib/docker/aufs/mnt/c83338693ff190945b2374dea210974b7213bc0916163cc30e16f6ccf1e4b03f

编辑2018-03-28:
docker层已被替换为docker备份

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

Usage:  docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
Run a command in a running container
Options:-d, --detach               Detached mode: run command in the background--detach-keys string   Override the key sequence for detaching acontainer-e, --env list             Set environment variables-i, --interactive          Keep STDIN open even if not attached--privileged           Give extended privileges to the command-t, --tty                  Allocate a pseudo-TTY-u, --user string          Username or UID (format:[:])-w, --workdir string       Working directory inside the container

例如:

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

docker exec -it containerId bash

2)在bash中以root身份访问正在运行的容器文件系统,以便能够拥有所需的权限:

docker exec -it -u root containerId bash

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

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

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

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

docker exec -it <container-name> sh

您可以使用dive与TUI交互查看图像内容

https://github.com/wagoodman/dive

在此处输入图片描述

这将为图像启动一个bash会话:

docker运行--rm-it--entrypoint=/bin/bash

仅适用于linux

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

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

    PID=$(docker检查-f'\{\{. State. Pid}}''你的容器名称)

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

    cd /proc/$PID/root

如果您想在不找出PID数字的情况下通过dir,只需使用此长命令

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

温馨提示:

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

希望有帮助

备注:

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

现有的答案都没有解决容器退出(无法重新启动)和/或没有安装任何shell(例如无发行版)的情况。只要你对Docker主机有root访问权限,这个就可以工作。

对于真正的手动检查,首先找出层ID:

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

在输出中,您应该看到如下内容

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

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

如果您使用的是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

我想这样做,但是我无法执行到我的容器中,因为它已经停止并且由于我的代码中的一些错误而没有再次启动。

对我有效的方法是简单地将整个容器的内容复制到一个新文件夹中,如下所示:

docker cp container_name:/app/ new_dummy_folder

然后,我能够像使用普通文件夹一样探索此文件夹的内容。

实际上我使用的所有容器都有Python,所以我附加到容器上,

pip install jupyterlabcd /jupyter lab --allow-root

我^点击Jupyter Lab服务器提供的链接,在主机的浏览器中,我有完美的文件系统GUI,可以打开各种文件(ipnb,py,md(预览版),…)

干杯
G.

通常我只需要探索docker文件系统,因为我的构建不会运行,所以docker run -it <container_name> bash是不切实际的。我也不想浪费时间和内存复制文件系统,所以docker cp <container_name>:<path> <target_path>也是不切实际的。

虽然可能是非正统的,但我建议使用ls作为Dockerfile中的最终命令重新构建:

CMD [ "ls", "-R" ]

我发现了最简单的,一体化的解决方案,可以在几乎任何正在运行的容器中使用GUI应用程序查看,编辑,复制文件。

mc在docker中编辑文件

  1. 在容器内安装mc和ssh:docker exec -it <container> /bin/bash,然后提示安装mc和ssh包
  2. 在同一个exec-bash控制台中,运行mc
  3. 按ESC,然后按9,然后按ENTER打开菜单并选择“Shell link…”
  4. 使用“Shell link…”打开基于SCP的文件系统访问任何主机,并通过其IP地址运行ssh服务器(包括运行docker的主机)
  5. 在图形UI中做好你的工作

这种方法克服了权限,快照隔离等所有问题,允许直接复制到任何机器,对我来说是最愉快的使用

我有一个未知的容器,它正在做一些生产工作负载,不想运行任何命令。

所以我用了docker diff

这将列出容器已更改的所有文件,因此非常适合探索容器文件系统。

要仅获取一个文件夹,您可以使用grep:

docker diff <container> | grep /var/log

它不会显示docker映像中的文件。这取决于您的用例是否有帮助。

派对迟到了,但在2022年我们有VS代码