Windows: Add cpu count option
Signed-off-by: Darren Stahl <darst@microsoft.com>
This commit is contained in:
parent
d7d0bc1d58
commit
4e15420b9b
12 changed files with 187 additions and 20 deletions
|
@ -27,10 +27,13 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultNetworkSpace = "172.16.0.0/12"
|
||||
platformSupported = true
|
||||
windowsMinCPUShares = 1
|
||||
windowsMaxCPUShares = 10000
|
||||
defaultNetworkSpace = "172.16.0.0/12"
|
||||
platformSupported = true
|
||||
windowsMinCPUShares = 1
|
||||
windowsMaxCPUShares = 10000
|
||||
windowsMinCPUPercent = 1
|
||||
windowsMaxCPUPercent = 100
|
||||
windowsMinCPUCount = 1
|
||||
)
|
||||
|
||||
func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) {
|
||||
|
@ -80,6 +83,15 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf
|
|||
return nil
|
||||
}
|
||||
|
||||
numCPU := int64(sysinfo.NumCPU())
|
||||
if hostConfig.CPUCount < 0 {
|
||||
logrus.Warnf("Changing requested CPUCount of %d to minimum allowed of %d", hostConfig.CPUCount, windowsMinCPUCount)
|
||||
hostConfig.CPUCount = windowsMinCPUCount
|
||||
} else if hostConfig.CPUCount > numCPU {
|
||||
logrus.Warnf("Changing requested CPUCount of %d to current number of processors, %d", hostConfig.CPUCount, numCPU)
|
||||
hostConfig.CPUCount = numCPU
|
||||
}
|
||||
|
||||
if hostConfig.CPUShares < 0 {
|
||||
logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, windowsMinCPUShares)
|
||||
hostConfig.CPUShares = windowsMinCPUShares
|
||||
|
@ -88,19 +100,42 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf
|
|||
hostConfig.CPUShares = windowsMaxCPUShares
|
||||
}
|
||||
|
||||
if hostConfig.CPUPercent < 0 {
|
||||
logrus.Warnf("Changing requested CPUPercent of %d to minimum allowed of %d", hostConfig.CPUPercent, windowsMinCPUPercent)
|
||||
hostConfig.CPUPercent = windowsMinCPUPercent
|
||||
} else if hostConfig.CPUPercent > windowsMaxCPUPercent {
|
||||
logrus.Warnf("Changing requested CPUPercent of %d to maximum allowed of %d", hostConfig.CPUPercent, windowsMaxCPUPercent)
|
||||
hostConfig.CPUPercent = windowsMaxCPUPercent
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo) ([]string, error) {
|
||||
func verifyContainerResources(resources *containertypes.Resources, isHyperv bool) ([]string, error) {
|
||||
warnings := []string{}
|
||||
|
||||
// cpu subsystem checks and adjustments
|
||||
if resources.CPUPercent < 0 || resources.CPUPercent > 100 {
|
||||
return warnings, fmt.Errorf("Range of CPU percent is from 1 to 100")
|
||||
}
|
||||
|
||||
if resources.CPUPercent > 0 && resources.CPUShares > 0 {
|
||||
return warnings, fmt.Errorf("Conflicting options: CPU Shares and CPU Percent cannot both be set")
|
||||
if !isHyperv {
|
||||
// The processor resource controls are mutually exclusive on
|
||||
// Windows Server Containers, the order of precedence is
|
||||
// CPUCount first, then CPUShares, and CPUPercent last.
|
||||
if resources.CPUCount > 0 {
|
||||
if resources.CPUShares > 0 {
|
||||
warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
|
||||
logrus.Warn("Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
|
||||
resources.CPUShares = 0
|
||||
}
|
||||
if resources.CPUPercent > 0 {
|
||||
warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
||||
logrus.Warn("Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
||||
resources.CPUPercent = 0
|
||||
}
|
||||
} else if resources.CPUShares > 0 {
|
||||
if resources.CPUPercent > 0 {
|
||||
warnings = append(warnings, "Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
||||
logrus.Warn("Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
||||
resources.CPUPercent = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if resources.NanoCPUs > 0 && resources.CPUPercent > 0 {
|
||||
|
@ -154,7 +189,7 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi
|
|||
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
|
||||
warnings := []string{}
|
||||
|
||||
w, err := verifyContainerResources(&hostConfig.Resources, nil)
|
||||
w, err := verifyContainerResources(&hostConfig.Resources, daemon.runAsHyperVContainer(hostConfig))
|
||||
warnings = append(warnings, w...)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
|
@ -388,14 +423,14 @@ func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error
|
|||
}
|
||||
|
||||
// runasHyperVContainer returns true if we are going to run as a Hyper-V container
|
||||
func (daemon *Daemon) runAsHyperVContainer(container *container.Container) bool {
|
||||
if container.HostConfig.Isolation.IsDefault() {
|
||||
func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig) bool {
|
||||
if hostConfig.Isolation.IsDefault() {
|
||||
// Container is set to use the default, so take the default from the daemon configuration
|
||||
return daemon.defaultIsolation.IsHyperV()
|
||||
}
|
||||
|
||||
// Container is requesting an isolation mode. Honour it.
|
||||
return container.HostConfig.Isolation.IsHyperV()
|
||||
return hostConfig.Isolation.IsHyperV()
|
||||
|
||||
}
|
||||
|
||||
|
@ -403,7 +438,7 @@ func (daemon *Daemon) runAsHyperVContainer(container *container.Container) bool
|
|||
// container start to call mount.
|
||||
func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
|
||||
// We do not mount if a Hyper-V container
|
||||
if !daemon.runAsHyperVContainer(container) {
|
||||
if !daemon.runAsHyperVContainer(container.HostConfig) {
|
||||
return daemon.Mount(container)
|
||||
}
|
||||
return nil
|
||||
|
@ -413,7 +448,7 @@ func (daemon *Daemon) conditionalMountOnStart(container *container.Container) er
|
|||
// during the cleanup of a container to unmount.
|
||||
func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
|
||||
// We do not unmount if a Hyper-V container
|
||||
if !daemon.runAsHyperVContainer(container) {
|
||||
if !daemon.runAsHyperVContainer(container.HostConfig) {
|
||||
return daemon.Unmount(container)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -86,11 +86,13 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
|||
if c.HostConfig.NanoCPUs > 0 {
|
||||
cpuPercent = uint8(c.HostConfig.NanoCPUs * 100 / int64(sysinfo.NumCPU()) / 1e9)
|
||||
}
|
||||
cpuCount := uint64(c.HostConfig.CPUCount)
|
||||
memoryLimit := uint64(c.HostConfig.Memory)
|
||||
s.Windows.Resources = &specs.WindowsResources{
|
||||
CPU: &specs.WindowsCPUResources{
|
||||
Percent: &cpuPercent,
|
||||
Shares: &cpuShares,
|
||||
Count: &cpuCount,
|
||||
},
|
||||
Memory: &specs.WindowsMemoryResources{
|
||||
Limit: &memoryLimit,
|
||||
|
|
|
@ -166,6 +166,7 @@ This section lists each version from latest to oldest. Each listing includes a
|
|||
* `GET /nodes` and `GET /node/(id or name)` now return `Addr` as part of a node's `Status`, which is the address that that node connects to the manager from.
|
||||
* The `HostConfig` field now includes `NanoCPUs` that represents CPU quota in units of 10<sup>-9</sup> CPUs.
|
||||
* `GET /info` now returns more structured information about security options.
|
||||
* The `HostConfig` field now includes `CpuCount` that represents the number of CPUs available for execution by the container. Windows daemon only.
|
||||
|
||||
### v1.24 API changes
|
||||
|
||||
|
|
|
@ -303,6 +303,7 @@ Create a container
|
|||
"MemoryReservation": 0,
|
||||
"KernelMemory": 0,
|
||||
"NanoCPUs": 500000,
|
||||
"CpuCount": 4,
|
||||
"CpuPercent": 80,
|
||||
"CpuShares": 512,
|
||||
"CpuPeriod": 100000,
|
||||
|
@ -427,7 +428,14 @@ Create a container
|
|||
- **MemoryReservation** - Memory soft limit in bytes.
|
||||
- **KernelMemory** - Kernel memory limit in bytes.
|
||||
- **NanoCPUs** - CPU quota in units of 10<sup>-9</sup> CPUs.
|
||||
- **CpuPercent** - An integer value containing the usable percentage of the available CPUs. (Windows daemon only)
|
||||
- **CpuCount** - An integer value containing the number of usable CPUs.
|
||||
Windows daemon only. On Windows Server containers,
|
||||
the processor resource controls are mutually exclusive, the order of precedence
|
||||
is CPUCount first, then CPUShares, and CPUPercent last.
|
||||
- **CpuPercent** - An integer value containing the usable percentage of
|
||||
the available CPUs. Windows daemon only. On Windows Server containers,
|
||||
the processor resource controls are mutually exclusive, the order of precedence
|
||||
is CPUCount first, then CPUShares, and CPUPercent last.
|
||||
- **CpuShares** - An integer value containing the container's CPU Shares
|
||||
(ie. the relative weight vs other containers).
|
||||
- **CpuPeriod** - The length of a CPU period in microseconds.
|
||||
|
@ -623,6 +631,7 @@ Return low-level information on the container `id`
|
|||
"ContainerIDFile": "",
|
||||
"CpusetCpus": "",
|
||||
"CpusetMems": "",
|
||||
"CpuCount": 4,
|
||||
"CpuPercent": 80,
|
||||
"CpuShares": 0,
|
||||
"CpuPeriod": 100000,
|
||||
|
|
|
@ -31,6 +31,9 @@ Options:
|
|||
--cap-drop value Drop Linux capabilities (default [])
|
||||
--cgroup-parent string Optional parent cgroup for the container
|
||||
--cidfile string Write the container ID to the file
|
||||
--cpu-count int The number of CPUs available for execution by the container.
|
||||
Windows daemon only. On Windows Server containers, this is
|
||||
approximated as a percentage of total CPU usage.
|
||||
--cpu-percent int CPU percent (Windows only)
|
||||
--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period
|
||||
--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota
|
||||
|
|
|
@ -29,7 +29,14 @@ Options:
|
|||
--cap-drop value Drop Linux capabilities (default [])
|
||||
--cgroup-parent string Optional parent cgroup for the container
|
||||
--cidfile string Write the container ID to the file
|
||||
--cpu-percent int CPU percent (Windows only)
|
||||
--cpu-count int The number of CPUs available for execution by the container.
|
||||
Windows daemon only. On Windows Server containers, this is
|
||||
approximated as a percentage of total CPU usage.
|
||||
--cpu-percent int Limit percentage of CPU available for execution
|
||||
by the container. Windows daemon only.
|
||||
The processor resource controls are mutually
|
||||
exclusive, the order of precedence is CPUCount
|
||||
first, then CPUShares, and CPUPercent last.
|
||||
--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period
|
||||
--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota
|
||||
-c, --cpu-shares int CPU shares (relative weight)
|
||||
|
|
|
@ -4766,3 +4766,67 @@ func (s *DockerSuite) TestRunMount(c *check.C) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunWindowsWithCPUCount(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--cpu-count=1", "--name", "test", "busybox", "echo", "testing")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "testing")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUCount")
|
||||
c.Assert(out, check.Equals, "1")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunWindowsWithCPUShares(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--cpu-shares=1000", "--name", "test", "busybox", "echo", "testing")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "testing")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUShares")
|
||||
c.Assert(out, check.Equals, "1000")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunWindowsWithCPUPercent(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--cpu-percent=80", "--name", "test", "busybox", "echo", "testing")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "testing")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUPercent")
|
||||
c.Assert(out, check.Equals, "80")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunProcessIsolationWithCPUCountCPUSharesAndCPUPercent(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows, IsolationIsProcess)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--cpu-count=1", "--cpu-shares=1000", "--cpu-percent=80", "--name", "test", "busybox", "echo", "testing")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "WARNING: Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "WARNING: Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "testing")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUCount")
|
||||
c.Assert(out, check.Equals, "1")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUShares")
|
||||
c.Assert(out, check.Equals, "0")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUPercent")
|
||||
c.Assert(out, check.Equals, "0")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunHypervIsolationWithCPUCountCPUSharesAndCPUPercent(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows, IsolationIsHyperv)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--cpu-count=1", "--cpu-shares=1000", "--cpu-percent=80", "--name", "test", "busybox", "echo", "testing")
|
||||
c.Assert(strings.TrimSpace(out), checker.Contains, "testing")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUCount")
|
||||
c.Assert(out, check.Equals, "1")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUShares")
|
||||
c.Assert(out, check.Equals, "1000")
|
||||
|
||||
out = inspectField(c, "test", "HostConfig.CPUPercent")
|
||||
c.Assert(out, check.Equals, "80")
|
||||
}
|
||||
|
|
|
@ -218,6 +218,18 @@ var (
|
|||
},
|
||||
"Test requires containers are not pausable.",
|
||||
}
|
||||
IsolationIsHyperv = testRequirement{
|
||||
func() bool {
|
||||
return daemonPlatform == "windows" && isolation == "hyperv"
|
||||
},
|
||||
"Test requires a Windows daemon running default isolation mode of hyperv.",
|
||||
}
|
||||
IsolationIsProcess = testRequirement{
|
||||
func() bool {
|
||||
return daemonPlatform == "windows" && isolation == "process"
|
||||
},
|
||||
"Test requires a Windows daemon running default isolation mode of process.",
|
||||
}
|
||||
)
|
||||
|
||||
// testRequires checks if the environment satisfies the requirements
|
||||
|
|
|
@ -110,6 +110,9 @@ func (clnt *client) Create(containerID string, checkpoint string, checkpointDir
|
|||
|
||||
if spec.Windows.Resources != nil {
|
||||
if spec.Windows.Resources.CPU != nil {
|
||||
if spec.Windows.Resources.CPU.Count != nil {
|
||||
configuration.ProcessorCount = uint32(*spec.Windows.Resources.CPU.Count)
|
||||
}
|
||||
if spec.Windows.Resources.CPU.Shares != nil {
|
||||
configuration.ProcessorWeight = uint64(*spec.Windows.Resources.CPU.Shares)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ docker-create - Create a new container
|
|||
[**--cap-drop**[=*[]*]]
|
||||
[**--cgroup-parent**[=*CGROUP-PATH*]]
|
||||
[**--cidfile**[=*CIDFILE*]]
|
||||
[**--cpu-count**[=*0*]]
|
||||
[**--cpu-percent**[=*0*]]
|
||||
[**--cpu-period**[=*0*]]
|
||||
[**--cpu-quota**[=*0*]]
|
||||
[**--cpu-rt-period**[=*0*]]
|
||||
|
@ -124,6 +126,18 @@ The initial status of the container created with **docker create** is 'created'.
|
|||
**--cidfile**=""
|
||||
Write the container ID to the file
|
||||
|
||||
**--cpu-count**=*0*
|
||||
Limit the number of CPUs available for execution by the container.
|
||||
|
||||
On Windows Server containers, this is approximated as a percentage of total CPU usage.
|
||||
|
||||
On Windows Server containers, the processor resource controls are mutually exclusive, the order of precedence is CPUCount first, then CPUShares, and CPUPercent last.
|
||||
|
||||
**--cpu-percent**=*0*
|
||||
Limit the percentage of CPU available for execution by a container running on a Windows daemon.
|
||||
|
||||
On Windows Server containers, the processor resource controls are mutually exclusive, the order of precedence is CPUCount first, then CPUShares, and CPUPercent last.
|
||||
|
||||
**--cpu-period**=*0*
|
||||
Limit the CPU CFS (Completely Fair Scheduler) period
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ docker-run - Run a command in a new container
|
|||
[**--cap-drop**[=*[]*]]
|
||||
[**--cgroup-parent**[=*CGROUP-PATH*]]
|
||||
[**--cidfile**[=*CIDFILE*]]
|
||||
[**--cpu-count**[=*0*]]
|
||||
[**--cpu-percent**[=*0*]]
|
||||
[**--cpu-period**[=*0*]]
|
||||
[**--cpu-quota**[=*0*]]
|
||||
[**--cpu-rt-period**[=*0*]]
|
||||
|
@ -174,6 +176,18 @@ division of CPU shares:
|
|||
**--cidfile**=""
|
||||
Write the container ID to the file
|
||||
|
||||
**--cpu-count**=*0*
|
||||
Limit the number of CPUs available for execution by the container.
|
||||
|
||||
On Windows Server containers, this is approximated as a percentage of total CPU usage.
|
||||
|
||||
On Windows Server containers, the processor resource controls are mutually exclusive, the order of precedence is CPUCount first, then CPUShares, and CPUPercent last.
|
||||
|
||||
**--cpu-percent**=*0*
|
||||
Limit the percentage of CPU available for execution by a container running on a Windows daemon.
|
||||
|
||||
On Windows Server containers, the processor resource controls are mutually exclusive, the order of precedence is CPUCount first, then CPUShares, and CPUPercent last.
|
||||
|
||||
**--cpu-period**=*0*
|
||||
Limit the CPU CFS (Completely Fair Scheduler) period
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ type ContainerOptions struct {
|
|||
kernelMemory string
|
||||
user string
|
||||
workingDir string
|
||||
cpuCount int64
|
||||
cpuShares int64
|
||||
cpuPercent int64
|
||||
cpuPeriod int64
|
||||
|
@ -227,6 +228,7 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions {
|
|||
flags.StringVar(&copts.containerIDFile, "cidfile", "", "Write the container ID to the file")
|
||||
flags.StringVar(&copts.cpusetCpus, "cpuset-cpus", "", "CPUs in which to allow execution (0-3, 0,1)")
|
||||
flags.StringVar(&copts.cpusetMems, "cpuset-mems", "", "MEMs in which to allow execution (0-3, 0,1)")
|
||||
flags.Int64Var(&copts.cpuCount, "cpu-count", 0, "CPU count (Windows only)")
|
||||
flags.Int64Var(&copts.cpuPercent, "cpu-percent", 0, "CPU percent (Windows only)")
|
||||
flags.Int64Var(&copts.cpuPeriod, "cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period")
|
||||
flags.Int64Var(&copts.cpuQuota, "cpu-quota", 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
|
||||
|
@ -529,6 +531,7 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c
|
|||
KernelMemory: kernelMemory,
|
||||
OomKillDisable: &copts.oomKillDisable,
|
||||
NanoCPUs: copts.cpus.Value(),
|
||||
CPUCount: copts.cpuCount,
|
||||
CPUPercent: copts.cpuPercent,
|
||||
CPUShares: copts.cpuShares,
|
||||
CPUPeriod: copts.cpuPeriod,
|
||||
|
|
Loading…
Reference in a new issue