Signed-off-by: Darren Stahl <darst@microsoft.com>
| ... | ... |
@@ -450,6 +450,9 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi |
| 450 | 450 |
if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) {
|
| 451 | 451 |
return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000")
|
| 452 | 452 |
} |
| 453 |
+ if resources.IOMaximumBandwidth != 0 || resources.IOMaximumIOps != 0 {
|
|
| 454 |
+ return warnings, fmt.Errorf("Invalid QoS settings: %s does not support Maximum IO Bandwidth or Maximum IO IOps", runtime.GOOS)
|
|
| 455 |
+ } |
|
| 453 | 456 |
if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
|
| 454 | 457 |
warnings = append(warnings, "Your kernel does not support Block I/O weight_device.") |
| 455 | 458 |
logrus.Warnf("Your kernel does not support Block I/O weight_device. Weight-device discarded.")
|
| ... | ... |
@@ -13,18 +13,18 @@ import ( |
| 13 | 13 |
"github.com/Sirupsen/logrus" |
| 14 | 14 |
"github.com/docker/docker/container" |
| 15 | 15 |
"github.com/docker/docker/daemon/graphdriver" |
| 16 |
+ "github.com/docker/docker/daemon/graphdriver/windows" // register the windows graph driver |
|
| 16 | 17 |
"github.com/docker/docker/dockerversion" |
| 17 | 18 |
"github.com/docker/docker/image" |
| 18 | 19 |
"github.com/docker/docker/layer" |
| 19 |
- "github.com/docker/docker/pkg/sysinfo" |
|
| 20 |
- "github.com/docker/docker/reference" |
|
| 21 |
- "github.com/docker/docker/runconfig" |
|
| 22 |
- // register the windows graph driver |
|
| 23 |
- "github.com/docker/docker/daemon/graphdriver/windows" |
|
| 24 | 20 |
"github.com/docker/docker/pkg/idtools" |
| 25 | 21 |
"github.com/docker/docker/pkg/parsers" |
| 22 |
+ "github.com/docker/docker/pkg/sysinfo" |
|
| 26 | 23 |
"github.com/docker/docker/pkg/system" |
| 24 |
+ "github.com/docker/docker/reference" |
|
| 25 |
+ "github.com/docker/docker/runconfig" |
|
| 27 | 26 |
"github.com/docker/engine-api/types" |
| 27 |
+ pblkiodev "github.com/docker/engine-api/types/blkiodev" |
|
| 28 | 28 |
containertypes "github.com/docker/engine-api/types/container" |
| 29 | 29 |
"github.com/docker/libnetwork" |
| 30 | 30 |
nwconfig "github.com/docker/libnetwork/config" |
| ... | ... |
@@ -107,13 +107,44 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi |
| 107 | 107 |
return warnings, fmt.Errorf("Conflicting options: CPU Shares and CPU Percent cannot both be set")
|
| 108 | 108 |
} |
| 109 | 109 |
|
| 110 |
+ // TODO Windows: Add more validation of resource settings not supported on Windows |
|
| 111 |
+ |
|
| 112 |
+ if resources.BlkioWeight > 0 {
|
|
| 113 |
+ warnings = append(warnings, "Windows does not support Block I/O weight. Weight discarded.") |
|
| 114 |
+ logrus.Warnf("Windows does not support Block I/O weight. --blkio-weight discarded.")
|
|
| 115 |
+ resources.BlkioWeight = 0 |
|
| 116 |
+ } |
|
| 117 |
+ if len(resources.BlkioWeightDevice) > 0 {
|
|
| 118 |
+ warnings = append(warnings, "Windows does not support Block I/O weight_device.") |
|
| 119 |
+ logrus.Warnf("Windows does not support Block I/O weight_device. --blkio-weight-device discarded.")
|
|
| 120 |
+ resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
|
|
| 121 |
+ } |
|
| 122 |
+ if len(resources.BlkioDeviceReadBps) > 0 {
|
|
| 123 |
+ warnings = append(warnings, "Windows does not support Block read limit in bytes per second.") |
|
| 124 |
+ logrus.Warnf("Windows does not support Block I/O read limit in bytes per second. --device-read-bps discarded.")
|
|
| 125 |
+ resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
|
|
| 126 |
+ } |
|
| 127 |
+ if len(resources.BlkioDeviceWriteBps) > 0 {
|
|
| 128 |
+ warnings = append(warnings, "Windows does not support Block write limit in bytes per second.") |
|
| 129 |
+ logrus.Warnf("Windows does not support Block I/O write limit in bytes per second. --device-write-bps discarded.")
|
|
| 130 |
+ resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
|
|
| 131 |
+ } |
|
| 132 |
+ if len(resources.BlkioDeviceReadIOps) > 0 {
|
|
| 133 |
+ warnings = append(warnings, "Windows does not support Block read limit in IO per second.") |
|
| 134 |
+ logrus.Warnf("Windows does not support Block I/O read limit in IO per second. -device-read-iops discarded.")
|
|
| 135 |
+ resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
|
|
| 136 |
+ } |
|
| 137 |
+ if len(resources.BlkioDeviceWriteIOps) > 0 {
|
|
| 138 |
+ warnings = append(warnings, "Windows does not support Block write limit in IO per second.") |
|
| 139 |
+ logrus.Warnf("Windows does not support Block I/O write limit in IO per second. --device-write-iops discarded.")
|
|
| 140 |
+ resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
|
|
| 141 |
+ } |
|
| 110 | 142 |
return warnings, nil |
| 111 | 143 |
} |
| 112 | 144 |
|
| 113 | 145 |
// verifyPlatformContainerSettings performs platform-specific validation of the |
| 114 | 146 |
// hostconfig and config structures. |
| 115 | 147 |
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
|
| 116 |
- |
|
| 117 | 148 |
warnings := []string{}
|
| 118 | 149 |
|
| 119 | 150 |
w, err := verifyContainerResources(&hostConfig.Resources, nil) |
| ... | ... |
@@ -181,9 +181,9 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e |
| 181 | 181 |
//TODO Bandwidth: ..., |
| 182 | 182 |
}, |
| 183 | 183 |
Storage: &windowsoci.Storage{
|
| 184 |
- //TODO Bps: ..., |
|
| 185 |
- //TODO Iops: ..., |
|
| 186 |
- //TODO SandboxSize: ..., |
|
| 184 |
+ Bps: &c.HostConfig.IOMaximumBandwidth, |
|
| 185 |
+ Iops: &c.HostConfig.IOMaximumIOps, |
|
| 186 |
+ //TODO SandboxSize: ..., |
|
| 187 | 187 |
}, |
| 188 | 188 |
} |
| 189 | 189 |
return (*libcontainerd.Spec)(&s), nil |
| ... | ... |
@@ -115,6 +115,7 @@ This section lists each version from latest to oldest. Each listing includes a |
| 115 | 115 |
* `POST /containers/create` now takes `StorageOpt` field. |
| 116 | 116 |
* `GET /info` now returns `SecurityOptions` field, showing if `apparmor`, `seccomp`, or `selinux` is supported. |
| 117 | 117 |
* `GET /networks` now supports filtering by `label`. |
| 118 |
+* `POST /containers/create` now takes `MaximumIOps` and `MaximumIOBps` fields. Windows daemon only. |
|
| 118 | 119 |
|
| 119 | 120 |
### v1.23 API changes |
| 120 | 121 |
|
| ... | ... |
@@ -288,6 +288,8 @@ Create a container |
| 288 | 288 |
"CpuQuota": 50000, |
| 289 | 289 |
"CpusetCpus": "0,1", |
| 290 | 290 |
"CpusetMems": "0,1", |
| 291 |
+ "MaximumIOps": 0, |
|
| 292 |
+ "MaximumIOBps": 0, |
|
| 291 | 293 |
"BlkioWeight": 300, |
| 292 | 294 |
"BlkioWeightDevice": [{}],
|
| 293 | 295 |
"BlkioDeviceReadBps": [{}],
|
| ... | ... |
@@ -392,6 +394,8 @@ Json Parameters: |
| 392 | 392 |
- **CpuQuota** - Microseconds of CPU time that the container can get in a CPU period. |
| 393 | 393 |
- **CpusetCpus** - String value containing the `cgroups CpusetCpus` to use. |
| 394 | 394 |
- **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems. |
| 395 |
+ - **MaximumIOps** - Maximum IO absolute rate in terms of IOps. MaximumIOps and MaximumIOBps are mutually exclusive settings. |
|
| 396 |
+ - **MaximumIOBps** - Maximum IO absolute rate in terms of bytes per second. MaximumIOps and MaximumIOBps are mutually exclusive settings. |
|
| 395 | 397 |
- **BlkioWeight** - Block IO weight (relative weight) accepts a weight value between 10 and 1000. |
| 396 | 398 |
- **BlkioWeightDevice** - Block IO weight (relative device weight) in the form of: `"BlkioWeightDevice": [{"Path": "device_path", "Weight": weight}]`
|
| 397 | 399 |
- **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` |
| 533 | 533 |
"ExecIDs": null, |
| 534 | 534 |
"HostConfig": {
|
| 535 | 535 |
"Binds": null, |
| 536 |
+ "MaximumIOps": 0, |
|
| 537 |
+ "MaximumIOBps": 0, |
|
| 536 | 538 |
"BlkioWeight": 0, |
| 537 | 539 |
"BlkioWeightDevice": [{}],
|
| 538 | 540 |
"BlkioDeviceReadBps": [{}],
|
| ... | ... |
@@ -59,6 +59,15 @@ parent = "smn_cli" |
| 59 | 59 |
--log-opt=[] Log driver specific options |
| 60 | 60 |
-m, --memory="" Memory limit |
| 61 | 61 |
--mac-address="" Container MAC address (e.g. 92:d0:c6:0a:29:33) |
| 62 |
+ --io-maxbandwidth="" Maximum IO bandwidth limit for the system drive |
|
| 63 |
+ (Windows only). The format is `<number><unit>`. |
|
| 64 |
+ Unit is optional and can be `b` (bytes per second), |
|
| 65 |
+ `k` (kilobytes per second), `m` (megabytes per second), |
|
| 66 |
+ or `g` (gigabytes per second). If you omit the unit, |
|
| 67 |
+ the system uses bytes per second. |
|
| 68 |
+ --io-maxbandwidth and --io-maxiops are mutually exclusive options. |
|
| 69 |
+ --io-maxiops=0 Maximum IO per second limit for the system drive (Windows only). |
|
| 70 |
+ --io-maxbandwidth and --io-maxiops are mutually exclusive options. |
|
| 62 | 71 |
--memory-reservation="" Memory soft limit |
| 63 | 72 |
--memory-swap="" A positive integer equal to memory plus swap. Specify -1 to enable unlimited swap. |
| 64 | 73 |
--memory-swappiness="" Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100. |
| ... | ... |
@@ -62,6 +62,11 @@ func DecodeContainerConfig(src io.Reader) (*container.Config, *container.HostCon |
| 62 | 62 |
if err := ValidateIsolation(hc); err != nil {
|
| 63 | 63 |
return nil, nil, nil, err |
| 64 | 64 |
} |
| 65 |
+ |
|
| 66 |
+ // Validate QoS |
|
| 67 |
+ if err := ValidateQoS(hc); err != nil {
|
|
| 68 |
+ return nil, nil, nil, err |
|
| 69 |
+ } |
|
| 65 | 70 |
return w.Config, hc, w.NetworkingConfig, nil |
| 66 | 71 |
} |
| 67 | 72 |
|
| ... | ... |
@@ -87,3 +87,21 @@ func ValidateIsolation(hc *container.HostConfig) error {
|
| 87 | 87 |
} |
| 88 | 88 |
return nil |
| 89 | 89 |
} |
| 90 |
+ |
|
| 91 |
+// ValidateQoS performs platform specific validation of the QoS settings |
|
| 92 |
+// a disk can be limited by either Bps or IOps, but not both. |
|
| 93 |
+func ValidateQoS(hc *container.HostConfig) error {
|
|
| 94 |
+ // We may not be passed a host config, such as in the case of docker commit |
|
| 95 |
+ if hc == nil {
|
|
| 96 |
+ return nil |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ if hc.IOMaximumBandwidth != 0 {
|
|
| 100 |
+ return fmt.Errorf("invalid QoS settings: %s does not support --maximum-bandwidth", runtime.GOOS)
|
|
| 101 |
+ } |
|
| 102 |
+ |
|
| 103 |
+ if hc.IOMaximumIOps != 0 {
|
|
| 104 |
+ return fmt.Errorf("invalid QoS settings: %s does not support --maximum-iops", runtime.GOOS)
|
|
| 105 |
+ } |
|
| 106 |
+ return nil |
|
| 107 |
+} |
| ... | ... |
@@ -44,3 +44,17 @@ func ValidateIsolation(hc *container.HostConfig) error {
|
| 44 | 44 |
} |
| 45 | 45 |
return nil |
| 46 | 46 |
} |
| 47 |
+ |
|
| 48 |
+// ValidateQoS performs platform specific validation of the Qos settings |
|
| 49 |
+// a disk can be limited by either Bps or IOps, but not both. |
|
| 50 |
+func ValidateQoS(hc *container.HostConfig) error {
|
|
| 51 |
+ // We may not be passed a host config, such as in the case of docker commit |
|
| 52 |
+ if hc == nil {
|
|
| 53 |
+ return nil |
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 56 |
+ if hc.IOMaximumIOps != 0 && hc.IOMaximumBandwidth != 0 {
|
|
| 57 |
+ return fmt.Errorf("invalid QoS settings: maximum bandwidth and maximum iops cannot both be set")
|
|
| 58 |
+ } |
|
| 59 |
+ return nil |
|
| 60 |
+} |
| ... | ... |
@@ -84,6 +84,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host |
| 84 | 84 |
flCpusetCpus = cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
|
| 85 | 85 |
flCpusetMems = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
|
| 86 | 86 |
flBlkioWeight = cmd.Uint16([]string{"-blkio-weight"}, 0, "Block IO (relative weight), between 10 and 1000")
|
| 87 |
+ flIOMaxBandwidth = cmd.String([]string{"-io-maxbandwidth"}, "", "Maximum IO bandwidth limit for the system drive (Windows only)")
|
|
| 88 |
+ flIOMaxIOps = cmd.Uint64([]string{"-io-maxiops"}, 0, "Maximum IOps limit for the system drive (Windows only)")
|
|
| 87 | 89 |
flSwappiness = cmd.Int64([]string{"-memory-swappiness"}, -1, "Tune container memory swappiness (0 to 100)")
|
| 88 | 90 |
flNetMode = cmd.String([]string{"-net"}, "default", "Connect a container to a network")
|
| 89 | 91 |
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 |
| 210 | 210 |
} |
| 211 | 211 |
} |
| 212 | 212 |
|
| 213 |
+ // TODO FIXME units.RAMInBytes should have a uint64 version |
|
| 214 |
+ var maxIOBandwidth int64 |
|
| 215 |
+ if *flIOMaxBandwidth != "" {
|
|
| 216 |
+ maxIOBandwidth, err = units.RAMInBytes(*flIOMaxBandwidth) |
|
| 217 |
+ if err != nil {
|
|
| 218 |
+ return nil, nil, nil, cmd, err |
|
| 219 |
+ } |
|
| 220 |
+ if maxIOBandwidth < 0 {
|
|
| 221 |
+ return nil, nil, nil, cmd, fmt.Errorf("invalid value: %s. Maximum IO Bandwidth must be positive", *flIOMaxBandwidth)
|
|
| 222 |
+ } |
|
| 223 |
+ } |
|
| 224 |
+ |
|
| 213 | 225 |
var binds []string |
| 214 | 226 |
// add any bind targets to the list of container volumes |
| 215 | 227 |
for bind := range flVolumes.GetMap() {
|
| ... | ... |
@@ -368,6 +382,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host |
| 368 | 368 |
BlkioDeviceWriteBps: flDeviceWriteBps.GetList(), |
| 369 | 369 |
BlkioDeviceReadIOps: flDeviceReadIOps.GetList(), |
| 370 | 370 |
BlkioDeviceWriteIOps: flDeviceWriteIOps.GetList(), |
| 371 |
+ IOMaximumIOps: *flIOMaxIOps, |
|
| 372 |
+ IOMaximumBandwidth: uint64(maxIOBandwidth), |
|
| 371 | 373 |
Ulimits: flUlimits.GetList(), |
| 372 | 374 |
Devices: deviceMappings, |
| 373 | 375 |
} |