فهرست منبع

Add support for blkio read/write iops device

Signed-off-by: Ma Shimiao <mashimiao.fnst@cn.fujitsu.com>
Ma Shimiao 10 سال پیش
والد
کامیت
843084b08b

+ 2 - 0
contrib/completion/bash/docker

@@ -1389,7 +1389,9 @@ _docker_run() {
 		--cpu-shares
 		--cpu-shares
 		--device
 		--device
 		--device-read-bps
 		--device-read-bps
+		--device-read-iops
 		--device-write-bps
 		--device-write-bps
+		--device-write-iops
 		--dns
 		--dns
 		--dns-opt
 		--dns-opt
 		--dns-search
 		--dns-search

+ 2 - 0
contrib/completion/zsh/_docker

@@ -469,7 +469,9 @@ __docker_subcommand() {
         "($help)--cidfile=[Write the container ID to the file]:CID file:_files"
         "($help)--cidfile=[Write the container ID to the file]:CID file:_files"
         "($help)*--device=[Add a host device to the container]:device:_files"
         "($help)*--device=[Add a host device to the container]:device:_files"
         "($help)*--device-read-bps=[Limit the read rate (bytes per second) from a device]:device:IO rate: "
         "($help)*--device-read-bps=[Limit the read rate (bytes per second) from a device]:device:IO rate: "
+        "($help)*--device-read-iops=[Limit the read rate (IO per second) from a device]:device:IO rate: "
         "($help)*--device-write-bps=[Limit the write rate (bytes per second) to a device]:device:IO rate: "
         "($help)*--device-write-bps=[Limit the write rate (bytes per second) to a device]:device:IO rate: "
+        "($help)*--device-write-iops=[Limit the write rate (IO per second) to a device]:device:IO rate: "
         "($help)*--dns=[Set custom DNS servers]:DNS server: "
         "($help)*--dns=[Set custom DNS servers]:DNS server: "
         "($help)*--dns-opt=[Set custom DNS options]:DNS option: "
         "($help)*--dns-opt=[Set custom DNS options]:DNS option: "
         "($help)*--dns-search=[Set custom DNS search domains]:DNS domains: "
         "($help)*--dns-search=[Set custom DNS search domains]:DNS domains: "

+ 24 - 12
daemon/container_operations_unix.go

@@ -174,6 +174,16 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
 		return err
 		return err
 	}
 	}
 
 
+	readIOpsDevice, err := getBlkioReadIOpsDevices(c.HostConfig)
+	if err != nil {
+		return err
+	}
+
+	writeIOpsDevice, err := getBlkioWriteIOpsDevices(c.HostConfig)
+	if err != nil {
+		return err
+	}
+
 	for _, limit := range ulimits {
 	for _, limit := range ulimits {
 		rl, err := limit.GetRlimit()
 		rl, err := limit.GetRlimit()
 		if err != nil {
 		if err != nil {
@@ -189,18 +199,20 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
 			CPUShares:         c.HostConfig.CPUShares,
 			CPUShares:         c.HostConfig.CPUShares,
 			BlkioWeight:       c.HostConfig.BlkioWeight,
 			BlkioWeight:       c.HostConfig.BlkioWeight,
 		},
 		},
-		MemorySwap:                  c.HostConfig.MemorySwap,
-		KernelMemory:                c.HostConfig.KernelMemory,
-		CpusetCpus:                  c.HostConfig.CpusetCpus,
-		CpusetMems:                  c.HostConfig.CpusetMems,
-		CPUPeriod:                   c.HostConfig.CPUPeriod,
-		CPUQuota:                    c.HostConfig.CPUQuota,
-		Rlimits:                     rlimits,
-		BlkioWeightDevice:           weightDevices,
-		BlkioThrottleReadBpsDevice:  readBpsDevice,
-		BlkioThrottleWriteBpsDevice: writeBpsDevice,
-		OomKillDisable:              c.HostConfig.OomKillDisable,
-		MemorySwappiness:            -1,
+		MemorySwap:                   c.HostConfig.MemorySwap,
+		KernelMemory:                 c.HostConfig.KernelMemory,
+		CpusetCpus:                   c.HostConfig.CpusetCpus,
+		CpusetMems:                   c.HostConfig.CpusetMems,
+		CPUPeriod:                    c.HostConfig.CPUPeriod,
+		CPUQuota:                     c.HostConfig.CPUQuota,
+		Rlimits:                      rlimits,
+		BlkioWeightDevice:            weightDevices,
+		BlkioThrottleReadBpsDevice:   readBpsDevice,
+		BlkioThrottleWriteBpsDevice:  writeBpsDevice,
+		BlkioThrottleReadIOpsDevice:  readIOpsDevice,
+		BlkioThrottleWriteIOpsDevice: writeIOpsDevice,
+		OomKillDisable:               c.HostConfig.OomKillDisable,
+		MemorySwappiness:             -1,
 	}
 	}
 
 
 	if c.HostConfig.MemorySwappiness != nil {
 	if c.HostConfig.MemorySwappiness != nil {

+ 40 - 1
daemon/daemon_unix.go

@@ -85,6 +85,36 @@ func parseSecurityOpt(container *container.Container, config *runconfig.HostConf
 	return err
 	return err
 }
 }
 
 
+func getBlkioReadIOpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
+	var blkioReadIOpsDevice []*blkiodev.ThrottleDevice
+	var stat syscall.Stat_t
+
+	for _, iopsDevice := range config.BlkioDeviceReadIOps {
+		if err := syscall.Stat(iopsDevice.Path, &stat); err != nil {
+			return nil, err
+		}
+		readIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate)
+		blkioReadIOpsDevice = append(blkioReadIOpsDevice, readIOpsDevice)
+	}
+
+	return blkioReadIOpsDevice, nil
+}
+
+func getBlkioWriteIOpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
+	var blkioWriteIOpsDevice []*blkiodev.ThrottleDevice
+	var stat syscall.Stat_t
+
+	for _, iopsDevice := range config.BlkioDeviceWriteIOps {
+		if err := syscall.Stat(iopsDevice.Path, &stat); err != nil {
+			return nil, err
+		}
+		writeIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate)
+		blkioWriteIOpsDevice = append(blkioWriteIOpsDevice, writeIOpsDevice)
+	}
+
+	return blkioWriteIOpsDevice, nil
+}
+
 func getBlkioReadBpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
 func getBlkioReadBpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
 	var blkioReadBpsDevice []*blkiodev.ThrottleDevice
 	var blkioReadBpsDevice []*blkiodev.ThrottleDevice
 	var stat syscall.Stat_t
 	var stat syscall.Stat_t
