From 837eec064d2d40a4d86acbc6f47fada8263e0d4c Mon Sep 17 00:00:00 2001 From: Qiang Huang Date: Wed, 11 Mar 2015 09:31:18 +0800 Subject: [PATCH] move resources from Config to HostConfig Cgroup resources are host dependent, they should be in hostConfig. For backward compatibility, we just copy it to hostConfig, and leave it in Config for now, so there is no regressions, but the right way to use this throught json is to put it in HostConfig, like: { "Hostname": "", ... "HostConfig": { "CpuShares": 512, "Memory": 314572800, ... } } As we will add CpusetMems, CpusetCpus is definitely a better name, but some users are already using Cpuset in their http APIs, we also make it compatible. The main idea is keep using Cpuset in Config Struct, and make it has the same value as CpusetCpus, but not always, some scenarios: - Users use --cpuset in docker command, it can setup cpuset.cpus and can get Cpuset field from docker inspect or other http API which will get config info. - Users use --cpuset-cpus in docker command, ditto. - Users use Cpuset field in their http APIs, ditto. - Users use CpusetCpus field in their http APIs, they won't get Cpuset field in Config info, because by then, they should already know what happens to Cpuset. Signed-off-by: Qiang Huang --- daemon/container.go | 8 ++--- daemon/create.go | 25 ++++++--------- daemon/execdriver/driver.go | 4 +-- daemon/execdriver/lxc/lxc_template.go | 4 +-- docs/man/docker-create.1.md | 4 +-- docs/man/docker-run.1.md | 4 +-- .../reference/api/docker_remote_api_v1.18.md | 31 +++++++------------ docs/sources/reference/commandline/cli.md | 4 +-- integration-cli/docker_cli_run_test.go | 11 +++++++ runconfig/config.go | 8 ++--- runconfig/hostconfig.go | 31 +++++++++++++++++++ runconfig/parse.go | 14 ++++++--- 12 files changed, 90 insertions(+), 58 deletions(-) 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 587b9a2cd5..85c56a8230 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 76e0e400d6..07014a3887 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, @@ -1539,10 +1538,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, @@ -1896,10 +1891,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 efcf5bff81..d80d803d5c 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -781,7 +781,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 @@ -1638,7 +1638,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 52e8b12164..33c9fba570 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -1283,6 +1283,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(),