为什么必须使用 shell 来在 Docker 中运行命名二进制文件?

为什么必须使用 shell 来在 Docker 中运行命名二进制文件?

在 docker 中使用 alpine 并尝试启动命名但它只退出(零输出)

这有效 CMD /usr/sbin/named -f -c /etc/bind/named.conf

然后在 docker 镜像中表示为

            "Cmd": [
                "/bin/sh",
                "-c",
                "/usr/sbin/named -f -c /etc/bind/named.conf"

然而这并不起作用。

CMD ["/usr/sbin/named", "-f", "-c /etc/bind/named.conf"]

这是完整的 Dockerfile,我也用它来进行 CI 测试

FROM alpine
RUN apk --no-cache add bind bind-tools bash
CMD /usr/sbin/named -f -c /etc/bind/named.conf

答案1

您混淆了命令的参数。

使用CMD ["/usr/sbin/named", "-f", "-c /etc/bind/named.conf"],程序会将其视为:

argc = 3
argv[1] = "-f"
argv[2] = "-c /etc/bind/named.conf"

但是使用 shell 时,由于 shell 会为您进行参数拆分,因此实际命令是:

argc = 4
argv[1] = "-f"
argv[2] = "-c"
argv[3] = "/etc/bind/named.conf"

因此你可能应该像这样编写 Dockerfile:

CMD ["/usr/sbin/named", "-f", "-c", "/etc/bind/named.conf"]

答案2

CMD 命令有三种变体:

  1. 执行形式:["executable", "param1", "param2"]
  2. ENTRYPOINT 的参数:["param1", "param2"]
  3. 壳体形式:executable param1 param2

第二个只有ENTRYPOINT在图中指定时才有效。第一个和第三个的区别在于 exec 形式不运行 shell,而 shell 形式运行。

换句话说CMD /usr/sbin/named -f -c /etc/bind/named.conf,Alpine 实际上运行/bin/sh -c "/usr/sbin/named -f -c /etc/bind/named.conf",因此相当于CMD ["/bin/sh", "-c", "/usr/sbin/named -f -c /etc/bind/named.conf"],这就是两者都能正常工作的原因。

至于CMD ["/usr/sbin/named", "-f", "-c /etc/bind/named.conf"]它传递两个参数给named-f-c /etc/bind/named.conf,而您显然想要传递三个参数:-f-c/etc/bind/named.conf

你应该尝试一下CMD ["/usr/sbin/named", "-f", "-c", "/etc/bind/named.conf"]。它可能会起作用,因为我认为它named不需要 shell。

也可以看看CMD 的 Dockerfile 参考

相关内容