moby: CMD works incorrectly on Windows when ENTRYPOINT is specified

Description

If ENTRYPOINT is in shell format and CMD is in JSON format, ENTRYPOINT should be ignored.

Steps to reproduce the issue:

#1
FROM microsoft/nanoserver
CMD ["echo", "hi"]
#2
FROM microsoft/nanoserver
ENTRYPOINT echo START
CMD ["echo", "hi"]

Describe the results you received:

#1
C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error response from daemon: container 434d705c4988241f36530291989c3c18de0786df44d9e302e8f9e4207d63b612 encountered an error during CreateProcess: failure in a Windows system call: The system cannot find the file specified. (0x2) extra info: {"ApplicationName":"","CommandLine":"echo hi","User":"","WorkingDirectory":"C:\\","Environment":{},"EmulateConsole":false,"CreateStdInPipe":true,"CreateStdOutPipe":true,"CreateStdErrPipe":true,"ConsoleSize":[0,0]}.
#2
START echo hi

Describe the results you expected: #1 returns error. It’s correct.

#2 prints message. It’s wrong. It should return error, because CMD is in JSON format.

Additional information you deem important (e.g. issue happens only occasionally):

https://docs.docker.com/engine/reference/builder/#cmd

The CMD instruction has three forms: CMD [“executable”,“param1”,“param2”] (exec form, this is the preferred form) CMD [“param1”,“param2”] (as default parameters to ENTRYPOINT) CMD command param1 param2 (shell form)

Note: If CMD is used to provide default arguments for the ENTRYPOINT instruction, both the CMD and ENTRYPOINT instructions should be specified with the JSON array format.

Output of docker version:

Docker version 17.05.0-ce, build 89658be

Output of docker info:

Containers: 67
 Running: 0
 Paused: 0
 Stopped: 67
Images: 161
Server Version: 17.05.0-ce
Storage Driver: windowsfilter
 Windows:
Logging Driver: json-file
Plugins:
 Volume: local
 Network: l2bridge l2tunnel nat null overlay transparent
Swarm: inactive
Default Isolation: hyperv
Kernel Version: 10.0 15063 (15063.0.amd64fre.rs2_release.170317-1834)
Operating System: Windows 10 Pro
OSType: windows
Architecture: x86_64
CPUs: 4
Total Memory: 15.91GiB
Name: ANTON-PC
ID: XOFH:ZGJZ:Q7OO:LM7Z:NQER:HW7H:B7XQ:HUWB:G5CU:HSQM:IPG5:P4A7
Docker Root Dir: D:\Docker2
Debug Mode (client): false
Debug Mode (server): true
 File Descriptors: -1
 Goroutines: 22
 System Time: 2017-05-24T19:12:26.0469256+07:00
 EventsListeners: 0
Registry: https://index.docker.io/v1/
Experimental: true
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Comments: 22 (12 by maintainers)

Most upvoted comments

Aha, the answer to this is hilarious. After scanning the moby codebase, along with containerd and runc, there’s nothing explicit in any of that code to strip the “CMD” part.

It’s actually shell behaviour. So

ENTRYPOINT echo hello
CMD ["world"]

will generate a container config similar to below with both Cmd and Entrypoint populated:

image

When a container is run from that image, the OCI spec is process bit is populated as follows:

image

Note both the entrypoint and the cmd are both in there.

However, if you look at ps, you’ll notice “world” isn’t present.

image

It turns out, this is entirely shell behaviour on Linux (that the “CMD” part is dropped if the ENTRYPOINT is in shell form).

image

Which is completely different to how command line parsing works on Windows:

image

So to fix this, I may be able to do a Windows-targeted fix in moby and drop the CMD part from OCI if the entrypoint is shell form. I’m already heavily all-over that code for containerd integration on Windows, but might give it a go to fix building on what I already have. However, it might be a bit contentious as I will need to store the fact that ENTRYPOINT is shell form in the config so as to know to drop the CMD part when building the OCI spec prior to passing it to the runtime. IOW, make the OCI spec so that it doesn’t have the “world” part in it. However, kind of low priority to do right now.

Why not just add “powershell”, “-command” to the entrypoint?

No. Double backslash. This is straight JSON