【问题标题】:Entrypoint's exec form executed through shell通过 shell 执行 Entrypoint 的 exec 表单
【发布时间】:2019-10-02 23:10:47
【问题描述】:

我正在构建一个基于 Windows 的 docker 映像:

FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019

# omitted for brevity

ENTRYPOINT ["c:\spinner.exe", "service", "w3svc", "-t", "c:\iislog\W3SVC\u_extend1.log"]

基础镜像将shell设置为Powershell

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

我的理解是当使用ENTRYPOINT指令的exec形式时,该命令将在没有shell的情况下执行。但是,当我创建容器时,它会失败并出现以下错误:

$ docker run -d -p 80:80 --isolation process --name pht site:local


$ docker logs pht

At line:1 char:77
+ ... ference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; [C:\\spin ...
+                                                                  ~
Missing ] at end of attribute or type literal.
At line:1 char:78
+ ... '; $ProgressPreference = 'SilentlyContinue'; [C:\\spinner.exe, servic ...
+                                                    ~~~~~~~~~~~~~~
Unexpected token ':\\spinner.exe' in expression or statement.
At line:1 char:92
+ ... ; $ProgressPreference = 'SilentlyContinue'; [C:\\spinner.exe, service ...
+                                                                 ~
Missing argument in parameter list.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordEx
   ception
    + FullyQualifiedErrorId : EndSquareBracketExpectedAtEndOfAttribute

当我检查停止的容器时,我看到执行的命令是通过 shell:

 "Entrypoint": [
                "powershell -Command $ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; [\"c:\\spinner.exe\", \"service\", \"w3svc\", \"-t\", \"c:\\iislog\\W3SVC\\u_extend1.log\"]"
            ],

我是不是误会了什么?

【问题讨论】:

    标签: powershell docker dockerfile docker-entrypoint


    【解决方案1】:

    exec 语法需要 JSON 格式,这意味着数组元素中的 \ 实例必须转义为 \\

    由于您的 ENTRYPOINT 指令因此不包含有效的 JSON 数组,看起来 Docker 正在回退到 shell 语法,因此传递了您的 ENTRYPOINT 参数到外壳,在您的情况下是 PowerShell,如您的 SHELL 指令中所定义 - 导致 外壳命令损坏[1]

    exec 格式的语法正确的ENTRYPOINT - 即有效的 JSON - 防止 shell 参与,在这种情况下这是正确的方法,假设您的命令仅包含 literal 元素。

    因此,请尝试以下操作(\ 实例转义为 \\):

    ENTRYPOINT ["c:\\spinner.exe", "service", "w3svc", "-t", "c:\\iislog\\W3SVC\\u_extend1.log"]
    

    这样,Docker 最终应该在容器中执行以下命令行:

    c:\spinner.exe service w3svc -t c:\iislog\W3SVC\u_extend1.log
    

    [1] 发生的情况是格式错误的ENTRYPOINT 参数["c:\spinner.exe", "service", "w3svc", "-t", "c:\iislog\W3SVC\u_extend1.log"] 被视为单个参数 - 逐字字符串根据 JSON 规则进行转义(\ 字符的两倍。) - 传递给 shell,如您的 SHELL 指令所定义。这意味着将该参数附加到 SHELL 数组的最后一个参数,前面有一个空格字符。你在日志中看到的就是证据。

    【讨论】:

    • 你是对的!我没有想到 Json 中的反斜杠是问题所在。我什至将 Dockerfile 的转义字符更改为反引号,认为它会传播到命令,但事实并非如此。
    • 很高兴听到它成功了,@AmirKeibi。我的 猜测 是可配置的转义字符仅适用于 unquoted 参数和行继续。
    猜你喜欢
    • 2017-05-21
    • 2010-10-07
    • 2022-12-09
    • 2020-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 2020-05-31
    相关资源
    最近更新 更多