我试图为我们的开发过程构建一个新的Docker映像,使用cpanm安装一堆Perl模块作为各种项目的基本映像。
在开发Dockerfile时,cpanm返回一个失败代码,因为一些模块没有干净地安装。
我很确定我需要准备安装更多的东西。
我在哪里可以找到/。在输出中引用Cpanm /work目录,以便检查日志?在一般情况下,我如何检查一个失败的docker构建命令的文件系统?
在运行一个发现后,我发现
/var/lib/docker/aufs/diff/3afa404e[...]/.cpanm
这是可靠的吗,还是我最好构建一个“裸”容器并手动运行一些东西,直到我拥有所有我需要的东西?
每次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的回答。
在我的情况下,我必须:
DOCKER_BUILDKIT=1 docker build ...
正如Jannis Schönleber在他的回答中提到的,目前在这种情况下没有可用的调试(即没有创建中间映像/容器)。
我发现我可以使用以下选项:
... --progress=plain ...
然后添加各种RUN…或现有RUN上的附加行…调试特定的命令。在我看来,这给了你完全的访问权限(至少如果你的构建相对较快)。
例如,你可以这样检查一个变量:
RUN echo "Variable NAME = [$NAME]"
如果你想知道文件是否正确安装,你可以这样做:
RUN find /
etc.
在我的情况下,我必须调试一个带有私有存储库的Go应用程序的docker构建,并且很难进行调试。我这里还有其他细节。
目前最新的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文件中的哪一步失败了,在我的情况下运行bundle安装,
把它改成
RUN bundle install || cat <path to the file containing the error>
这有双重效果,打印出失败的原因,并且这个中间步骤不会被docker构建认为是失败的。所以它不会被删除,并且可以通过以下方式进行检查:
docker run --rm -it <id_last_working_layer> bash -il
在那里,您甚至可以重新运行失败的命令并进行实时测试。
如果您正在使用docker-compose来构建docker映像,请尝试在命令之前添加DOCKER_BUILDKIT=0,以查看最后一个成功的层id
DOCKER_BUILDKIT=0 docker-compose ...
这将暂时禁用命令的DOCKER_BUILDKIT。
有了最后一个层id,您可以使用从顶部答案的命令连接到它
docker run --rm -it LAST_LAYER_ID sh
仍然使用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
...