Add IO Resource Controls for Windows

Signed-off-by: Darren Stahl <darst@microsoft.com>
This commit is contained in:
Darren Stahl 2016-02-24 17:51:46 -08:00
parent e974eadd94
commit 8df2066341
10 changed files with 112 additions and 9 deletions

View File

@ -450,6 +450,9 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi
if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) {
return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000")
}
if resources.IOMaximumBandwidth != 0 || resources.IOMaximumIOps != 0 {
return warnings, fmt.Errorf("Invalid QoS settings: %s does not support Maximum IO Bandwidth or Maximum IO IOps", runtime.GOOS)
}
if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
warnings = append(warnings, "Your kernel does not support Block I/O weight_device.")
logrus.Warnf("Your kernel does not support Block I/O weight_device. Weight-device discarded.")

View File

@ -13,18 +13,18 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/daemon/graphdriver/windows" // register the windows graph driver
"github.com/docker/docker/dockerversion"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/reference"
"github.com/docker/docker/runconfig"
// register the windows graph driver
"github.com/docker/docker/daemon/graphdriver/windows"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/reference"
"github.com/docker/docker/runconfig"
"github.com/docker/engine-api/types"
pblkiodev "github.com/docker/engine-api/types/blkiodev"
containertypes "github.com/docker/engine-api/types/container"
"github.com/docker/libnetwork"
nwconfig "github.com/docker/libnetwork/config"
@ -107,13 +107,44 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi
return warnings, fmt.Errorf("Conflicting options: CPU Shares and CPU Percent cannot both be set")
}
// TODO Windows: Add more validation of resource settings not supported on Windows
if resources.BlkioWeight > 0 {
warnings = append(warnings, "Windows does not support Block I/O weight. Weight discarded.")
logrus.Warnf("Windows does not support Block I/O weight. --blkio-weight discarded.")
resources.BlkioWeight = 0
}
if len(resources.BlkioWeightDevice) > 0 {
warnings = append(warnings, "Windows does not support Block I/O weight_device.")
logrus.Warnf("Windows does not support Block I/O weight_device. --blkio-weight-device discarded.")
resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
}
if len(resources.BlkioDeviceReadBps) > 0 {
warnings = append(warnings, "Windows does not support Block read limit in bytes per second.")
logrus.Warnf("Windows does not support Block I/O read limit in bytes per second. --device-read-bps discarded.")
resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
}
if len(resources.BlkioDeviceWriteBps) > 0 {
warnings = append(warnings, "Windows does not support Block write limit in bytes per second.")
logrus.Warnf("Windows does not support Block I/O write limit in bytes per second. --device-write-bps discarded.")
resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
}
if len(resources.BlkioDeviceReadIOps) > 0 {
warnings = append(warnings, "Windows does not support Block read limit in IO per second.")
logrus.Warnf("Windows does not support Block I/O read limit in IO per second. -device-read-iops discarded.")
resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
}
if len(resources.BlkioDeviceWriteIOps) > 0 {
warnings = append(warnings, "Windows does not support Block write limit in IO per second.")
logrus.Warnf("Windows does not support Block I/O write limit in IO per second. --device-write-iops discarded.")
resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
}
return warnings, nil
}
// verifyPlatformContainerSettings performs platform-specific validation of the
// hostconfig and config structures.
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
warnings := []string{}
w, err := verifyContainerResources(&hostConfig.Resources, nil)

View File

@ -181,9 +181,9 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e
//TODO Bandwidth: ...,
},
Storage: &windowsoci.Storage{
//TODO Bps: ...,
//TODO Iops: ...,
//TODO SandboxSize: ...,
Bps: &c.HostConfig.IOMaximumBandwidth,
Iops: &c.HostConfig.IOMaximumIOps,
//TODO SandboxSize: ...,
},
}
return (*libcontainerd.Spec)(&s), nil

View File

@ -115,6 +115,7 @@ This section lists each version from latest to oldest. Each listing includes a
* `POST /containers/create` now takes `StorageOpt` field.
* `GET /info` now returns `SecurityOptions` field, showing if `apparmor`, `seccomp`, or `selinux` is supported.
* `GET /networks` now supports filtering by `label`.
* `POST /containers/create` now takes `MaximumIOps` and `MaximumIOBps` fields. Windows daemon only.
### v1.23 API changes

View File

@ -288,6 +288,8 @@ Create a container
"CpuQuota": 50000,
"CpusetCpus": "0,1",
"CpusetMems": "0,1",
"MaximumIOps": 0,
"MaximumIOBps": 0,
"BlkioWeight": 300,
"BlkioWeightDevice": [{}],
"BlkioDeviceReadBps": [{}],
@ -392,6 +394,8 @@ Json Parameters:
- **CpuQuota** - Microseconds of CPU time that the container can get in a CPU period.
- **CpusetCpus** - String value containing the `cgroups CpusetCpus` to use.
- **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
- **MaximumIOps** - Maximum IO absolute rate in terms of IOps. MaximumIOps and MaximumIOBps are mutually exclusive settings.
- **MaximumIOBps** - Maximum IO absolute rate in terms of bytes per second. MaximumIOps and MaximumIOBps are mutually exclusive settings.
- **BlkioWeight** - Block IO weight (relative weight) accepts a weight value between 10 and 1000.
- **BlkioWeightDevice** - Block IO weight (relative device weight) in the form of: `"BlkioWeightDevice": [{"Path": "device_path", "Weight": weight}]`
- **BlkioDeviceReadBps** - Limit read rate (bytes per second) from a device in the form of: `"BlkioDeviceReadBps": [{"Path": "device_path", "Rate": rate}]`, for example:
@ -533,6 +537,8 @@ Return low-level information on the container `id`
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"MaximumIOps": 0,
"MaximumIOBps": 0,
"BlkioWeight": 0,
"BlkioWeightDevice": [{}],
"BlkioDeviceReadBps": [{}],