@@ -299,6 +329,16 @@ func verifyContainerResources(resources *runconfig.Resources) ([]string, error)
 		logrus.Warnf("Your kernel does not support Block I/O write limit in bytes per second. --device-write-bps discarded.")
 		logrus.Warnf("Your kernel does not support Block I/O write limit in bytes per second. --device-write-bps discarded.")
 		resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
 		resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
 	}
 	}
+	if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
+		warnings = append(warnings, "Your kernel does not support Block read limit in IO per second.")
+		logrus.Warnf("Your kernel 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 && !sysInfo.BlkioWriteIOpsDevice {
+		warnings = append(warnings, "Your kernel does not support Block write limit in IO per second.")
+		logrus.Warnf("Your kernel does not support Block I/O write limit in IO per second. --device-write-iops discarded.")
+		resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
+	}
 
 
 	return warnings, nil
 	return warnings, nil
 }
 }
@@ -328,7 +368,6 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostC
 		hostConfig.OomKillDisable = false
 		hostConfig.OomKillDisable = false
 		return warnings, fmt.Errorf("Your kernel does not support oom kill disable.")
 		return warnings, fmt.Errorf("Your kernel does not support oom kill disable.")
 	}
 	}
-
 	if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
 	if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
 		return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000].", hostConfig.OomScoreAdj)
 		return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000].", hostConfig.OomScoreAdj)
 	}
 	}

+ 8 - 0
daemon/daemon_windows.go

@@ -38,6 +38,14 @@ func parseSecurityOpt(container *container.Container, config *runconfig.HostConf
 	return nil
 	return nil
 }
 }
 
 
+func getBlkioReadIOpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
+	return nil, nil
+}
+
+func getBlkioWriteIOpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
+	return nil, nil
+}
+
 func getBlkioReadBpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
 func getBlkioReadBpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
 	return nil, nil
 	return nil, nil
 }
 }

+ 16 - 12
daemon/execdriver/driver_unix.go

@@ -37,18 +37,20 @@ type Resources struct {
 
 
 	// Fields below here are platform specific
 	// Fields below here are platform specific
 
 
-	BlkioWeightDevice           []*blkiodev.WeightDevice   `json:"blkio_weight_device"`
-	BlkioThrottleReadBpsDevice  []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_bps_device"`
-	BlkioThrottleWriteBpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_bps_device"`
-	MemorySwap                  int64                      `json:"memory_swap"`
-	KernelMemory                int64                      `json:"kernel_memory"`
-	CPUQuota                    int64                      `json:"cpu_quota"`
-	CpusetCpus                  string                     `json:"cpuset_cpus"`
-	CpusetMems                  string                     `json:"cpuset_mems"`
-	CPUPeriod                   int64                      `json:"cpu_period"`
-	Rlimits                     []*ulimit.Rlimit           `json:"rlimits"`
-	OomKillDisable              bool                       `json:"oom_kill_disable"`
-	MemorySwappiness            int64                      `json:"memory_swappiness"`
+	BlkioWeightDevice            []*blkiodev.WeightDevice   `json:"blkio_weight_device"`
+	BlkioThrottleReadBpsDevice   []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_bps_device"`
+	BlkioThrottleWriteBpsDevice  []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_bps_device"`
+	BlkioThrottleReadIOpsDevice  []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_iops_device"`
+	BlkioThrottleWriteIOpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_iops_device"`
+	MemorySwap                   int64                      `json:"memory_swap"`
+	KernelMemory                 int64                      `json:"kernel_memory"`
+	CPUQuota                     int64                      `json:"cpu_quota"`
+	CpusetCpus                   string                     `json:"cpuset_cpus"`
+	CpusetMems                   string                     `json:"cpuset_mems"`
+	CPUPeriod                    int64                      `json:"cpu_period"`
+	Rlimits                      []*ulimit.Rlimit           `json:"rlimits"`
+	OomKillDisable               bool                       `json:"oom_kill_disable"`
+	MemorySwappiness             int64                      `json:"memory_swappiness"`
 }
 }
 
 
 // ProcessConfig is the platform specific structure that describes a process
 // ProcessConfig is the platform specific structure that describes a process
