我试图为我们的开发过程构建一个新的Docker映像,使用cpanm安装一堆Perl模块作为各种项目的基本映像。

在开发Dockerfile时,cpanm返回一个失败代码,因为一些模块没有干净地安装。

我很确定我需要准备安装更多的东西。

我在哪里可以找到/。在输出中引用Cpanm /work目录,以便检查日志?在一般情况下,我如何检查一个失败的docker构建命令的文件系统?

在运行一个发现后,我发现

/var/lib/docker/aufs/diff/3afa404e[...]/.cpanm

这是可靠的吗,还是我最好构建一个“裸”容器并手动运行一些东西,直到我拥有所有我需要的东西?


当前回答

我的解决方案是看看docker文件中的哪一步失败了,在我的情况下运行bundle安装,

把它改成

RUN bundle install || cat <path to the file containing the error>

这有双重效果,打印出失败的原因,并且这个中间步骤不会被docker构建认为是失败的。所以它不会被删除,并且可以通过以下方式进行检查:

docker run --rm -it <id_last_working_layer> bash -il

在那里,您甚至可以重新运行失败的命令并进行实时测试。

其他回答

仍然使用BuildKit,正如Alexis Wilke的回答,您可以使用ktock/ building。

参见Kohei Tokunaga的“Dockerfile的交互式调试器”

build是一个基于BuildKit交互调试Dockerfile的工具。 源代码级检验 断点和步骤执行 交互式shell的一步与您自己的调试工具 基于BuildKit(需要未合并的补丁) 支持无根的

例子:

$ buildg.sh debug --image=ubuntu:22.04 /tmp/ctx
WARN[2022-05-09T01:40:21Z] using host network as the default            
#1 [internal] load .dockerignore
#1 transferring context: 2B done
#1 DONE 0.1s

#2 [internal] load build definition from Dockerfile
#2 transferring dockerfile: 195B done
#2 DONE 0.1s

#3 [internal] load metadata for docker.io/library/busybox:latest
#3 DONE 3.0s

#4 [build1 1/2] FROM docker.io/library/busybox@sha256:d2b53584f580310186df7a2055ce3ff83cc0df6caacf1e3489bff8cf5d0af5d8
#4 resolve docker.io/library/busybox@sha256:d2b53584f580310186df7a2055ce3ff83cc0df6caacf1e3489bff8cf5d0af5d8 0.0s done
#4 sha256:50e8d59317eb665383b2ef4d9434aeaa394dcd6f54b96bb7810fdde583e9c2d1 772.81kB / 772.81kB 0.2s done
Filename: "Dockerfile"
      2| RUN echo hello > /hello
      3| 
      4| FROM busybox AS build2
 =>   5| RUN echo hi > /hi
      6| 
      7| FROM scratch
      8| COPY --from=build1 /hello /
>>> break 2
>>> breakpoints
[0]: line 2
>>> continue
#4 extracting sha256:50e8d59317eb665383b2ef4d9434aeaa394dcd6f54b96bb7810fdde583e9c2d1 0.0s done
#4 DONE 0.3s
...

目前最新的docker-desktop,没有办法选择退出 的新Buildkit,它还不支持调试(请参考 在这个GitHub线程上的最新更新: https://github.com/moby/buildkit/issues/1472)。

找出Dockerfile中的哪一行出错了。 添加到Dockerfile的顶部:FROM xxx作为调试 添加一个额外的目标:FROM xxx作为下一个,就在失败命令的前一行(因为你不想构建那部分)。例子:

FROM xxx as debug
RUN echo "working command"

FROM xxx as next
RUN echoo "failing command"

运行docker build -f Dockerfile——target debug——tag debug。 然后你可以调试容器:docker运行- debug /bin/sh

您可以通过按CTRL P + CTRL Q退出shell

如果你想使用docker compose build而不是docker build,可以在docker-compose中添加target: debug。Yml正在建设中。 然后通过docker撰写运行xxxYourServiceNamexxx来启动容器,并使用其中之一:

上面的第二个答案是找出如何在容器中运行shell。 或者在FROM xxx之前添加ENTRYPOINT /bin/sh作为Dockerfile中的下一行。

在我的情况下,我必须:

DOCKER_BUILDKIT=1 docker build ...

正如Jannis Schönleber在他的回答中提到的,目前在这种情况下没有可用的调试(即没有创建中间映像/容器)。

我发现我可以使用以下选项:

... --progress=plain ...

然后添加各种RUN…或现有RUN上的附加行…调试特定的命令。在我看来,这给了你完全的访问权限(至少如果你的构建相对较快)。

例如,你可以这样检查一个变量:

RUN echo "Variable NAME = [$NAME]"

如果你想知道文件是否正确安装,你可以这样做:

RUN find /

etc.

在我的情况下,我必须调试一个带有私有存储库的Go应用程序的docker构建,并且很难进行调试。我这里还有其他细节。

Docker在每个成功的RUN行之后缓存整个文件系统状态。

知道:

检查RUN命令失败之前的最新状态,在Dockerfile中注释掉它(以及任何和所有后续的RUN命令),然后运行docker build和docker RUN。 要检查RUN命令失败后的状态,只需添加|| true来强制它成功;然后像上面那样进行(保留所有后续RUN命令,运行docker build和docker RUN)

也就是说,无需修改Docker内部代码或层id,而且作为额外的奖励,Docker会自动最小化需要重新完成的工作量。

如果您希望在命令失败之前立即检查状态,上面的答案是有效的。

但是,问题询问如何检查失败容器本身的状态。在我的情况下,失败的命令是一个需要几个小时的构建,所以在失败的命令之前倒回并再次运行它需要很长时间,而且没有太大帮助。

这里的解决方案是找到失败的容器:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                          PORTS               NAMES
6934ada98de6        42e0228751b3        "/bin/sh -c './utils/"   24 minutes ago      Exited (1) About a minute ago                       sleepy_bell

将其提交到一个图像:

$ docker commit 6934ada98de6
sha256:7015687976a478e0e94b60fa496d319cdf4ec847bcd612aecf869a72336e6b83

然后运行映像[如果需要,运行bash]:

$ docker run -it 7015687976a4 [bash -il]

现在您实际上看到的是构建失败时的状态,而不是运行导致失败的命令之前的状态。