diff --git a/daemon/container.go b/daemon/container.go index a065d00b57..07e1bf0ea2 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -303,10 +303,10 @@ func populateCommand(c *Container, env []string) error { } resources := &execdriver.Resources{ - Memory: c.Config.Memory, - MemorySwap: c.Config.MemorySwap, - CpuShares: c.Config.CpuShares, - Cpuset: c.Config.Cpuset, + Memory: c.hostConfig.Memory, + MemorySwap: c.hostConfig.MemorySwap, + CpuShares: c.hostConfig.CpuShares, + CpusetCpus: c.hostConfig.CpusetCpus, Rlimits: rlimits, } diff --git a/daemon/create.go b/daemon/create.go index 5729cc1e57..ee7df30e0e 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -18,33 +18,28 @@ func (daemon *Daemon) ContainerCreate(job *engine.Job) engine.Status { } else if len(job.Args) > 1 { return job.Errorf("Usage: %s", job.Name) } + config := runconfig.ContainerConfigFromJob(job) - if config.Memory != 0 && config.Memory < 4194304 { + hostConfig := runconfig.ContainerHostConfigFromJob(job) + + if hostConfig.Memory != 0 && hostConfig.Memory < 4194304 { return job.Errorf("Minimum memory limit allowed is 4MB") } - if config.Memory > 0 && !daemon.SystemConfig().MemoryLimit { + if hostConfig.Memory > 0 && !daemon.SystemConfig().MemoryLimit { job.Errorf("Your kernel does not support memory limit capabilities. Limitation discarded.\n") - config.Memory = 0 + hostConfig.Memory = 0 } - if config.Memory > 0 && !daemon.SystemConfig().SwapLimit { + if hostConfig.Memory > 0 && !daemon.SystemConfig().SwapLimit { job.Errorf("Your kernel does not support swap limit capabilities. Limitation discarded.\n") - config.MemorySwap = -1 + hostConfig.MemorySwap = -1 } - if config.Memory > 0 && config.MemorySwap > 0 && config.MemorySwap < config.Memory { + if hostConfig.Memory > 0 && hostConfig.MemorySwap > 0 && hostConfig.MemorySwap < hostConfig.Memory { return job.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.\n") } - if config.Memory == 0 && config.MemorySwap > 0 { + if hostConfig.Memory == 0 && hostConfig.MemorySwap > 0 { return job.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.\n") } - var hostConfig *runconfig.HostConfig - if job.EnvExists("HostConfig") { - hostConfig = runconfig.ContainerHostConfigFromJob(job) - } else { - // Older versions of the API don't provide a HostConfig. - hostConfig = nil - } - container, buildWarnings, err := daemon.Create(config, hostConfig, name) if err != nil { if daemon.Graph().IsNotExist(err) { diff --git a/daemon/execdriver/driver.go b/daemon/execdriver/driver.go index bc66c0e542..932b734d27 100644 --- a/daemon/execdriver/driver.go +++ b/daemon/execdriver/driver.go @@ -109,7 +109,7 @@ type Resources struct { Memory int64 `json:"memory"` MemorySwap int64 `json:"memory_swap"` CpuShares int64 `json:"cpu_shares"` - Cpuset string `json:"cpuset"` + CpusetCpus string `json:"cpuset_cpus"` Rlimits []*ulimit.Rlimit `json:"rlimits"` } @@ -198,7 +198,7 @@ func SetupCgroups(container *configs.Config, c *Command) error { container.Cgroups.Memory = c.Resources.Memory container.Cgroups.MemoryReservation = c.Resources.Memory container.Cgroups.MemorySwap = c.Resources.MemorySwap - container.Cgroups.CpusetCpus = c.Resources.Cpuset + container.Cgroups.CpusetCpus = c.Resources.CpusetCpus } return nil diff --git a/daemon/execdriver/lxc/lxc_template.go b/daemon/execdriver/lxc/lxc_template.go index 79ef51fb72..e4a8ed6b5f 100644 --- a/daemon/execdriver/lxc/lxc_template.go +++ b/daemon/execdriver/lxc/lxc_template.go @@ -107,8 +107,8 @@ lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}} {{if .Resources.CpuShares}} lxc.cgroup.cpu.shares = {{.Resources.CpuShares}} {{end}} -{{if .Resources.Cpuset}} -lxc.cgroup.cpuset.cpus = {{.Resources.Cpuset}} +{{if .Resources.CpusetCpus}} +lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}} {{end}} {{end}} diff --git a/docs/man/docker-create.1.md b/docs/man/docker-create.1.md index d5166ca93a..9faeabe302 100644 --- a/docs/man/docker-create.1.md +++ b/docs/man/docker-create.1.md @@ -12,7 +12,7 @@ docker-create - Create a new container [**--cap-add**[=*[]*]] [**--cap-drop**[=*[]*]] [**--cidfile**[=*CIDFILE*]] -[**--cpuset**[=*CPUSET*]] +[**--cpuset-cpus**[=*CPUSET-CPUS*]] [**--device**[=*[]*]] [**--dns-search**[=*[]*]] [**--dns**[=*[]*]] @@ -64,7 +64,7 @@ IMAGE [COMMAND] [ARG...] **--cidfile**="" Write the container ID to the file -**--cpuset**="" +**--cpuset-cpus**="" CPUs in which to allow execution (0-3, 0,1) **--device**=[] diff --git a/docs/man/docker-run.1.md b/docs/man/docker-run.1.md index ae0503ec8c..74450fd143 100644 --- a/docs/man/docker-run.1.md +++ b/docs/man/docker-run.1.md @@ -12,7 +12,7 @@ docker-run - Run a command in a new container [**--cap-add**[=*[]*]] [**--cap-drop**[=*[]*]] [**--cidfile**[=*CIDFILE*]] -[**--cpuset**[=*CPUSET*]] +[**--cpuset-cpus**[=*CPUSET-CPUS*]] [**-d**|**--detach**[=*false*]] [**--device**[=*[]*]] [**--dns-search**[=*[]*]] @@ -124,7 +124,7 @@ division of CPU shares: **--cidfile**="" Write the container ID to the file -**--cpuset**="" +**--cpuset-cpus**="" CPUs in which to allow execution (0-3, 0,1) **-d**, **--detach**=*true*|*false* diff --git a/docs/sources/reference/api/docker_remote_api_v1.18.md b/docs/sources/reference/api/docker_remote_api_v1.18.md index 46351ed85c..3543c7e7a0 100644 --- a/docs/sources/reference/api/docker_remote_api_v1.18.md +++ b/docs/sources/reference/api/docker_remote_api_v1.18.md @@ -113,10 +113,6 @@ Create a container "Hostname": "", "Domainname": "", "User": "", - "Memory": 0, - "MemorySwap": 0, - "CpuShares": 512, - "Cpuset": "0,1", "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, @@ -143,6 +139,10 @@ Create a container "Binds": ["/tmp:/tmp"], "Links": ["redis3:redis"], "LxcConf": {"lxc.utsname":"docker"}, + "Memory": 0, + "MemorySwap": 0, + "CpuShares": 512, + "CpusetCpus": "0,1", "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] }, "PublishAllPorts": false, "Privileged": false, @@ -182,7 +182,8 @@ Json Parameters: always use this with `memory`, and make the value larger than `memory`. - **CpuShares** - An integer value containing the CPU Shares for container (ie. the relative weight vs othercontainers). - **CpuSet** - String value containg the cgroups Cpuset to use. +- **Cpuset** - The same as CpusetCpus, but deprecated, please don't use. +- **CpusetCpus** - String value containg the cgroups CpusetCpus to use. - **AttachStdin** - Boolean value, attaches to stdin. - **AttachStdout** - Boolean value, attaches to stdout. - **AttachStderr** - Boolean value, attaches to stderr. @@ -195,7 +196,7 @@ Json Parameters: of strings - **Image** - String value containing the image name to use for the container - **Volumes** – An object mapping mountpoint paths (strings) inside the - container to empty objects. + container to empty objects. - **WorkingDir** - A string value containing the working dir for commands to run in. - **NetworkDisabled** - Boolean value, when true disables neworking for the @@ -292,8 +293,6 @@ Return low-level information on the container `id` "-c", "exit 9" ], - "CpuShares": 0, - "Cpuset": "", "Domainname": "", "Entrypoint": null, "Env": [ @@ -303,8 +302,6 @@ Return low-level information on the container `id` "Hostname": "ba033ac44011", "Image": "ubuntu", "MacAddress": "", - "Memory": 0, - "MemorySwap": 0, "NetworkDisabled": false, "OnBuild": null, "OpenStdin": false, @@ -324,6 +321,8 @@ Return low-level information on the container `id` "CapAdd": null, "CapDrop": null, "ContainerIDFile": "", + "CpusetCpus": "", + "CpuShares": 0, "Devices": [], "Dns": null, "DnsSearch": null, @@ -331,6 +330,8 @@ Return low-level information on the container `id` "IpcMode": "", "Links": null, "LxcConf": [], + "Memory": 0, + "MemorySwap": 0, "NetworkMode": "bridge", "PortBindings": {}, "Privileged": false, @@ -1173,8 +1174,6 @@ Return low-level information on the image `name` { "Hostname": "", "User": "", - "Memory": 0, - "MemorySwap": 0, "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, @@ -1540,10 +1539,6 @@ Create a new image from a container's changes "Hostname": "", "Domainname": "", "User": "", - "Memory": 0, - "MemorySwap": 0, - "CpuShares": 512, - "Cpuset": "0,1", "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, @@ -1897,10 +1892,6 @@ Return low-level information about the exec command `id`. "Hostname" : "8f177a186b97", "Domainname" : "", "User" : "", - "Memory" : 0, - "MemorySwap" : 0, - "CpuShares" : 0, - "Cpuset" : "", "AttachStdin" : false, "AttachStdout" : false, "AttachStderr" : false, diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 685bbbcbff..1ca43cb9aa 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -780,7 +780,7 @@ Creates a new container. --cap-add=[] Add Linux capabilities --cap-drop=[] Drop Linux capabilities --cidfile="" Write the container ID to the file - --cpuset="" CPUs in which to allow execution (0-3, 0,1) + --cpuset-cpus="" CPUs in which to allow execution (0-3, 0,1) --device=[] Add a host device to the container --dns=[] Set custom DNS servers --dns-search=[] Set custom DNS search domains @@ -1646,7 +1646,7 @@ removed before the image is removed. --cap-add=[] Add Linux capabilities --cap-drop=[] Drop Linux capabilities --cidfile="" Write the container ID to the file - --cpuset="" CPUs in which to allow execution (0-3, 0,1) + --cpuset-cpus="" CPUs in which to allow execution (0-3, 0,1) -d, --detach=false Run container in background and print container ID --device=[] Add a host device to the container --dns=[] Set custom DNS servers diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 888a18c809..ff3b0461e3 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -1282,6 +1282,17 @@ func TestRunWithCpuset(t *testing.T) { logDone("run - cpuset 0") } +func TestRunWithCpusetCpus(t *testing.T) { + defer deleteAllContainers() + + cmd := exec.Command(dockerBinary, "run", "--cpuset-cpus", "0", "busybox", "true") + if code, err := runCommand(cmd); err != nil || code != 0 { + t.Fatalf("container should run successfuly with cpuset-cpus of 0: %s", err) + } + + logDone("run - cpuset-cpus 0") +} + func TestRunDeviceNumbers(t *testing.T) { defer deleteAllContainers() diff --git a/runconfig/config.go b/runconfig/config.go index ca5c3240b6..ccc9ee60e2 100644 --- a/runconfig/config.go +++ b/runconfig/config.go @@ -12,10 +12,10 @@ type Config struct { Hostname string Domainname string User string - Memory int64 // Memory limit (in bytes) - MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap - CpuShares int64 // CPU shares (relative weight vs. other containers) - Cpuset string // Cpuset 0-2, 0,1 + Memory int64 // FIXME: we keep it for backward compatibility, it has been moved to hostConfig. + MemorySwap int64 // FIXME: it has been moved to hostConfig. + CpuShares int64 // FIXME: it has been moved to hostConfig. + Cpuset string // FIXME: it has been moved to hostConfig and renamed to CpusetCpus. AttachStdin bool AttachStdout bool AttachStderr bool diff --git a/runconfig/hostconfig.go b/runconfig/hostconfig.go index 85db438b7d..872cccfa1e 100644 --- a/runconfig/hostconfig.go +++ b/runconfig/hostconfig.go @@ -103,6 +103,10 @@ type HostConfig struct { Binds []string ContainerIDFile string LxcConf []utils.KeyValuePair + Memory int64 // Memory limit (in bytes) + MemorySwap int64 // Total memory usage (memory + swap); set `-1` to disable swap + CpuShares int64 // CPU shares (relative weight vs. other containers) + CpusetCpus string // CpusetCpus 0-2, 0,1 Privileged bool PortBindings nat.PortMap Links []string @@ -141,11 +145,31 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig { if job.EnvExists("HostConfig") { hostConfig := HostConfig{} job.GetenvJson("HostConfig", &hostConfig) + + // FIXME: These are for backward compatibility, if people use these + // options with `HostConfig`, we should still make them workable. + if job.EnvExists("Memory") && hostConfig.Memory == 0 { + hostConfig.Memory = job.GetenvInt64("Memory") + } + if job.EnvExists("MemorySwap") && hostConfig.MemorySwap == 0 { + hostConfig.MemorySwap = job.GetenvInt64("MemorySwap") + } + if job.EnvExists("CpuShares") && hostConfig.CpuShares == 0 { + hostConfig.CpuShares = job.GetenvInt64("CpuShares") + } + if job.EnvExists("Cpuset") && hostConfig.CpusetCpus == "" { + hostConfig.CpusetCpus = job.Getenv("Cpuset") + } + return &hostConfig } hostConfig := &HostConfig{ ContainerIDFile: job.Getenv("ContainerIDFile"), + Memory: job.GetenvInt64("Memory"), + MemorySwap: job.GetenvInt64("MemorySwap"), + CpuShares: job.GetenvInt64("CpuShares"), + CpusetCpus: job.Getenv("CpusetCpus"), Privileged: job.GetenvBool("Privileged"), PublishAllPorts: job.GetenvBool("PublishAllPorts"), NetworkMode: NetworkMode(job.Getenv("NetworkMode")), @@ -154,6 +178,13 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig { ReadonlyRootfs: job.GetenvBool("ReadonlyRootfs"), } + // FIXME: This is for backward compatibility, if people use `Cpuset` + // in json, make it workable, we will only pass hostConfig.CpusetCpus + // to execDriver. + if job.EnvExists("Cpuset") && hostConfig.CpusetCpus == "" { + hostConfig.CpusetCpus = job.Getenv("Cpuset") + } + job.GetenvJson("LxcConf", &hostConfig.LxcConf) job.GetenvJson("PortBindings", &hostConfig.PortBindings) job.GetenvJson("Devices", &hostConfig.Devices) diff --git a/runconfig/parse.go b/runconfig/parse.go index bf87c42f94..bb3f013035 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -62,7 +62,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID (format: [:])") flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container") flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)") - flCpuset = cmd.String([]string{"-cpuset"}, "", "CPUs in which to allow execution (0-3, 0,1)") + flCpusetCpus = cmd.String([]string{"#-cpuset", "-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)") flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container") flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)") flIpcMode = cmd.String([]string{"-ipc"}, "", "IPC namespace to use") @@ -283,10 +283,10 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe Tty: *flTty, NetworkDisabled: !*flNetwork, OpenStdin: *flStdin, - Memory: flMemory, - MemorySwap: MemorySwap, - CpuShares: *flCpuShares, - Cpuset: *flCpuset, + Memory: flMemory, // FIXME: for backward compatibility + MemorySwap: MemorySwap, // FIXME: for backward compatibility + CpuShares: *flCpuShares, // FIXME: for backward compatibility + Cpuset: *flCpusetCpus, // FIXME: for backward compatibility AttachStdin: attachStdin, AttachStdout: attachStdout, AttachStderr: attachStderr, @@ -303,6 +303,10 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe Binds: binds, ContainerIDFile: *flContainerIDFile, LxcConf: lxcConf, + Memory: flMemory, + MemorySwap: MemorySwap, + CpuShares: *flCpuShares, + CpusetCpus: *flCpusetCpus, Privileged: *flPrivileged, PortBindings: portBindings, Links: flLinks.GetAll(),