我将首先介绍 Heroku 文档中有关其容器注册表和 Docker 部署运行时的相关部分。
Docker 命令和运行时部分指出:
ENTRYPOINT
是可选的。如果不设置,/bin/sh -c
将使用
CMD
将始终由 shell 执行,以便您的进程可以使用配置变量;要执行单个二进制文件或使用没有 shell 的图像,请使用ENTRYPOINT
我想强调最后一句话(强调):
要执行单个二进制文件或使用没有 shell 的图像,请使用
ENTRYPOINT
此外,在不支持的Dockerfile 命令部分。
SHELL
- Docker 镜像的默认 shell 是,您可以根据需要/bin/sh
覆盖。ENTRYPOINT
我对此的理解是,如果ENTRYPOINT
指令存在于我的 Dockerfile 中,那么 Heroku 的容器堆栈将不会执行带有/bin/sh
. 但显然我的理解是错误的,因为这似乎仍在发生。
下面是我的 Dockerfile 的示意图:
FROM golang:1.14 as build
# ... builds the binary
FROM scratch
# ... other irrelevant stuff
COPY --from=build /myprogram /myprogram
ENTRYPOINT ["/myprogram"]
最终图像包含基础图像中的二进制/myprogram
文件scratch
。由于scratch
没有/bin/sh
,因此有必要覆盖它。根据他们的文档,这是通过ENTRYPOINT
.
但是,当我将它部署到 Heroku 时,它似乎仍然使用 shell 执行。为了显示:
% heroku ps -a my-app-name
== web (Free): /bin/sh -c --myflag1 --myflag2 (1)
这意味着它最终正在执行:
/myprogram /bin/sh -c --myflag1 --myflag2
这显然不是我想要的。但是这部分文档(我之前强调过)发生了什么?:
要执行单个二进制文件或使用没有 shell 的图像,请使用
ENTRYPOINT
...
heroku.yml 文件如下所示:
---
build:
docker:
web: Dockerfile
run:
web:
command:
- --myflag1
- --myflag2
我仍然对 shell 表单和 exec 表单有同样的问题。意思是,我也尝试使用看起来像这样的 heroku.yml 文件:
---
build:
docker:
web: Dockerfile
run:
web: --myflag1 --myflag2
现在,我知道我可以通过将最终图像基于具有/bin/sh
并删除ENTRYPOINT
指令的图像来“正常工作”,并使用/myprogram
. 我不需要使用从头开始,但我想并且应该能够使用scratch
,对吧?这是我多年来一直使用的在容器中运行静态链接二进制文件的方法,在其他平台上部署时我从未遇到过这样的问题。
那么我是否误解了他们的文档?我需要做什么才能摆脱这种/bin/sh
恶作剧?