ChatGPT解决这个技术问题 Extra ChatGPT

探索 Docker 容器的文件系统

我注意到 docker 我需要了解容器内发生了什么或其中存在哪些文件。一个例子是从 docker index 下载图像——你不知道图像包含什么,因此无法启动应用程序。

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

在最新版本的 Docker 中,可能会出现这样的情况:docker exec <container> bash。因此,您只需在容器内打开一个外壳。
仅当容器内安装了 bash 时,在容器上运行 bash
同样,您可以这样做:docker exec <container> ls <dir path>docker exec <container> cat <file path>。但是,对于 bash,请添加 -it 选项。
@ChristopherThomas,确切地说。因此,我发现这样做的唯一可靠方法是使用 docker image save image_name > image.tar,如@Gaurav24 的响应中所示。

1
10 revs, 6 users 68%

这里有几种不同的方法......

A)使用 docker exec(最简单)

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

docker exec -t -i mycontainer /bin/bash

Docker command line documentation

B) 使用快照

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

# 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

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,见 Why you don't need to run SSHd in your Docker containers

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


但请注意,如果您需要访问文件,请使用“docker cp”命令用法: docker cp CONTAINER:PATH HOSTPATH 将文件/文件夹从容器文件系统复制到主机路径。路径是相对于文件系统的根目录的。 #> docker cp 7bb0e258aefe:/etc/debian_version 。 #> docker cp blue_frog:/etc/hosts 。
选项 4 非常重要,应将其移至顶部并重命名为 Option 1
@JanusTroelsen 如果没有外壳,您可以安装它 - 例如在 alpine linux 的 dockerfile 中(确实没有外壳):RUN apk update && apk add bash(大小:~4MB)
根据我自己的经验,Docker exec 的限制是该命令必须添加到正在运行的容器上或作为一种入口点。因此,停止的容器超出了此方法的范围。
要使用 Window 的 linux shell,请使用 docker exec -t -i mycontainer /bin/sh
K
Khalil Gharbaoui

更新:探索!

这个命令应该让你探索一个正在运行的 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 等常用工具,如果您有权访问 { 3}:高山的例子:

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 documentation

docker-compose exec documentation

docker inspect documentation

docker create documentation


这非常有用,谢谢!我需要将包含在 docker 图像文件结构中的文件拖放到应用程序中,但除非它以 GUI 格式打开,否则这是不可能的。知道我该如何解决这个问题吗?
很明显,这只适用于安装了 bash 的容器。
对于想在 Windows Container/Powershell 上执行此操作的任何人,命令是 docker exec -ti <name> powershell (source)
@ssell 我的容器/图像由于某种原因没有 powershell,所以 docker exec -ti <name> cmd 工作。对于像我这样的其他新手,请确保使用来自 docker ps 的容器实例名称(类似于 070494393ca5),而不是您为其分配的可读名称。
关于图像中的 powershell github.com/aspnet/aspnet-docker/issues/362 - 如果您只需要在 Windows 图像上卷曲:blogs.technet.microsoft.com/virtualization/2017/12/19/…
x
x-yuri

如果您的容器已停止或没有外壳(例如 installation guide 中提到的 hello-world 或非 alpine traefik),这可能是探索文件系统的唯一可能方法。

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

docker export adoring_kowalevski > contents.tar

或列出文件:

docker export adoring_kowalevski | tar t

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


我只是想列出一个没有安装标准 UNIX 工具的容器的内容。上面 export 示例的一个变体恰如其分:docker export adoring_kowalevski | tar tf -
对粗心的人的警告:这可能会导出大量数据(> GB)并需要很长时间。
@berto 并不是说这是一件大事,但是您不需要 f - 在命令末尾, tar 默认情况下从标准输入读取。只需 docker export adoring_kowalevski | tar t 即可。
越简单越好;太棒了,谢谢你的提示! 🙌🏽
@ShaunBouckaert tar f 的默认值取决于一个人的配置。一部分是 TAPE 环境变量。其他的则作为构建的一部分进行控制。最终结果是,永远不要假设它读取 stdin 或写入 stdout,但始终明确说明。
J
Julius Printz

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

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

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

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

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


为什么这没有更多的+1!绝对是最好的方法
这比通过 tar 导出还要简单。我必须使用 -L 通过符号链接访问文件。无需运行容器!
这应该是公认的答案!特别是如果您想在 docker 容器由于某种原因(“调试”)无法运行时探索文件系统。这种方式简单易行。
G
Gaurav Ingalkar

容器创建之前:

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

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

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

容器创建后:

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

docker exec -t -i container /bin/bash

这里应该提到的是,只有在与映像具有相同架构的机器上运行 bash 才能在容器内运行。如果您在 PC 上试图窥探 raspberry pi 的图像文件系统,那么 bash 技巧将不起作用。
@MaximKulkin 真的吗?如果容器是 Linux,那么主机是什么并不重要,如果 bash 可用。也许您正在考虑 Windows 容器?
在极少数情况下,我只能在容器中未加载 bash 时输入 sh 提示。
R
Rovanion