@@ -181,6 +183,8 @@ func SetupCgroups(container *configs.Config, c *Command) error {
 		container.Cgroups.BlkioWeightDevice = c.Resources.BlkioWeightDevice
 		container.Cgroups.BlkioWeightDevice = c.Resources.BlkioWeightDevice
 		container.Cgroups.BlkioThrottleReadBpsDevice = c.Resources.BlkioThrottleReadBpsDevice
 		container.Cgroups.BlkioThrottleReadBpsDevice = c.Resources.BlkioThrottleReadBpsDevice
 		container.Cgroups.BlkioThrottleWriteBpsDevice = c.Resources.BlkioThrottleWriteBpsDevice
 		container.Cgroups.BlkioThrottleWriteBpsDevice = c.Resources.BlkioThrottleWriteBpsDevice
+		container.Cgroups.BlkioThrottleReadIOPSDevice = c.Resources.BlkioThrottleReadIOpsDevice
+		container.Cgroups.BlkioThrottleWriteIOPSDevice = c.Resources.BlkioThrottleWriteIOpsDevice
 		container.Cgroups.OomKillDisable = c.Resources.OomKillDisable
 		container.Cgroups.OomKillDisable = c.Resources.OomKillDisable
 		container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness
 		container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness
 	}
 	}

+ 2 - 0
docs/reference/api/docker_remote_api.md

@@ -107,6 +107,8 @@ This section lists each version from latest to oldest.  Each listing includes a
 * Pushes initiated with `POST /images/(name)/push` and pulls initiated with `POST /images/create`
 * Pushes initiated with `POST /images/(name)/push` and pulls initiated with `POST /images/create`
   will be cancelled if the HTTP connection making the API request is closed before
   will be cancelled if the HTTP connection making the API request is closed before
   the push or pull completes.
   the push or pull completes.
+* `POST /containers/create` now allows you to set a read/write rate limit for a 
+  device (in bytes per second or IO per second).
 
 
 ### v1.21 API changes
 ### v1.21 API changes
 
 

+ 10 - 2
docs/reference/api/docker_remote_api_v1.22.md

@@ -248,7 +248,9 @@ Create a container
              "BlkioWeight": 300,
              "BlkioWeight": 300,
              "BlkioWeightDevice": [{}],
              "BlkioWeightDevice": [{}],
              "BlkioDeviceReadBps": [{}],
              "BlkioDeviceReadBps": [{}],
+             "BlkioDeviceReadIOps": [{}],
              "BlkioDeviceWriteBps": [{}],
              "BlkioDeviceWriteBps": [{}],
+             "BlkioDeviceWriteIOps": [{}],
              "MemorySwappiness": 60,
              "MemorySwappiness": 60,
              "OomKillDisable": false,
              "OomKillDisable": false,
              "OomScoreAdj": 500,
              "OomScoreAdj": 500,
@@ -306,10 +308,14 @@ Json Parameters:
 -   **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
 -   **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
 -   **BlkioWeight** - Block IO weight (relative weight) accepts a weight value between 10 and 1000.
 -   **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}]`
 -   **BlkioWeightDevice** - Block IO weight (relative device weight) in the form of:        `"BlkioWeightDevice": [{"Path": "device_path", "Weight": weight}]`
--   **BlkioDeviceReadBps** - Limit read rate from a device in form of:	`"BlkioDeviceReadBps": [{"Path": "device_path", "Rate": rate}]`, for example:
+-   **BlkioDeviceReadBps** - Limit read rate (bytes per second) from a device in the form of:	`"BlkioDeviceReadBps": [{"Path": "device_path", "Rate": rate}]`, for example:
 	`"BlkioDeviceReadBps": [{"Path": "/dev/sda", "Rate": "1024"}]"`
 	`"BlkioDeviceReadBps": [{"Path": "/dev/sda", "Rate": "1024"}]"`
