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

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

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

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

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

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

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


当前回答

更新更新的docker版本20.10以上

Linux或macOS

DOCKER_BUILDKIT=0 docker build ...

窗户

# Command line
set DOCKER_BUILDKIT=0 docker build ...
# PowerShell
$env:DOCKER_BUILDKIT=0

使用 DOCKER_BUILDKIT=0 docker build… 从旧版本中获取中间容器哈希值。

在较新的版本上,Buildkit默认是激活的。建议仅将其用于调试目的。Build Kit可以使您的构建更快。

供参考: Buildkit不支持中间容器哈希:https://github.com/moby/buildkit/issues/1053

感谢@David Callanan和@MegaCookie的投入。

其他回答

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

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

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

$ 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]

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

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

知道:

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

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

如果您正在使用docker-compose来构建docker映像,请尝试在命令之前添加DOCKER_BUILDKIT=0,以查看最后一个成功的层id

DOCKER_BUILDKIT=0 docker-compose ... 

这将暂时禁用命令的DOCKER_BUILDKIT。

有了最后一个层id,您可以使用从顶部答案的命令连接到它

docker run --rm -it LAST_LAYER_ID sh

更新更新的docker版本20.10以上

Linux或macOS

DOCKER_BUILDKIT=0 docker build ...

窗户

# Command line
set DOCKER_BUILDKIT=0 docker build ...
# PowerShell
$env:DOCKER_BUILDKIT=0

使用 DOCKER_BUILDKIT=0 docker build… 从旧版本中获取中间容器哈希值。

在较新的版本上,Buildkit默认是激活的。建议仅将其用于调试目的。Build Kit可以使您的构建更快。

供参考: Buildkit不支持中间容器哈希:https://github.com/moby/buildkit/issues/1053

感谢@David Callanan和@MegaCookie的投入。

每次docker成功执行Dockerfile中的RUN命令时,镜像文件系统中的一个新层就会被提交。你可以方便地使用这些图层id作为图像来启动一个新容器。

以以下Dockerfile为例:

FROM busybox
RUN echo 'foo' > /tmp/foo.txt
RUN echo 'bar' >> /tmp/foo.txt

并建立它:

$ docker build -t so-26220957 .
Sending build context to Docker daemon 47.62 kB
Step 1/3 : FROM busybox
 ---> 00f017a8c2a6
Step 2/3 : RUN echo 'foo' > /tmp/foo.txt
 ---> Running in 4dbd01ebf27f
 ---> 044e1532c690
Removing intermediate container 4dbd01ebf27f
Step 3/3 : RUN echo 'bar' >> /tmp/foo.txt
 ---> Running in 74d81cb9d2b1
 ---> 5bd8172529c1
Removing intermediate container 74d81cb9d2b1
Successfully built 5bd8172529c1

你现在可以从00f017a8c2a6, 044e1532c690和5bd8172529c1开始一个新容器:

$ docker run --rm 00f017a8c2a6 cat /tmp/foo.txt
cat: /tmp/foo.txt: No such file or directory

$ docker run --rm 044e1532c690 cat /tmp/foo.txt
foo

$ docker run --rm 5bd8172529c1 cat /tmp/foo.txt
foo
bar

当然,你可能想要启动一个shell来探索文件系统并尝试命令:

$ docker run --rm -it 044e1532c690 sh      
/ # ls -l /tmp
total 4
-rw-r--r--    1 root     root             4 Mar  9 19:09 foo.txt
/ # cat /tmp/foo.txt 
foo

当其中一个Dockerfile命令失败时,你需要做的是寻找前一层的id,并在由该id创建的容器中运行shell:

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

一旦进入容器:

尝试失败的命令,并重现问题 然后修复该命令并测试它 最后用fixed命令更新Dockerfile


如果你真的需要在实际失败的层中进行实验,而不是从最后一个工作层开始工作,请参阅Drew的回答。