我如何检查一个失败的`docker build`文件系统?

我正在尝试为我们的开发过程构build一个新的Docker镜像,使用cpanm来安装一堆Perl模块作为各种项目的基础镜像。

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

我很确定我需要安装一些更多的东西。

我的问题是,我在哪里可以find输出中引用的/.cpanm/work目录,以检查日志? 在一般情况下,我如何检查一个失败的docker build命令的文件系统?

上午编辑咬了子弹,并运行我发现的发现

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

这是可靠的,还是我最好build立一个“裸”的容器和手动运行的东西,直到我有我需要的所有东西?

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

以下面的Dockerfile:

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

并build立它:

 $ docker build -t so-2622957 . 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 

您现在可以从044e1532c6905bd8172529c1开始一个新的容器:

 $ 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创build的容器中运行一个shell:

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

一旦进入容器:

  • 尝试失败的命令,并重现该问题
  • 然后修复命令并testing它
  • 最后用固定的命令更新你的Dockerfile

如果您确实需要在实际失败的图层中进行实验,而不是从最后一个工作层开始工作,请参阅下面的Drew的答案 。

如果您想在失败的命令之前立即检查状态,则回答最好。

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

这里的解决scheme是find失败的容器:

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

现在,您正在查看构build失败时的状态,而不是在运行导致失败的命令之前。

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

知道:

  • 检查RUN失败之前的最新状态,在Dockerfile(以及所有后续RUN命令)中注释掉,然后运行docker builddocker run
  • 在失败的RUN命令之后检查状态,只需添加|| true || true它迫使它成功; 然后像上面那样继续(保留所有随后的RUN命令注释掉,运行docker builddocker run

Tada,不需要混淆Docker内部或层ID,作为奖励,Docker会自动最小化需要重新完成的工作量。

我要做的是将下面的Dockerfile注释掉,包括有问题的一行。 然后你可以运行容器并手动运行docker命令,并以通常的方式查看日志。 例如,如果Dockerfile是

 RUN foo RUN bar RUN baz 

它会死在酒吧,我会做的

 RUN foo # RUN bar # RUN baz 

然后

 $ docker build -t foo . $ docker run -it foo bash container# bar ...grep logs...