Skip to content

Don't create source directory while the daemon is being shutdown, fix #30348 - #33330

Merged
AkihiroSuda merged 1 commit into
moby:masterfrom
coolljt0725:fix_sock_is_dir
Jun 7, 2017
Merged

AkihiroSuda merged 1 commit into
moby:masterfrom
coolljt0725:fix_sock_is_dir

Conversation

@coolljt0725

Copy link
Copy Markdown
Contributor

If a container mount the socket the daemon is listening on into
container while the daemon is being shutdown, the socket will
not exist on the host, then daemon will assume it's a directory
and create it on the host, this will cause the daemon can't start
next time.

fix issue #30348

To reproduce this issue, you can add following code

--- a/daemon/oci_linux.go
+++ b/daemon/oci_linux.go
@@ -8,6 +8,7 @@ import (
        "sort"
        "strconv"
        "strings"
+       "time"

        "github.com/Sirupsen/logrus"
        "github.com/docker/docker/container"
@@ -666,7 +667,8 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e
        if err := daemon.setupIpcDirs(c); err != nil {
                return nil, err
        }
-
+       fmt.Printf("===please stop the daemon===\n")
+       time.Sleep(time.Second * 2)
        ms, err := daemon.setupMounts(c)
        if err != nil {
                return nil, err

step1 run a container which has --restart always and -v /var/run/docker.sock:/sock

$ docker run -ti --restart always -v /var/run/docker.sock:/sock busybox
/ #

step2 exit the the container

/ # exit

and kill the daemon when you see

===please stop the daemon===

in the daemon log

The daemon can't restart again and fail with can't create unix socket /var/run/docker.sock: is a directory.

Signed-off-by: Lei Jitang leijitang@huawei.com

ping @cpuguy83 @thaJeztah

- What I did

- How I did it

- How to verify it

- Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

@thaJeztah

Copy link
Copy Markdown
Member

@coolljt0725 looks like build is failing;

11:26:03 # github.com/docker/docker/daemon
11:26:03 daemon/volumes_windows.go:27: not enough arguments in call to mount.Setup
11:26:03 	have (string, number, number)
11:26:03 	want (string, int, int, func() error)

@coolljt0725

Copy link
Copy Markdown
Contributor Author

@thaJeztah updated

@thaJeztah

Copy link
Copy Markdown
Member

ping @cpuguy83 @mlaventure PTAL

@mlaventure mlaventure left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few nits and a requested change to checkFun prototype.

Otherwise, LGTM. Thanks for finding this!

Comment thread daemon/volumes_unix.go Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

If the daemon is being shutdown, we should not let a container start if it is trying to mount the socket the daemon is listening on. During daemon shutdown, the socket (/var/run/docker.sock by default) doesn't exist anymore causing the call to m.Setup to create at directory instead. This in turn will prevent the daemon to restart.

Comment thread daemon/volumes_unix.go Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd prefer the callback to be of the form func(m *Mountpoint) error

Comment thread volume/volume.go Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

The, optional, checkFun parameter allows doing additional checking before creating the source directory on the host.

Comment thread volume/volume.go Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Before creating the source directory on the host, invoke checkFun if it's not nil. One of the use case is to forbid creating the daemon socket as a directory if the daemon is in the process of shutting down.

@coolljt0725

Copy link
Copy Markdown
Contributor Author

@mlaventure update

…oby#30348

If a container mount the socket the daemon is listening on into
container while the daemon is being shutdown, the socket will
not exist on the host, then daemon will assume it's a directory
and create it on the host, this will cause the daemon can't start
next time.

fix issue moby#30348

To reproduce this issue, you can add following code

```
--- a/daemon/oci_linux.go
+++ b/daemon/oci_linux.go
@@ -8,6 +8,7 @@ import (
        "sort"
        "strconv"
        "strings"
+       "time"

        "github.com/Sirupsen/logrus"
        "github.com/docker/docker/container"
@@ -666,7 +667,8 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e
        if err := daemon.setupIpcDirs(c); err != nil {
                return nil, err
        }
-
+       fmt.Printf("===please stop the daemon===\n")
+       time.Sleep(time.Second * 2)
        ms, err := daemon.setupMounts(c)
        if err != nil {
                return nil, err

```

step1 run a container which has `--restart always` and `-v /var/run/docker.sock:/sock`
```
$ docker run -ti --restart always -v /var/run/docker.sock:/sock busybox
/ #

```
step2 exit the the container
```
/ # exit
```
and kill the daemon when you see
```
===please stop the daemon===
```
in the daemon log

The daemon can't restart again and fail with `can't create unix socket /var/run/docker.sock: is a directory`.

Signed-off-by: Lei Jitang <leijitang@huawei.com>

@mlaventure mlaventure left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Thanks!

Comment thread daemon/daemon.go
// StoreHosts stores the addresses the daemon is listening on
func (daemon *Daemon) StoreHosts(hosts []string) {
if daemon.hosts == nil {
daemon.hosts = make(map[string]bool)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we initialize daemon.hosts in NewDaemon()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have considered that, but it will have some duplicate code to dealing with the hosts config (https://github.com/moby/moby/blob/master/cmd/dockerd/daemon.go#L157).

@AkihiroSuda AkihiroSuda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants