一个从零开始的 Docker 容器如何执行二进制文件?

3

Docker文档中提到你可以构建这个最小化的镜像:

FROM scratch
ADD hello /
CMD ["/hello"]

假设这个过程是这样的:CMD 步骤使用默认 shell (即 bin/sh,参见 https://dev59.com/mmEi5IYBdhLWcg3wK5rd#21564990) 运行 hello 可执行文件。

但如果 SCRATCH 真的完全为空,那么 bin/sh 来自哪里呢?为什么我的镜像包含一个 shell?

1个回答

9

scratch 构建的容器一开始是空的,因此您的镜像中不包含 /bin/sh

然而,在这里有两种格式的 CMD 比较重要:

CMD ["/hello"]
CMD /hello

第一种格式指定了一个完整的命令,并直接通过execve(2)调用。实际执行的进程就像是["/hello"] 一样(即 argc == 1)。

第二种格式指定了一个 "入口点参数",作为单个参数传递给入口点,因此Docker将尝试使用["/bin/sh", "-c", "/hello"]运行,并且argc == 3会失败。

您可以使用 CMD /hello替换CMD行并自行观察其效果。


这确实很有道理!那接下来一个基本的问题是,为什么我要将我的二进制文件作为容器分发,而不只是作为单独的二进制文件呢?是为了系统之间的互操作性,因为任何人都可以使用 Docker 拉取我的镜像并运行它,但是二进制文件只针对特定的操作系统/架构进行编译。 - sherz1
@sherz1 如果你的二进制文件是静态链接的,那么将其单独分发与将其放入容器中几乎没有什么区别。然而,如果架构不同,将其封装在容器中也无济于事。在没有特殊的翻译帮助下,你仍然无法在x86机器上运行ARM二进制文件。 - iBug
@sherz1 但是,如果它是动态链接的或需要额外的库,容器可以确保执行环境保持一致,这样你就不必担心错误的库版本或缺少的库等问题。 - iBug

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接