--   **BlkioDeviceWriteBps** - Limit write rate to a device in the form of:	`"BlkioDeviceWriteBps": [{"Path": "device_path", "Rate": rate}]`, for example:
+-   **BlkioDeviceWriteBps** - Limit write rate (bytes per second) to a device in the form of:	`"BlkioDeviceWriteBps": [{"Path": "device_path", "Rate": rate}]`, for example:
 	`"BlkioDeviceWriteBps": [{"Path": "/dev/sda", "Rate": "1024"}]"`
 	`"BlkioDeviceWriteBps": [{"Path": "/dev/sda", "Rate": "1024"}]"`
+-   **BlkioDeviceReadIOps** - Limit read rate (IO per second) from a device in the form of:	`"BlkioDeviceReadIOps": [{"Path": "device_path", "Rate": rate}]`, for example:
+	`"BlkioDeviceReadIOps": [{"Path": "/dev/sda", "Rate": "1000"}]`
+-   **BlkioDeviceWiiteIOps** - Limit write rate (IO per second) to a device in the form of:	`"BlkioDeviceWriteIOps": [{"Path": "device_path", "Rate": rate}]`, for example:
+	`"BlkioDeviceWriteIOps": [{"Path": "/dev/sda", "Rate": "1000"}]`
 -   **MemorySwappiness** - Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
 -   **MemorySwappiness** - Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
 -   **OomKillDisable** - Boolean value, whether to disable OOM Killer for the container or not.
 -   **OomKillDisable** - Boolean value, whether to disable OOM Killer for the container or not.
 -   **OomScoreAdj** - An integer value containing the score given to the container in order to tune OOM killer preferences.
 -   **OomScoreAdj** - An integer value containing the score given to the container in order to tune OOM killer preferences.
@@ -465,6 +471,8 @@ Return low-level information on the container `id`
 			"BlkioWeightDevice": [{}],
 			"BlkioWeightDevice": [{}],
 			"BlkioDeviceReadBps": [{}],
 			"BlkioDeviceReadBps": [{}],
 			"BlkioDeviceWriteBps": [{}],
 			"BlkioDeviceWriteBps": [{}],
+			"BlkioDeviceReadIOps": [{}],
+			"BlkioDeviceWriteIOps": [{}],
 			"CapAdd": null,
 			"CapAdd": null,
 			"CapDrop": null,
 			"CapDrop": null,
 			"ContainerIDFile": "",
 			"ContainerIDFile": "",

+ 2 - 0
docs/reference/commandline/create.md

@@ -31,7 +31,9 @@ Creates a new container.
       --cpuset-mems=""              Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
       --cpuset-mems=""              Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
       --device=[]                   Add a host device to the container
       --device=[]                   Add a host device to the container
       --device-read-bps=[]          Limit read rate (bytes per second) from a device (e.g., --device-read-bps=/dev/sda:1mb)
       --device-read-bps=[]          Limit read rate (bytes per second) from a device (e.g., --device-read-bps=/dev/sda:1mb)
+      --device-read-iops=[]         Limit read rate (IO per second) from a device (e.g., --device-read-iops=/dev/sda:1000)
       --device-write-bps=[]         Limit write rate (bytes per second) to a device (e.g., --device-write-bps=/dev/sda:1mb)
       --device-write-bps=[]         Limit write rate (bytes per second) to a device (e.g., --device-write-bps=/dev/sda:1mb)
+      --device-write-iops=[]        Limit write rate (IO per second) to a device (e.g., --device-write-iops=/dev/sda:1000)
       --disable-content-trust=true  Skip image verification
       --disable-content-trust=true  Skip image verification
       --dns=[]                      Set custom DNS servers
       --dns=[]                      Set custom DNS servers
       --dns-opt=[]                  Set custom DNS options
       --dns-opt=[]                  Set custom DNS options

+ 2 - 0
docs/reference/commandline/run.md

@@ -30,7 +30,9 @@ parent = "smn_cli"
       -d, --detach=false            Run container in background and print container ID
       -d, --detach=false            Run container in background and print container ID
       --device=[]                   Add a host device to the container
       --device=[]                   Add a host device to the container
       --device-read-bps=[]          Limit read rate (bytes per second) from a device (e.g., --device-read-bps=/dev/sda:1mb)
       --device-read-bps=[]          Limit read rate (bytes per second) from a device (e.g., --device-read-bps=/dev/sda:1mb)
+      --device-read-iops=[]         Limit read rate (IO per second) from a device (e.g., --device-read-iops=/dev/sda:1000)
       --device-write-bps=[]         Limit write rate (bytes per second) to a device (e.g., --device-write-bps=/dev/sda:1mb)
       --device-write-bps=[]         Limit write rate (bytes per second) to a device (e.g., --device-write-bps=/dev/sda:1mb)