容器的文件系统在docker的data文件夹下,一般在/var/lib/docker。为了启动和检查正在运行的容器文件系统,请执行以下操作:

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

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


不过,这不包括任何已安装的卷。
A
Andy Wong

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

https://github.com/wagoodman/dive

https://i.stack.imgur.com/OLFEC.png


潜水真的是完美的工具!
G
Gaurav Sharma

尝试使用

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

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

docker exec -it <container-name> sh

p
piercebot

在运行 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/
不幸的是,在 Ubuntu 16.10 和 docker 1.12.1 中,情况不再如此(没有devicemapper目录)。该文件存在于 /var/lib/docker/overlay/<a sha256 apparently/<upper or merged>/... 下。我不确定在那里访问文件的便携性/安全性
从 1.10 开始,Docker 引入了一种新的内容可寻址存储模型,它不使用随机生成的 UUID,就像以前用于层和容器标识符一样。在新模型中,这被层 id 的安全内容散列所取代。所以这种方法将不再有效。
这不是可移植的,很大程度上取决于 storage driver 的选择。例如,不确定该解决方案是否适用于 direct-lvm
s
shx

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

docker exec -it <container-name> sh

谢谢,考虑到OP询问如何通过SSH进入容器,我觉得这应该更高。
t
telamon

我使用了另一个与 aufs/devicemapper 无关的肮脏技巧。

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

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

瞧,你在容器里面。

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


此处有关此方法的其他信息:superuser.com/a/1288058/195840
A
Aditya Kresna Permana

仅适用于 LINUX

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

找出容器的进程ID(PID)并将其存储到某个变量中 PID=$(docker inspect -f '{{.State.Pid}}' your-container-name-here) 确保容器进程正在运行, 并使用变量名进入容器文件夹 cd /proc/$PID/root

如果你想通过 dir 而不找出 PID 号,只需使用这个长命令

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

提示:

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

希望能帮助到你

笔记:

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


这应该更高。我的 Docker 主机的文件系统以只读方式挂载,所以我无法使用 docker cp。相反,需要一条我可以通过 scp 从主机中提取的直接路径,而您的解决方案为我提供了一条。谢谢!
F
Florent

投票最多的答案是好的,除非您的容器不是实际的 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 身份运行它。


这不再有效。 devicemapper 文件夹不存在。
如果答案过时的人会清理它们会很好
我更新了命令以匹配新的 docker 存储结构。
在我运行 docker 19.03 的系统上,现在可以在 /var/lib/docker/image/overlay2/$dockerId/mount-id 中找到 mountId,并且已安装的文件系统位于 /var/lib/docker/overlay2/$mountId/merged/ 或您只需使用上面@Raphael 的好答案,即使再次更改覆盖 fs 的使用方式,它也应该继续工作。
R
Raphael

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

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

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

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

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

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


不幸的是,对我来说,即使容器的文件系统显然不是,该文件夹也是空的。 :\
x
xrh

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

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


我试过这个,但没有用。 Khalil Gharbaoui 的上述建议奏效了。
这对我有用。您也可以尝试使用容器 ID 而不是图像名称
f
flyer2403

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

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

docker cp container_name:/app/ new_dummy_folder

然后,我可以像使用普通文件夹一样探索该文件夹的内容。


L
LeYAUable

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

docker run --rm -it --entrypoint=/bin/bash


d
dashohoxha

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

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

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


q
qxo

对于 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

G
Garren S

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

列出正在运行的 docker 容器:

docker ps

=> 容器 ID“4c721f1985bd”

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

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

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

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

了解本地物理机目录 (/tmp/container-garren) 意味着无论 docker 容器是否正在运行,我都可以探索文件系统。这对于帮助我找出即使在容器未运行后也不应该保留的一些残留数据至关重要。


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

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

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

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

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

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


我非常偏爱“sudo -i”而不是“sudo su”,因为没有理由运行一个启动另一个启动 shell 的 suid 程序的 suid 程序。剪掉中间人。 :)
你的答案很好,只是路径不是。您应该使用 piercebot 的路径。
G
Giuseppe Scrivano

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

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

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


但是你需要有特制的容器才能工作,对吧?也许您应该将其添加为警告,因为大多数人无法将其作为解决方案出售给他们的团队/公司...
s
saurabh tiwari

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

m
m00am

我更喜欢了解容器内部发生的事情的方法是:

暴露 -p 8000 docker run -it -p 8000:8000 image 在里面启动服务器 python -m SimpleHTTPServer


V
Vince

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


d
davidxxx

在正在运行的容器中运行命令的 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 a
                             container
  -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) 以 root 身份访问正在运行的容器文件系统以获得所需的权限:

docker exec -it -u root containerId bash  

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

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

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

t
tim-montague

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

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

CMD [ "ls", "-R" ]

s
sschoof

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

所以,我使用了 docker diff

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

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

docker diff <container> | grep /var/log

它不会显示来自 docker 映像的文件。根据您的用例,这可能有帮助或没有帮助。


Y
Yang Yu

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


g
gue22

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

pip install jupyterlab
cd /
jupyter lab --allow-root

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

干杯G。