Search code examples
powershelldockerdockerfiledocker-entrypoint

Entrypoint's exec form executed through shell


I'm building a Windows based docker image:

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"]

The base image sets the shell to Powershell:

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

My understanding was that when the exec form of the ENTRYPOINT instruction is used, the command will be executed without a shell. However, when I create the container, it fails with this error:

$ 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

And when I inspect the stopped container, I see the executed command was through shell:

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

Am I misunderstanding something here?


Solution

  • The exec syntax requires JSON format, which means that \ instances in the array elements must be escaped as \\.

    Since your ENTRYPOINT instruction therefore does not contain a valid JSON array, it looks like Docker is falling back to shell syntax and therefore passes your ENTRYPOINT argument to the shell, which in your case is PowerShell, as defined in your SHELL instruction - and that results in a broken shell command.[1]

    A syntactically correct ENTRYPOINT in exec format - i.e., valid JSON - prevents involvement of a shell, which is the correct approach in this case, given that your command contains literal elements only.

    Therefore, try the following (\ instances escaped as \\):

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

    That way, Docker should end up executing the following command line in the container:

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

    [1] What happens is that the malformed ENTRYPOINT argument, ["c:\spinner.exe", "service", "w3svc", "-t", "c:\iislog\W3SVC\u_extend1.log"], is taken to be a single argument - a verbatim string to be escaped based on JSON rules (doubling of \ chars.) - to be passed to the shell, as defined by your SHELL instruction. This means appending that argument to the last argument of your SHELL array, preceded by a space character. What you saw in the logs is evidence of that.