+      --device-write-iops=[]        Limit write rate (IO per second) to a device (e.g., --device-write-bps=/dev/sda:1000)
       --disable-content-trust=true  Skip image verification
       --disable-content-trust=true  Skip image verification
       --dns=[]                      Set custom DNS servers
       --dns=[]                      Set custom DNS servers
       --dns-opt=[]                  Set custom DNS options
       --dns-opt=[]                  Set custom DNS options

+ 23 - 6
docs/reference/run.md

@@ -632,6 +632,8 @@ container:
 | `--blkio-weight-device=""` | Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)                                                                          |
 | `--blkio-weight-device=""` | Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)                                                                          |
 | `--device-read-bps=""`     | Limit read rate from a device (format: `<device-path>:<number>[<unit>]`). Number is a positive integer. Unit can be one of `kb`, `mb`, or `gb`. |
 | `--device-read-bps=""`     | Limit read rate from a device (format: `<device-path>:<number>[<unit>]`). Number is a positive integer. Unit can be one of `kb`, `mb`, or `gb`. |
 | `--device-write-bps=""`    | Limit write rate to a device (format: `<device-path>:<number>[<unit>]`). Number is a positive integer. Unit can be one of `kb`, `mb`, or `gb`.  |
 | `--device-write-bps=""`    | Limit write rate to a device (format: `<device-path>:<number>[<unit>]`). Number is a positive integer. Unit can be one of `kb`, `mb`, or `gb`.  |
+| `--device-read-iops="" `   | Limit read rate (IO per second) from a device (format: `<device-path>:<number>`). Number is a positive integer.                                 |
+| `--device-write-iops="" `  | Limit write rate (IO per second) to a device (format: `<device-path>:<number>`). Number is a positive integer.                                  |
 | `--oom-kill-disable=false` | Whether to disable OOM Killer for the container or not.                                                                                         |
 | `--oom-kill-disable=false` | Whether to disable OOM Killer for the container or not.                                                                                         |
 | `--memory-swappiness=""`   | Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.                                                            |
 | `--memory-swappiness=""`   | Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.                                                            |
 | `--shm-size=""`            | Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. |
 | `--shm-size=""`            | Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. |
@@ -983,15 +985,15 @@ on `/dev/sda` setting that weight to `200`:
         --blkio-weight-device "/dev/sda:200" \
         --blkio-weight-device "/dev/sda:200" \
         ubuntu
         ubuntu
 
 
-The `--device-read-bps` flag limits the read rate from a device. For example,
-this command creates a container and limits the read rate to `1mb` per second
-from `/dev/sda`:
+The `--device-read-bps` flag limits the read rate (bytes per second) from a device.
+For example, this command creates a container and limits the read rate to `1mb`
+per second from `/dev/sda`:
 
 
     $ docker run -it --device-read-bps /dev/sda:1mb ubuntu
     $ docker run -it --device-read-bps /dev/sda:1mb ubuntu
 
 
-The `--device-write-bps` flag limits the write rate to a device. For example,
-this command creates a container and limits the write rate to `1mb` per second
-for `/dev/sda`: 
+The `--device-write-bps` flag limits the write rate (bytes per second)to a device.
+For example, this command creates a container and limits the write rate to `1mb`
+per second for `/dev/sda`: 
 
 
     $ docker run -it --device-write-bps /dev/sda:1mb ubuntu
     $ docker run -it --device-write-bps /dev/sda:1mb ubuntu
 
 
@@ -999,6 +1001,21 @@ Both flags take limits in the `<device-path>:<limit>[unit]` format. Both read
 and write rates must be a positive integer. You can specify the rate in `kb`
 and write rates must be a positive integer. You can specify the rate in `kb`
 (kilobytes), `mb` (megabytes), or `gb` (gigabytes).
 (kilobytes), `mb` (megabytes), or `gb` (gigabytes).
 
 
+The `--device-read-iops` flag limits read rate (IO per second) from a device.
+For example, this command creates a container and limits the read rate to
+`1000` IO per second from `/dev/sda`:
+
+    $ docker run -ti --device-read-iops /dev/sda:1000 ubuntu
+
+The `--device-write-iops` flag limits write rate (IO per second) to a device.
+For example, this command creates a container and limits the write rate to
+`1000` IO per second to `/dev/sda`:
+
+    $ docker run -ti --device-write-iops /dev/sda:1000 ubuntu
+
+Both flags take limits in the `<device-path>:<limit>` format. Both read and
+write rates must be a positive integer.
+
 ## Additional groups
 ## Additional groups
     --group-add: Add Linux capabilities
     --group-add: Add Linux capabilities
 
 

+ 12 - 0
integration-cli/docker_cli_run_unix_test.go

@@ -267,6 +267,18 @@ func (s *DockerSuite) TestRunWithBlkioInvalidDeviceWriteBps(c *check.C) {
 	c.Assert(err, check.NotNil, check.Commentf(out))
 	c.Assert(err, check.NotNil, check.Commentf(out))
 }
 }
 
 