View File

@ -59,6 +59,15 @@ parent = "smn_cli"
--log-opt=[] Log driver specific options
-m, --memory="" Memory limit
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33)
--io-maxbandwidth="" Maximum IO bandwidth limit for the system drive
(Windows only). The format is `<number><unit>`.
Unit is optional and can be `b` (bytes per second),
`k` (kilobytes per second), `m` (megabytes per second),
or `g` (gigabytes per second). If you omit the unit,
the system uses bytes per second.
--io-maxbandwidth and --io-maxiops are mutually exclusive options.
--io-maxiops=0 Maximum IO per second limit for the system drive (Windows only).
--io-maxbandwidth and --io-maxiops are mutually exclusive options.
--memory-reservation="" Memory soft limit
--memory-swap="" A positive integer equal to memory plus swap. Specify -1 to enable unlimited swap.
--memory-swappiness="" Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.

View File

@ -62,6 +62,11 @@ func DecodeContainerConfig(src io.Reader) (*container.Config, *container.HostCon
if err := ValidateIsolation(hc); err != nil {
return nil, nil, nil, err
}
// Validate QoS
if err := ValidateQoS(hc); err != nil {
return nil, nil, nil, err
}
return w.Config, hc, w.NetworkingConfig, nil
}

View File

@ -87,3 +87,21 @@ func ValidateIsolation(hc *container.HostConfig) error {
}
return nil
}
// ValidateQoS performs platform specific validation of the QoS settings
// a disk can be limited by either Bps or IOps, but not both.
func ValidateQoS(hc *container.HostConfig) error {
// We may not be passed a host config, such as in the case of docker commit
if hc == nil {
return nil
}
if hc.IOMaximumBandwidth != 0 {
return fmt.Errorf("invalid QoS settings: %s does not support --maximum-bandwidth", runtime.GOOS)
}
if hc.IOMaximumIOps != 0 {
return fmt.Errorf("invalid QoS settings: %s does not support --maximum-iops", runtime.GOOS)
}
return nil
}

View File

@ -44,3 +44,17 @@ func ValidateIsolation(hc *container.HostConfig) error {
}
return nil
}
// ValidateQoS performs platform specific validation of the Qos settings
// a disk can be limited by either Bps or IOps, but not both.
func ValidateQoS(hc *container.HostConfig) error {
// We may not be passed a host config, such as in the case of docker commit
if hc == nil {
return nil
}
if hc.IOMaximumIOps != 0 && hc.IOMaximumBandwidth != 0 {
return fmt.Errorf("invalid QoS settings: maximum bandwidth and maximum iops cannot both be set")
}
return nil
}

View File

@ -84,6 +84,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
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)")
flBlkioWeight = cmd.Uint16([]string{"-blkio-weight"}, 0, "Block IO (relative weight), between 10 and 1000")
flIOMaxBandwidth = cmd.String([]string{"-io-maxbandwidth"}, "", "Maximum IO bandwidth limit for the system drive (Windows only)")
flIOMaxIOps = cmd.Uint64([]string{"-io-maxiops"}, 0, "Maximum IOps limit for the system drive (Windows only)")
flSwappiness = cmd.Int64([]string{"-memory-swappiness"}, -1, "Tune container memory swappiness (0 to 100)")
flNetMode = cmd.String([]string{"-net"}, "default", "Connect a container to a network")
flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
@ -210,6 +212,18 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
}
}
// TODO FIXME units.RAMInBytes should have a uint64 version
var maxIOBandwidth int64
if *flIOMaxBandwidth != "" {
maxIOBandwidth, err = units.RAMInBytes(*flIOMaxBandwidth)
if err != nil {
return nil, nil, nil, cmd, err
}
if maxIOBandwidth < 0 {
return nil, nil, nil, cmd, fmt.Errorf("invalid value: %s. Maximum IO Bandwidth must be positive", *flIOMaxBandwidth)
}
}
var binds []string
// add any bind targets to the list of container volumes
for bind := range flVolumes.GetMap() {
@ -368,6 +382,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
BlkioDeviceWriteBps: flDeviceWriteBps.GetList(),
BlkioDeviceReadIOps: flDeviceReadIOps.GetList(),
BlkioDeviceWriteIOps: flDeviceWriteIOps.GetList(),
IOMaximumIOps: *flIOMaxIOps,
IOMaximumBandwidth: uint64(maxIOBandwidth),
Ulimits: flUlimits.GetList(),
Devices: deviceMappings,
}