diff --git a/api/client/build.go b/api/client/build.go index 27b06afb71..3139e451b8 100644 --- a/api/client/build.go +++ b/api/client/build.go @@ -58,6 +58,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { flCpuQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota") flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)") flCPUSetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)") + flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container") cmd.Require(flag.Exact, 1) cmd.ParseFlags(args, true) @@ -276,6 +277,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { v.Set("cpuquota", strconv.FormatInt(*flCpuQuota, 10)) v.Set("memory", strconv.FormatInt(memory, 10)) v.Set("memswap", strconv.FormatInt(memorySwap, 10)) + v.Set("cgroupparent", *flCgroupParent) v.Set("dockerfile", *dockerfileName) diff --git a/api/server/server.go b/api/server/server.go index fbc844ad2e..ab236f876f 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -1301,6 +1301,7 @@ func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *ht buildConfig.CpuQuota = int64ValueOrZero(r, "cpuquota") buildConfig.CpuSetCpus = r.FormValue("cpusetcpus") buildConfig.CpuSetMems = r.FormValue("cpusetmems") + buildConfig.CgroupParent = r.FormValue("cgroupparent") // Job cancellation. Note: not all job types support this. if closeNotifier, ok := w.(http.CloseNotifier); ok { diff --git a/builder/evaluator.go b/builder/evaluator.go index 7dfb001bd8..cd8bff1cec 100644 --- a/builder/evaluator.go +++ b/builder/evaluator.go @@ -122,12 +122,13 @@ type Builder struct { noBaseImage bool // indicates that this build does not start from any base image, but is being built from an empty file system. // Set resource restrictions for build containers - cpuSetCpus string - cpuSetMems string - cpuShares int64 - cpuQuota int64 - memory int64 - memorySwap int64 + cpuSetCpus string + cpuSetMems string + cpuShares int64 + cpuQuota int64 + cgroupParent string + memory int64 + memorySwap int64 cancelled <-chan struct{} // When closed, job was cancelled. } diff --git a/builder/internals.go b/builder/internals.go index adeadd87c8..452180f902 100644 --- a/builder/internals.go +++ b/builder/internals.go @@ -552,12 +552,13 @@ func (b *Builder) create() (*daemon.Container, error) { b.Config.Image = b.image hostConfig := &runconfig.HostConfig{ - CpuShares: b.cpuShares, - CpuQuota: b.cpuQuota, - CpusetCpus: b.cpuSetCpus, - CpusetMems: b.cpuSetMems, - Memory: b.memory, - MemorySwap: b.memorySwap, + CpuShares: b.cpuShares, + CpuQuota: b.cpuQuota, + CpusetCpus: b.cpuSetCpus, + CpusetMems: b.cpuSetMems, + CgroupParent: b.cgroupParent, + Memory: b.memory, + MemorySwap: b.memorySwap, } config := *b.Config diff --git a/builder/job.go b/builder/job.go index 0ad488aae8..a64375c96b 100644 --- a/builder/job.go +++ b/builder/job.go @@ -52,6 +52,7 @@ type Config struct { CpuQuota int64 CpuSetCpus string CpuSetMems string + CgroupParent string AuthConfig *cliconfig.AuthConfig ConfigFile *cliconfig.ConfigFile @@ -166,6 +167,7 @@ func Build(d *daemon.Daemon, buildConfig *Config) error { cpuQuota: buildConfig.CpuQuota, cpuSetCpus: buildConfig.CpuSetCpus, cpuSetMems: buildConfig.CpuSetMems, + cgroupParent: buildConfig.CgroupParent, memory: buildConfig.Memory, memorySwap: buildConfig.MemorySwap, cancelled: buildConfig.WaitCancelled(), diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 76d934fc31..5a92739529 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -642,8 +642,9 @@ is returned by the `docker attach` command to its caller too: -m, --memory="" Memory limit for all build containers --memory-swap="" Total memory (memory + swap), `-1` to disable swap -c, --cpu-shares CPU Shares (relative weight) - --cpuset-cpus="" CPUs in which to allow execution, e.g. `0-3`, `0,1` --cpuset-mems="" MEMs in which to allow execution, e.g. `0-3`, `0,1` + --cpuset-cpus="" CPUs in which to allow exection, e.g. `0-3`, `0,1` + --cgroup-parent="" Optional parent cgroup for the container Builds Docker images from a Dockerfile and a "context". A build's context is the files located in the specified `PATH` or `URL`. The build process can @@ -862,6 +863,11 @@ you refer to it on the command line. > children) for security reasons, and to ensure repeatable builds on remote > Docker hosts. This is also the reason why `ADD ../file` will not work. +When `docker build` is run with the `--cgroup-parent` option the containers used +in the build will be run with the [corresponding `docker run` +flag](/reference/run/#specifying-custom-cgroups). + + ## commit Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index 60a180584f..6d9c314dd7 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -465,6 +465,13 @@ Note: You would have to write policy defining a `svirt_apache_t` type. +## Specifying custom cgroups + +Using the `--cgroup-parent` flag, you can pass a specific cgroup to run a +container in. This allows you to create and manage cgroups on their own. You can +define custom resources for those cgroups and put containers under a common +parent group. + ## Runtime constraints on resources The operator can also adjust the performance parameters of the diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 9ae69e7be1..20a317246e 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -5322,3 +5322,30 @@ func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) { } } + +func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) { + testRequires(c, NativeExecDriver) + testRequires(c, SameHostDaemon) + defer deleteImages() + + cgroupParent := "test" + data, err := ioutil.ReadFile("/proc/self/cgroup") + if err != nil { + c.Fatalf("failed to read '/proc/self/cgroup - %v", err) + } + selfCgroupPaths := parseCgroupPaths(string(data)) + _, found := selfCgroupPaths["memory"] + if !found { + c.Fatalf("unable to find self cpu cgroup path. CgroupsPath: %v", selfCgroupPaths) + } + cmd := exec.Command(dockerBinary, "build", "--cgroup-parent", cgroupParent, "-") + cmd.Stdin = strings.NewReader(` +FROM busybox +RUN cat /proc/self/cgroup +`) + + out, _, err := runCommandWithOutput(cmd) + if err != nil { + c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err) + } +}