+func (s *DockerSuite) TestRunWithBlkioInvalidReadiopsDevice(c *check.C) {
+	testRequires(c, blkioWeight)
+	out, _, err := dockerCmdWithError("run", "--device-read-iops", "/dev/sdX:500", "busybox", "true")
+	c.Assert(err, check.NotNil, check.Commentf(out))
+}
+
+func (s *DockerSuite) TestRunWithBlkioInvalidWriteiopsDevice(c *check.C) {
+	testRequires(c, blkioWeight)
+	out, _, err := dockerCmdWithError("run", "--device-write-iops", "/dev/sdX:500", "busybox", "true")
+	c.Assert(err, check.NotNil, check.Commentf(out))
+}
+
 func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
 func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
 	testRequires(c, oomControl)
 	testRequires(c, oomControl)
 	errChan := make(chan error)
 	errChan := make(chan error)

+ 8 - 0
man/docker-create.1.md

@@ -21,7 +21,9 @@ docker-create - Create a new container
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
 [**--device**[=*[]*]]
 [**--device**[=*[]*]]
 [**--device-read-bps**[=*[]*]]
 [**--device-read-bps**[=*[]*]]
+[**--device-read-iops**[=*[]*]]
 [**--device-write-bps**[=*[]*]]
 [**--device-write-bps**[=*[]*]]
+[**--device-write-iops**[=*[]*]]
 [**--dns**[=*[]*]]
 [**--dns**[=*[]*]]
 [**--dns-search**[=*[]*]]
 [**--dns-search**[=*[]*]]
 [**--dns-opt**[=*[]*]]
 [**--dns-opt**[=*[]*]]
@@ -130,9 +132,15 @@ two memory nodes.
 **--device-read-bps**=[]
 **--device-read-bps**=[]
     Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)
     Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)
 
 
+**--device-read-iops**=[]
+    Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)
+
 **--device-write-bps**=[]
 **--device-write-bps**=[]
     Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)
     Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)
 
 
+**--device-write-iops**=[]
+    Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)
+
 **--dns**=[]
 **--dns**=[]
    Set custom DNS servers
    Set custom DNS servers
 
 

+ 8 - 0
man/docker-run.1.md

@@ -22,7 +22,9 @@ docker-run - Run a command in a new container
 [**-d**|**--detach**[=*false*]]
 [**-d**|**--detach**[=*false*]]
 [**--device**[=*[]*]]
 [**--device**[=*[]*]]
 [**--device-read-bps**[=*[]*]]
 [**--device-read-bps**[=*[]*]]
+[**--device-read-iops**[=*[]*]]
 [**--device-write-bps**[=*[]*]]
 [**--device-write-bps**[=*[]*]]
+[**--device-write-iops**[=*[]*]]
 [**--dns**[=*[]*]]
 [**--dns**[=*[]*]]
 [**--dns-opt**[=*[]*]]
 [**--dns-opt**[=*[]*]]
 [**--dns-search**[=*[]*]]
 [**--dns-search**[=*[]*]]
@@ -197,9 +199,15 @@ stopping the process by pressing the keys CTRL-P CTRL-Q.
 **--device-read-bps**=[]
 **--device-read-bps**=[]
    Limit read rate from a device (e.g. --device-read-bps=/dev/sda:1mb)
    Limit read rate from a device (e.g. --device-read-bps=/dev/sda:1mb)
 
 
+**--device-read-iops**=[]
+   Limit read rate from a device (e.g. --device-read-iops=/dev/sda:1000)
+
 **--device-write-bps**=[]
 **--device-write-bps**=[]
    Limit write rate to a device (e.g. --device-write-bps=/dev/sda:1mb)
    Limit write rate to a device (e.g. --device-write-bps=/dev/sda:1mb)
 
 
+**--device-write-iops**=[]
+   Limit write rate a a device (e.g. --device-write-iops=/dev/sda:1000)
+
 **--dns-search**=[]
 **--dns-search**=[]
    Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)
    Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)
 
 

+ 23 - 0
opts/opts.go

@@ -219,6 +219,29 @@ func ValidateThrottleBpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
 	}, nil
 	}, nil
 }
 }
 
 
+// ValidateThrottleIOpsDevice validates that the specified string has a valid device-rate format.
+func ValidateThrottleIOpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
+	split := strings.SplitN(val, ":", 2)
+	if len(split) != 2 {
+		return nil, fmt.Errorf("bad format: %s", val)
+	}
+	if !strings.HasPrefix(split[0], "/dev/") {
+		return nil, fmt.Errorf("bad format for device path: %s", val)
+	}
+	rate, err := strconv.ParseUint(split[1], 10, 64)
+	if err != nil {
+		return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
+	}
+	if rate < 0 {
+		return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
+	}
+
+	return &blkiodev.ThrottleDevice{
+		Path: split[0],
+		Rate: uint64(rate),
+	}, nil
+}
+
 // ValidateEnv validates an environment variable and returns it.
 // ValidateEnv validates an environment variable and returns it.
 // If no value is specified, it returns the current value using os.Getenv.
 // If no value is specified, it returns the current value using os.Getenv.
 //
 //

