docker run -i can hang and leak a container if started with stdin closed
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 6.1k
- Forks
- 2.2k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 43
Description
Follow up from https://github.com/moby/moby/issues/41015
How to reproduce
go run the following cocde
package main
import (
"fmt"
"os"
"time"
)
func main() {
name := "/usr/bin/docker"
args := []string{"run", "--rm", "-i", "busybox", "sleep", "1"}
//devNull, _ := os.Open(os.DevNull)
for {
fmt.Printf("Executing: \"%s\" %v\n", name, args)
proc, err := os.StartProcess(name, append([]string{name}, args...), &os.ProcAttr{
Files: []*os.File{nil, nil, nil},
})
if err != nil {
panic(err)
}
fmt.Println(time.Now(), "Wait on exit")
proc.Wait()
fmt.Println("Done")
}
}
Here we docker run in a loop with -i and no stdin, stdout, or stderr
It will work for a while, and eventually hang. When it is hanging, you can see the docker run process has created a container but the CLI is hanging on
https://github.com/docker/cli/blob/590f3271ef098f1e11dfbd84d8596b7bf1561c36/cli/command/container/run.go#L165
So the container is never started
$ ps -ef | grep "docker run"
bbuzbee 7384 7234 0 10:04 pts/0 00:00:00 /usr/bin/docker run --rm -i busybox sleep 1
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ddd9cc922c41 busybox "sleep 1" 4 minutes ago Created tender_hamilton
Analysis
If you remove -i from docker run, the issue goes away.
If you pass the devNull FD I have commented out to stdin, such as
Files: []*os.File{devNull, nil, nil},
then the issue goes away.
The CLI is hung waiting on headers to be returned to the call to the docker daemon's /wait endpoint, and I confirmed the daemon has flushed headers so I do not know what it is waiting on. Maybe it is because flush doesn't call fflush but I am not sure how that could be related to attach.
Thoughts
I don't know the design goals, but if -i without stdin is not supported I think it should exit with an error rather than hang. Also seems to be a race since it works sometimes.
Thanks
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the loop from the issue with docker run --rm -i busybox sleep 1 and stdin, stdout, and stderr closed. Start at cli/command/container/run.go around line 165 and trace the CLI's wait and attach behavior alongside the daemon's /wait endpoint. Done means the command no longer hangs or leaves a Created container, with the supported behavior for closed stdin established.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, go
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100