diff --git a/daemon/config_unix.go b/daemon/config_unix.go index 06439ef50b..15a422cb94 100644 --- a/daemon/config_unix.go +++ b/daemon/config_unix.go @@ -28,6 +28,7 @@ type Config struct { EnableSelinuxSupport bool RemappedRoot string SocketGroup string + CgroupParent string Ulimits map[string]*units.Ulimit } @@ -77,6 +78,7 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin cmd.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic")) cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header")) cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API")) + cmd.StringVar(&config.CgroupParent, []string{"-cgroup-parent"}, "/docker", usageFn("Set parent cgroup for all containers")) config.attachExperimentalFlags(cmd, usageFn) } diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go index f896912f9e..b5cd2f4aef 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_unix.go @@ -258,7 +258,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro AutoCreatedDevices: autoCreatedDevices, CapAdd: c.HostConfig.CapAdd.Slice(), CapDrop: c.HostConfig.CapDrop.Slice(), - CgroupParent: c.HostConfig.CgroupParent, + CgroupParent: daemon.configStore.CgroupParent, GIDMapping: gidMap, GroupAdd: c.HostConfig.GroupAdd, Ipc: ipc, @@ -270,6 +270,9 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro UIDMapping: uidMap, UTS: uts, } + if c.HostConfig.CgroupParent != "" { + c.Command.CgroupParent = c.HostConfig.CgroupParent + } return nil } diff --git a/docs/reference/commandline/daemon.md b/docs/reference/commandline/daemon.md index fbcf5583c3..04d6578371 100644 --- a/docs/reference/commandline/daemon.md +++ b/docs/reference/commandline/daemon.md @@ -20,6 +20,7 @@ weight = -1 --authz-plugin=[] Set authorization plugins to load -b, --bridge="" Attach containers to a network bridge --bip="" Specify network bridge IP + --cgroup-parent=/docker Set parent cgroup for all containers -D, --debug Enable debug mode --default-gateway="" Container default gateway IPv4 address --default-gateway-v6="" Container default gateway IPv6 address @@ -643,4 +644,20 @@ set like this: /usr/local/bin/docker daemon -D -g /var/lib/docker -H unix:// > /var/lib/docker-machine/docker.log 2>&1 +# Default cgroup parent +The `--cgroup-parent` option allows you to set the default cgroup parent +to use for containers. If this option is not set, it defaults to `/docker`. + +If the cgroup has a leading forward slash (`/`), the cgroup is created +under the root cgroup, otherwise the cgroup is created under the daemon +cgroup. + +Assuming the daemon is running in cgroup `daemoncgroup`, +`--cgroup-parent=/foobar` creates a cgroup in +`/sys/fs/cgroup/memory/foobar`, wheras using `--cgroup-parent=foobar` +creates the cgroup in `/sys/fs/cgroup/memory/daemoncgroup/foobar` + +This setting can also be set per container, using the `--cgroup-parent` +option on `docker create` and `docker run`, and takes precedence over +the `--cgroup-parent` option on the daemon. diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index 10bcf89a1d..cb14a190e0 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -10,6 +10,7 @@ import ( "net" "os" "os/exec" + "path" "path/filepath" "regexp" "strconv" @@ -1931,3 +1932,31 @@ func (s *DockerDaemonSuite) TestDaemonRestartContainerLinksRestart(c *check.C) { } } } + +func (s *DockerDaemonSuite) TestDaemonCgroupParent(c *check.C) { + testRequires(c, DaemonIsLinux) + + cgroupParent := "test" + name := "cgroup-test" + + err := s.d.StartWithBusybox("--cgroup-parent", cgroupParent) + c.Assert(err, check.IsNil) + defer s.d.Restart() + + out, err := s.d.Cmd("run", "--name", name, "busybox", "cat", "/proc/self/cgroup") + c.Assert(err, checker.IsNil) + cgroupPaths := parseCgroupPaths(string(out)) + c.Assert(len(cgroupPaths), checker.Not(checker.Equals), 0, check.Commentf("unexpected output - %q", string(out))) + out, err = s.d.Cmd("inspect", "-f", "{{.Id}}", name) + c.Assert(err, checker.IsNil) + id := strings.TrimSpace(string(out)) + expectedCgroup := path.Join(cgroupParent, id) + found := false + for _, path := range cgroupPaths { + if strings.HasSuffix(path, expectedCgroup) { + found = true + break + } + } + c.Assert(found, checker.True, check.Commentf("Cgroup path for container (%s) doesn't found in cgroups file: %s", expectedCgroup, cgroupPaths)) +} diff --git a/man/docker-daemon.8.md b/man/docker-daemon.8.md index 466b80537c..269268a1d1 100644 --- a/man/docker-daemon.8.md +++ b/man/docker-daemon.8.md @@ -10,6 +10,7 @@ docker-daemon - Enable daemon mode [**--authz-plugin**[=*[]*]] [**-b**|**--bridge**[=*BRIDGE*]] [**--bip**[=*BIP*]] +[**--cgroup-parent**[=*/docker*]] [**--cluster-store**[=*[]*]] [**--cluster-advertise**[=*[]*]] [**--cluster-store-opt**[=*map[]*]] @@ -80,6 +81,9 @@ format. **--bip**="" Use the provided CIDR notation address for the dynamically created bridge (docker0); Mutually exclusive of \-b +**--cgroup-parent**="" + Set parent cgroup for all containers. Default is "/docker". + **--cluster-store**="" URL of the distributed storage backend