+ 6 - 0
pkg/sysinfo/sysinfo.go

@@ -69,6 +69,12 @@ type cgroupBlkioInfo struct {
 
 
 	// Whether Block IO write limit in bytes per second is supported or not
 	// Whether Block IO write limit in bytes per second is supported or not
 	BlkioWriteBpsDevice bool
 	BlkioWriteBpsDevice bool
+
+	// Whether Block IO read limit in IO per second is supported or not
+	BlkioReadIOpsDevice bool
+
+	// Whether Block IO write limit in IO per second is supported or not
+	BlkioWriteIOpsDevice bool
 }
 }
 
 
 type cgroupCpusetInfo struct {
 type cgroupCpusetInfo struct {

+ 15 - 4
pkg/sysinfo/sysinfo_linux.go

@@ -136,11 +136,22 @@ func checkCgroupBlkioInfo(quiet bool) cgroupBlkioInfo {
 	if !quiet && !writeBpsDevice {
 	if !quiet && !writeBpsDevice {
 		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
 		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
 	}
 	}
+	readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
+	if !quiet && !readIOpsDevice {
+		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
+	}
+
+	writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
+	if !quiet && !writeIOpsDevice {
+		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
+	}
 	return cgroupBlkioInfo{
 	return cgroupBlkioInfo{
-		BlkioWeight:         weight,
-		BlkioWeightDevice:   weightDevice,
-		BlkioReadBpsDevice:  readBpsDevice,
-		BlkioWriteBpsDevice: writeBpsDevice,
+		BlkioWeight:          weight,
+		BlkioWeightDevice:    weightDevice,
+		BlkioReadBpsDevice:   readBpsDevice,
+		BlkioWriteBpsDevice:  writeBpsDevice,
+		BlkioReadIOpsDevice:  readIOpsDevice,
+		BlkioWriteIOpsDevice: writeIOpsDevice,
 	}
 	}
 }
 }
 
 

+ 18 - 16
runconfig/hostconfig.go

@@ -171,22 +171,24 @@ type Resources struct {
 	CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers)
 	CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers)
 
 
 	// Applicable to UNIX platforms
 	// Applicable to UNIX platforms
-	CgroupParent        string // Parent cgroup.
-	BlkioWeight         uint16 // Block IO weight (relative weight vs. other containers)
-	BlkioWeightDevice   []*blkiodev.WeightDevice
-	BlkioDeviceReadBps  []*blkiodev.ThrottleDevice
-	BlkioDeviceWriteBps []*blkiodev.ThrottleDevice
-	CPUPeriod           int64            `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
-	CPUQuota            int64            `json:"CpuQuota"`  // CPU CFS (Completely Fair Scheduler) quota
-	CpusetCpus          string           // CpusetCpus 0-2, 0,1
-	CpusetMems          string           // CpusetMems 0-2, 0,1
-	Devices             []DeviceMapping  // List of devices to map inside the container
-	KernelMemory        int64            // Kernel memory limit (in bytes)
-	Memory              int64            // Memory limit (in bytes)
-	MemoryReservation   int64            // Memory soft limit (in bytes)
-	MemorySwap          int64            // Total memory usage (memory + swap); set `-1` to disable swap
-	MemorySwappiness    *int64           // Tuning container memory swappiness behaviour
-	Ulimits             []*ulimit.Ulimit // List of ulimits to be set in the container
+	CgroupParent         string // Parent cgroup.
+	BlkioWeight          uint16 // Block IO weight (relative weight vs. other containers)
+	BlkioWeightDevice    []*blkiodev.WeightDevice
+	BlkioDeviceReadBps   []*blkiodev.ThrottleDevice
+	BlkioDeviceWriteBps  []*blkiodev.ThrottleDevice
+	BlkioDeviceReadIOps  []*blkiodev.ThrottleDevice
+	BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice
+	CPUPeriod            int64            `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
+	CPUQuota             int64            `json:"CpuQuota"`  // CPU CFS (Completely Fair Scheduler) quota
+	CpusetCpus           string           // CpusetCpus 0-2, 0,1
+	CpusetMems           string           // CpusetMems 0-2, 0,1
+	Devices              []DeviceMapping  // List of devices to map inside the container
+	KernelMemory         int64            // Kernel memory limit (in bytes)
+	Memory               int64            // Memory limit (in bytes)
+	MemoryReservation    int64            // Memory soft limit (in bytes)
+	MemorySwap           int64            // Total memory usage (memory + swap); set `-1` to disable swap
+	MemorySwappiness     *int64           // Tuning container memory swappiness behaviour
+	Ulimits              []*ulimit.Ulimit // List of ulimits to be set in the container
 }
 }
 
 
 // HostConfig the non-portable Config structure of a container.
 // HostConfig the non-portable Config structure of a container.

