【问题标题】:Exploring Docker container's file system探索 Docker 容器的文件系统
【发布时间】:2014-01-15 19:13:06
【问题描述】:

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

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

【问题讨论】:

  • 在最新版本的 Docker 中,这样的事情是可能的:docker exec <container> bash。因此,您只需在容器内打开一个外壳。
  • 只有在容器内安装了 bash 时,在容器上运行 bash 才有效
  • 同样,您可以这样做:docker exec <container> ls <dir path>docker exec <container> cat <file path>。但是,对于 bash,请添加 -it 选项。
  • @ChristopherThomas,没错。因此,我发现唯一可靠的方法是使用@Gaurav24 的回复中指出的docker image save image_name > image.tar

标签: linux docker filesystems


【解决方案1】:

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

A) 使用 docker exec (最简单)

Docker 1.3 或更高版本支持命令exec,其行为类似于nsenter。该命令可以在已经运行的容器中运行新进程(容器必须已经运行了 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
【解决方案2】:

更新:探索!

这个命令应该让你探索一个正在运行的 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 返回中查找 entrypoint 或 cmd。

注意:此答案依赖于存在的 commen 工具,但如果没有 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 documentation

docker-compose exec documentation

docker inspect documentation

docker create documentation

【讨论】:

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

如果您的容器已停止或没有外壳(例如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,而是始终明确声明。
【解决方案4】:

创建容器之前:

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

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 提示符。
【解决方案5】:

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

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

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

【讨论】:

  • 这不会包括任何已安装的卷。
【解决方案6】:

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

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 通过符号链接访问文件。无需运行容器!
【解决方案7】:

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

https://github.com/wagoodman/dive

【讨论】:

  • Dive 真是完美的工具!
【解决方案8】:

尝试使用

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

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

docker exec -it <container-name> sh

【讨论】:

    【解决方案9】:

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

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

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

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

    瞧,你在容器里面。

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

    【讨论】:

    【解决方案11】:

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

    docker exec -it <container-name> sh
    

    【讨论】:

      【解决方案12】:

      投票最多的答案是好的,除非您的容器不是实际的 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 的系统上,mountId 现在位于 /var/lib/docker/image/overlay2/$dockerId/mount-id 并且挂载的文件系统位于 /var/lib/docker/ overlay2/$mountId/merged/ 或者您只需使用上面@Raphael 的好答案,即使再次更改覆盖 fs 的使用方式,它也应该继续工作。
      【解决方案13】:

      仅适用于 LINUX

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

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

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

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

        cd /proc/$PID/root

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

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

      提示:

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

      希望对你有帮助

      注意:

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

      【讨论】:

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

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

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

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

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

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

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

      【讨论】:

      • 不幸的是,对我来说,即使容器的文件系统显然不是,该文件夹也是空的。 :\
      【解决方案15】:

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

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

      【讨论】:

      • 我试过了,但没用。 Khalil Gharbaoui 的上述建议奏效了。
      • 这对我有用。您也可以尝试使用容器 id 而不是图像名称
      【解决方案16】:

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

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

      docker cp container_name:/app/ new_dummy_folder
      

      然后我可以像浏览普通文件夹一样浏览该文件夹的内容。

      【讨论】:

        【解决方案17】:

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

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

        【讨论】:

          【解决方案18】:

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

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

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

          【讨论】:

            【解决方案19】:

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

            【讨论】:

              【解决方案20】:

              即使容器没有运行,这个答案也会帮助那些(像我一样)想要探索 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 容器是否正在运行,我都可以探索文件系统。这对于帮助我找出即使在容器未运行后也不应该保留的一些残留数据至关重要。

              【讨论】:

              • 这只会找到一个本地目录,该目录作为卷挂载在容器内,但不允许访问容器的整个文件系统。
              【解决方案21】:

              对于已经运行的容器,你可以这样做:

              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 的路径。
              【解决方案22】:

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

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

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

              【讨论】:

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

              了解容器内部情况的首选方式是:

              1. 暴露 -p 8000

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

                python -m SimpleHTTPServer
                

              【讨论】:

                【解决方案24】:

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

                【讨论】:

                  【解决方案25】:

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

                  【讨论】:

                    【解决方案26】:

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

                    用法:docker exec [OPTIONS] CONTAINER COMMAND [ARG...] 在正在运行的容器中运行命令 选项: -d, --detach 分离模式:在后台运行命令 --detach-keys string 覆盖用于分离的键序列 容器 -e, --env list 设置环境变量 -i, --interactive 保持 STDIN 打开,即使没有附加 --privileged 赋予命令扩展权限 -t, --tty 分配一个伪 TTY -u, --user 字符串用户名或 UID(格式: [:]) -w, --workdir string 容器内的工作目录

                    例如:

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

                    docker exec -it containerId bash 
                    

                    2) 以 root 身份在 bash 中访问正在运行的容器文件系统以获得所需的权限:

                    docker exec -it -u root containerId bash  
                    

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

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

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

                    【讨论】:

                      【解决方案27】:

                      您可以在容器内运行 bash,如下所示: $ docker run -it ubuntu /bin/bash

                      【讨论】:

                        【解决方案28】:

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

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

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

                        干杯
                        G.

                        【讨论】:

                          【解决方案29】:

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

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

                          CMD [ "ls", "-R" ]
                          

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 2021-04-04
                            • 2020-03-12
                            • 1970-01-01
                            • 1970-01-01
                            • 2018-02-28
                            • 1970-01-01
                            • 2019-09-27
                            相关资源
                            最近更新 更多