+ 23 - 17
runconfig/parse.go

@@ -57,6 +57,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 		flDeviceReadBps     = opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice)
 		flDeviceReadBps     = opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice)
 		flDeviceWriteBps    = opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice)
 		flDeviceWriteBps    = opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice)
 		flLinks             = opts.NewListOpts(ValidateLink)
 		flLinks             = opts.NewListOpts(ValidateLink)
+		flDeviceReadIOps    = opts.NewThrottledeviceOpt(opts.ValidateThrottleIOpsDevice)
+		flDeviceWriteIOps   = opts.NewThrottledeviceOpt(opts.ValidateThrottleIOpsDevice)
 		flEnv               = opts.NewListOpts(opts.ValidateEnv)
 		flEnv               = opts.NewListOpts(opts.ValidateEnv)
 		flLabels            = opts.NewListOpts(opts.ValidateEnv)
 		flLabels            = opts.NewListOpts(opts.ValidateEnv)
 		flDevices           = opts.NewListOpts(ValidateDevice)
 		flDevices           = opts.NewListOpts(ValidateDevice)
@@ -118,6 +120,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 	cmd.Var(&flBlkioWeightDevice, []string{"-blkio-weight-device"}, "Block IO weight (relative device weight)")
 	cmd.Var(&flBlkioWeightDevice, []string{"-blkio-weight-device"}, "Block IO weight (relative device weight)")
 	cmd.Var(&flDeviceReadBps, []string{"-device-read-bps"}, "Limit read rate (bytes per second) from a device")
 	cmd.Var(&flDeviceReadBps, []string{"-device-read-bps"}, "Limit read rate (bytes per second) from a device")
 	cmd.Var(&flDeviceWriteBps, []string{"-device-write-bps"}, "Limit write rate (bytes per second) to a device")
 	cmd.Var(&flDeviceWriteBps, []string{"-device-write-bps"}, "Limit write rate (bytes per second) to a device")
+	cmd.Var(&flDeviceReadIOps, []string{"-device-read-iops"}, "Limit read rate (IO per second) from a device")
+	cmd.Var(&flDeviceWriteIOps, []string{"-device-write-iops"}, "Limit write rate (IO per second) to a device")
 	cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume")
 	cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume")
 	cmd.Var(&flTmpfs, []string{"-tmpfs"}, "Mount a tmpfs directory")
 	cmd.Var(&flTmpfs, []string{"-tmpfs"}, "Mount a tmpfs directory")
 	cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
 	cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
@@ -343,23 +347,25 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 	}
 	}
 
 
 	resources := Resources{
 	resources := Resources{
-		CgroupParent:        *flCgroupParent,
-		Memory:              flMemory,
-		MemoryReservation:   MemoryReservation,
-		MemorySwap:          memorySwap,
-		MemorySwappiness:    flSwappiness,
-		KernelMemory:        KernelMemory,
-		CPUShares:           *flCPUShares,
-		CPUPeriod:           *flCPUPeriod,
-		CpusetCpus:          *flCpusetCpus,
-		CpusetMems:          *flCpusetMems,
-		CPUQuota:            *flCPUQuota,
-		BlkioWeight:         *flBlkioWeight,
-		BlkioWeightDevice:   flBlkioWeightDevice.GetList(),
-		BlkioDeviceReadBps:  flDeviceReadBps.GetList(),
-		BlkioDeviceWriteBps: flDeviceWriteBps.GetList(),
-		Ulimits:             flUlimits.GetList(),
-		Devices:             deviceMappings,
+		CgroupParent:         *flCgroupParent,
+		Memory:               flMemory,
+		MemoryReservation:    MemoryReservation,
+		MemorySwap:           memorySwap,
+		MemorySwappiness:     flSwappiness,
+		KernelMemory:         KernelMemory,
+		CPUShares:            *flCPUShares,
+		CPUPeriod:            *flCPUPeriod,
+		CpusetCpus:           *flCpusetCpus,
+		CpusetMems:           *flCpusetMems,
+		CPUQuota:             *flCPUQuota,
+		BlkioWeight:          *flBlkioWeight,
+		BlkioWeightDevice:    flBlkioWeightDevice.GetList(),
+		BlkioDeviceReadBps:   flDeviceReadBps.GetList(),
+		BlkioDeviceWriteBps:  flDeviceWriteBps.GetList(),
+		BlkioDeviceReadIOps:  flDeviceReadIOps.GetList(),
+		BlkioDeviceWriteIOps: flDeviceWriteIOps.GetList(),
+		Ulimits:              flUlimits.GetList(),
+		Devices:              deviceMappings,
 	}
 	}
 
 
 	config := &Config{
 	config := &Config{