Browse code

Implementing support for --cpu-rt-period and --cpu-rt-runtime so that containers may specify these cgroup values at runtime. This will allow processes to change their priority to real-time within the container when CONFIG_RT_GROUP_SCHED is enabled in the kernel. See #22380.

Also added sanity checks for the new --cpu-rt-runtime and --cpu-rt-period
flags to ensure that that the kernel supports these features and that
runtime is not greater than period.

Daemon will support a --cpu-rt-runtime flag to initialize the parent
cgroup on startup, this prevents the administrator from alotting runtime
to docker after each restart.

There are additional checks that could be added but maybe too far? Check
parent cgroups to ensure values are <= parent, inspecting rtprio ulimit
and issuing a warning.

Signed-off-by: Erik St. Martin <alakriti@gmail.com>

Erik St. Martin authored on 2016/06/08 04:05:43
Showing 25 changed files
... ...
@@ -243,8 +243,10 @@ type Resources struct {
243 243
 	BlkioDeviceWriteBps  []*blkiodev.ThrottleDevice
244 244
 	BlkioDeviceReadIOps  []*blkiodev.ThrottleDevice
245 245
 	BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice
246
-	CPUPeriod            int64           `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
247
-	CPUQuota             int64           `json:"CpuQuota"`  // CPU CFS (Completely Fair Scheduler) quota
246
+	CPUPeriod            int64           `json:"CpuPeriod"`          // CPU CFS (Completely Fair Scheduler) period
247
+	CPUQuota             int64           `json:"CpuQuota"`           // CPU CFS (Completely Fair Scheduler) quota
248
+	CPURealtimePeriod    int64           `json:"CpuRealtimePeriod"`  // CPU real-time period
249
+	CPURealtimeRuntime   int64           `json:"CpuRealtimeRuntime"` // CPU real-time runtime
248 250
 	CpusetCpus           string          // CpusetCpus 0-2, 0,1
249 251
 	CpusetMems           string          // CpusetMems 0-2, 0,1
250 252
 	Devices              []DeviceMapping // List of devices to map inside the container
... ...
@@ -15,17 +15,19 @@ import (
15 15
 )
16 16
 
17 17
 type updateOptions struct {
18
-	blkioWeight       uint16
19
-	cpuPeriod         int64
20
-	cpuQuota          int64
21
-	cpusetCpus        string
22
-	cpusetMems        string
23
-	cpuShares         int64
24
-	memoryString      string
25
-	memoryReservation string
26
-	memorySwap        string
27
-	kernelMemory      string
28
-	restartPolicy     string
18
+	blkioWeight        uint16
19
+	cpuPeriod          int64
20
+	cpuQuota           int64
21
+	cpuRealtimePeriod  int64
22
+	cpuRealtimeRuntime int64
23
+	cpusetCpus         string
24
+	cpusetMems         string
25
+	cpuShares          int64
26
+	memoryString       string
27
+	memoryReservation  string
28
+	memorySwap         string
29
+	kernelMemory       string
30
+	restartPolicy      string
29 31
 
30 32
 	nFlag int
31 33
 
... ...
@@ -51,6 +53,8 @@ func NewUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
51 51
 	flags.Uint16Var(&opts.blkioWeight, "blkio-weight", 0, "Block IO (relative weight), between 10 and 1000")
52 52
 	flags.Int64Var(&opts.cpuPeriod, "cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period")
53 53
 	flags.Int64Var(&opts.cpuQuota, "cpu-quota", 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
54
+	flags.Int64Var(&opts.cpuRealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds")
55
+	flags.Int64Var(&opts.cpuRealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds")
54 56
 	flags.StringVar(&opts.cpusetCpus, "cpuset-cpus", "", "CPUs in which to allow execution (0-3, 0,1)")
55 57
 	flags.StringVar(&opts.cpusetMems, "cpuset-mems", "", "MEMs in which to allow execution (0-3, 0,1)")
56 58
 	flags.Int64VarP(&opts.cpuShares, "cpu-shares", "c", 0, "CPU shares (relative weight)")
... ...
@@ -115,16 +119,18 @@ func runUpdate(dockerCli *command.DockerCli, opts *updateOptions) error {
115 115
 	}
116 116
 
117 117
 	resources := containertypes.Resources{
118
-		BlkioWeight:       opts.blkioWeight,
119
-		CpusetCpus:        opts.cpusetCpus,
120
-		CpusetMems:        opts.cpusetMems,
121
-		CPUShares:         opts.cpuShares,
122
-		Memory:            memory,
123
-		MemoryReservation: memoryReservation,
124
-		MemorySwap:        memorySwap,
125
-		KernelMemory:      kernelMemory,
126
-		CPUPeriod:         opts.cpuPeriod,
127
-		CPUQuota:          opts.cpuQuota,
118
+		BlkioWeight:        opts.blkioWeight,
119
+		CpusetCpus:         opts.cpusetCpus,
120
+		CpusetMems:         opts.cpusetMems,
121
+		CPUShares:          opts.cpuShares,
122
+		Memory:             memory,
123
+		MemoryReservation:  memoryReservation,
124
+		MemorySwap:         memorySwap,
125
+		KernelMemory:       kernelMemory,
126
+		CPUPeriod:          opts.cpuPeriod,
127
+		CPUQuota:           opts.cpuQuota,
128
+		CPURealtimePeriod:  opts.cpuRealtimePeriod,
129
+		CPURealtimeRuntime: opts.cpuRealtimeRuntime,
128 130
 	}
129 131
 
130 132
 	updateConfig := containertypes.UpdateConfig{
... ...
@@ -1316,6 +1316,8 @@ _docker_container_run() {
1316 1316
 		--cidfile
1317 1317
 		--cpu-period
1318 1318
 		--cpu-quota
1319
+		--cpu-rt-period
1320
+		--cpu-rt-runtime
1319 1321
 		--cpuset-cpus
1320 1322
 		--cpuset-mems
1321 1323
 		--cpu-shares -c
... ...
@@ -1667,6 +1669,8 @@ _docker_container_update() {
1667 1667
 		--blkio-weight
1668 1668
 		--cpu-period
1669 1669
 		--cpu-quota
1670
+		--cpu-rt-period
1671
+		--cpu-rt-runtime
1670 1672
 		--cpuset-cpus
1671 1673
 		--cpuset-mems
1672 1674
 		--cpu-shares -c
... ...
@@ -1433,6 +1433,8 @@ __docker_subcommand() {
1433 1433
         "($help -c --cpu-shares)"{-c=,--cpu-shares=}"[CPU shares (relative weight)]:CPU shares:(0 10 100 200 500 800 1000)"
1434 1434
         "($help)--cpu-period=[Limit the CPU CFS (Completely Fair Scheduler) period]:CPU period: "
1435 1435
         "($help)--cpu-quota=[Limit the CPU CFS (Completely Fair Scheduler) quota]:CPU quota: "
1436
+        "($help)--cpu-rt-period=[Limit the CPU real-time period]:CPU real-time period in microseconds: "
1437
+        "($help)--cpu-rt-runtime=[Limit the CPU real-time runtime]:CPU real-time runtime in microseconds: "
1436 1438
         "($help)--cpuset-cpus=[CPUs in which to allow execution]:CPUs: "
1437 1439
         "($help)--cpuset-mems=[MEMs in which to allow execution]:MEMs: "
1438 1440
         "($help -m --memory)"{-m=,--memory=}"[Memory limit]:Memory limit: "
... ...
@@ -34,6 +34,8 @@ type Config struct {
34 34
 	Ulimits              map[string]*units.Ulimit `json:"default-ulimits,omitempty"`
35 35
 	Runtimes             map[string]types.Runtime `json:"runtimes,omitempty"`
36 36
 	DefaultRuntime       string                   `json:"default-runtime,omitempty"`
37
+	CPURealtimePeriod    int64                    `json:"cpu-rt-period,omitempty"`
38
+	CPURealtimeRuntime   int64                    `json:"cpu-rt-runtime,omitempty"`
37 39
 	OOMScoreAdjust       int                      `json:"oom-score-adjust,omitempty"`
38 40
 	Init                 bool                     `json:"init,omitempty"`
39 41
 	InitPath             string                   `json:"init-path,omitempty"`
... ...
@@ -97,6 +99,8 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
97 97
 	flags.IntVar(&config.OOMScoreAdjust, "oom-score-adjust", -500, "Set the oom_score_adj for the daemon")
98 98
 	flags.BoolVar(&config.Init, "init", false, "Run an init in the container to forward signals and reap processes")
99 99
 	flags.StringVar(&config.InitPath, "init-path", "", "Path to the docker-init binary")
100
+	flags.Int64Var(&config.CPURealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds")
101
+	flags.Int64Var(&config.CPURealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds")
100 102
 
101 103
 	config.attachExperimentalFlags(flags)
102 104
 }
... ...
@@ -36,10 +36,11 @@ import (
36 36
 	"github.com/docker/libnetwork/options"
37 37
 	lntypes "github.com/docker/libnetwork/types"
38 38
 	"github.com/golang/protobuf/ptypes"
39
+	"github.com/opencontainers/runc/libcontainer/cgroups"
39 40
 	"github.com/opencontainers/runc/libcontainer/label"
40 41
 	rsystem "github.com/opencontainers/runc/libcontainer/system"
41 42
 	"github.com/opencontainers/runc/libcontainer/user"
42
-	"github.com/opencontainers/runtime-spec/specs-go"
43
+	specs "github.com/opencontainers/runtime-spec/specs-go"
43 44
 	"github.com/vishvananda/netlink"
44 45
 )
45 46
 
... ...
@@ -118,6 +119,16 @@ func getCPUResources(config containertypes.Resources) *specs.CPU {
118 118
 		cpu.Quota = &quota
119 119
 	}
120 120
 
121
+	if config.CPURealtimePeriod != 0 {
122
+		period := uint64(config.CPURealtimePeriod)
123
+		cpu.RealtimePeriod = &period
124
+	}
125
+
126
+	if config.CPURealtimeRuntime != 0 {
127
+		runtime := uint64(config.CPURealtimeRuntime)
128
+		cpu.RealtimeRuntime = &runtime
129
+	}
130
+
121 131
 	return &cpu
122 132
 }
123 133
 
... ...
@@ -1184,3 +1195,34 @@ func setupOOMScoreAdj(score int) error {
1184 1184
 	f.Close()
1185 1185
 	return err
1186 1186
 }
1187
+
1188
+func (daemon *Daemon) initCgroupsPath(path string) error {
1189
+	if path == "/" || path == "." {
1190
+		return nil
1191
+	}
1192
+
1193
+	daemon.initCgroupsPath(filepath.Dir(path))
1194
+
1195
+	_, root, err := cgroups.FindCgroupMountpointAndRoot("cpu")
1196
+	if err != nil {
1197
+		return err
1198
+	}
1199
+
1200
+	path = filepath.Join(root, path)
1201
+	sysinfo := sysinfo.New(false)
1202
+	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
1203
+		return err
1204
+	}
1205
+	if sysinfo.CPURealtimePeriod && daemon.configStore.CPURealtimePeriod != 0 {
1206
+		if err := ioutil.WriteFile(filepath.Join(path, "cpu.rt_period_us"), []byte(strconv.FormatInt(daemon.configStore.CPURealtimePeriod, 10)), 0700); err != nil {
1207
+			return err
1208
+		}
1209
+	}
1210
+	if sysinfo.CPURealtimeRuntime && daemon.configStore.CPURealtimeRuntime != 0 {
1211
+		if err := ioutil.WriteFile(filepath.Join(path, "cpu.rt_runtime_us"), []byte(strconv.FormatInt(daemon.configStore.CPURealtimeRuntime, 10)), 0700); err != nil {
1212
+			return err
1213
+		}
1214
+	}
1215
+
1216
+	return nil
1217
+}
... ...
@@ -21,9 +21,10 @@ import (
21 21
 	"github.com/docker/docker/pkg/symlink"
22 22
 	"github.com/docker/docker/volume"
23 23
 	"github.com/opencontainers/runc/libcontainer/apparmor"
24
+	"github.com/opencontainers/runc/libcontainer/cgroups"
24 25
 	"github.com/opencontainers/runc/libcontainer/devices"
25 26
 	"github.com/opencontainers/runc/libcontainer/user"
26
-	"github.com/opencontainers/runtime-spec/specs-go"
27
+	specs "github.com/opencontainers/runtime-spec/specs-go"
27 28
 )
28 29
 
29 30
 func setResources(s *specs.Spec, r containertypes.Resources) error {
... ...
@@ -655,6 +656,29 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
655 655
 	}
656 656
 	s.Linux.Resources.OOMScoreAdj = &c.HostConfig.OomScoreAdj
657 657
 	s.Linux.Sysctl = c.HostConfig.Sysctls
658
+
659
+	p := *s.Linux.CgroupsPath
660
+	if useSystemd {
661
+		initPath, err := cgroups.GetInitCgroupDir("cpu")
662
+		if err != nil {
663
+			return nil, err
664
+		}
665
+		p, _ = cgroups.GetThisCgroupDir("cpu")
666
+		if err != nil {
667
+			return nil, err
668
+		}
669
+		p = filepath.Join(initPath, p)
670
+	}
671
+
672
+	// Clean path to guard against things like ../../../BAD
673
+	parentPath := filepath.Dir(p)
674
+	if !filepath.IsAbs(parentPath) {
675
+		parentPath = filepath.Clean("/" + parentPath)
676
+	}
677
+
678
+	if err := daemon.initCgroupsPath(parentPath); err != nil {
679
+		return nil, fmt.Errorf("linux init cgroups path: %v", err)
680
+	}
658 681
 	if err := setDevices(&s, c); err != nil {
659 682
 		return nil, fmt.Errorf("linux runtime spec devices: %v", err)
660 683
 	}
... ...
@@ -160,6 +160,7 @@ This section lists each version from latest to oldest.  Each listing includes a
160 160
 * `POST /volumes/prune` prunes unused volumes.
161 161
 * `POST /networks/prune` prunes unused networks.
162 162
 * Every API response now includes a `Docker-Experimental` header specifying if experimental features are enabled (value can be `true` or `false`).
163
+* The `hostConfig` option now accepts the fields `CpuRealtimePeriod` and `CpuRtRuntime` to allocate cpu runtime to rt tasks when `CONFIG_RT_GROUP_SCHED` is enabled in the kernel.
163 164
 
164 165
 
165 166
 ### v1.24 API changes
... ...
@@ -304,6 +304,8 @@ Create a container
304 304
              "CpuPercent": 80,
305 305
              "CpuShares": 512,
306 306
              "CpuPeriod": 100000,
307
+             "CpuRealtimePeriod": 1000000,
308
+             "CpuRealtimeRuntime": 10000,
307 309
              "CpuQuota": 50000,
308 310
              "CpusetCpus": "0,1",
309 311
              "CpusetMems": "0,1",
... ...
@@ -426,6 +428,8 @@ Create a container
426 426
     -   **CpuShares** - An integer value containing the container's CPU Shares
427 427
           (ie. the relative weight vs other containers).
428 428
     -   **CpuPeriod** - The length of a CPU period in microseconds.
429
+    -   **CpuRealtimePeriod** - The length of a CPU real-time period in microseconds (0=no time allocated for rt tasks)
430
+    -   **CpuRealtimeRuntime** - The length of a CPU real-time runtime in microseconds (0=no time allocated for rt tasks)
429 431
     -   **CpuQuota** - Microseconds of CPU time that the container can get in a CPU period.
430 432
     -   **CpusetCpus** - String value containing the `cgroups CpusetCpus` to use.
431 433
     -   **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
... ...
@@ -615,6 +619,8 @@ Return low-level information on the container `id`
615 615
 			"CpuPercent": 80,
616 616
 			"CpuShares": 0,
617 617
 			"CpuPeriod": 100000,
618
+			"CpuRealtimePeriod": 1000000,
619
+			"CpuRealtimeRuntime": 10000,
618 620
 			"Devices": [],
619 621
 			"Dns": null,
620 622
 			"DnsOptions": null,
... ...
@@ -1191,6 +1197,8 @@ Update configuration of one or more containers.
1191 1191
          "BlkioWeight": 300,
1192 1192
          "CpuShares": 512,
1193 1193
          "CpuPeriod": 100000,
1194
+         "CpuRealtimePeriod": 1000000,
1195
+         "CpuRealtimeRuntime": 10000,
1194 1196
          "CpuQuota": 50000,
1195 1197
          "CpusetCpus": "0,1",
1196 1198
          "CpusetMems": "0",
... ...
@@ -35,6 +35,8 @@ Options:
35 35
       --cpu-period int              Limit CPU CFS (Completely Fair Scheduler) period
36 36
       --cpu-quota int               Limit CPU CFS (Completely Fair Scheduler) quota
37 37
   -c, --cpu-shares int              CPU shares (relative weight)
38
+      --cpu-rt-period int           Limit the CPU real-time period in microseconds
39
+      --cpu-rt-runtime int          Limit the CPU real-time runtime in microseconds
38 40
       --cpuset-cpus string          CPUs in which to allow execution (0-3, 0,1)
39 41
       --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
40 42
       --device value                Add a host device to the container (default [])
... ...
@@ -33,6 +33,8 @@ Options:
33 33
       --cpu-period int              Limit CPU CFS (Completely Fair Scheduler) period
34 34
       --cpu-quota int               Limit CPU CFS (Completely Fair Scheduler) quota
35 35
   -c, --cpu-shares int              CPU shares (relative weight)
36
+      --cpu-rt-period int           Limit the CPU real-time period in microseconds
37
+      --cpu-rt-runtime int          Limit the CPU real-time runtime in microseconds
36 38
       --cpuset-cpus string          CPUs in which to allow execution (0-3, 0,1)
37 39
       --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
38 40
   -d, --detach                      Run container in background and print container ID
... ...
@@ -25,6 +25,8 @@ Options:
25 25
       --cpu-period int              Limit CPU CFS (Completely Fair Scheduler) period
26 26
       --cpu-quota int               Limit CPU CFS (Completely Fair Scheduler) quota
27 27
   -c, --cpu-shares int              CPU shares (relative weight)
28
+      --cpu-rt-period int           Limit the CPU real-time period in microseconds
29
+      --cpu-rt-runtime int          Limit the CPU real-time runtime in microseconds
28 30
       --cpuset-cpus string          CPUs in which to allow execution (0-3, 0,1)
29 31
       --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
30 32
       --help                        Print usage
... ...
@@ -690,6 +690,8 @@ container:
690 690
 | `--cpuset-cpus=""`         | CPUs in which to allow execution (0-3, 0,1)                                                                                                     |
691 691
 | `--cpuset-mems=""`         | Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.                                                     |
692 692
 | `--cpu-quota=0`            | Limit the CPU CFS (Completely Fair Scheduler) quota                                                                                             |
693
+| `--cpu-rt-period=0`        | Limit the CPU real-time period. In microseconds. Requires parent cgroups be set and cannot be higher than parent. Also check rtprio ulimits.    |
694
+| `--cpu-rt-runtime=0`       | Limit the CPU real-time runtime. In microseconds. Requires parent cgroups be set and cannot be higher than parent. Also check rtprio ulimits.   |
693 695
 | `--blkio-weight=0`         | Block IO weight (relative weight) accepts a weight value between 10 and 1000.                                                                   |
694 696
 | `--blkio-weight-device=""` | Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)                                                                          |
695 697
 | `--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`. |
... ...
@@ -17,6 +17,8 @@ docker-create - Create a new container
17 17
 [**--cidfile**[=*CIDFILE*]]
18 18
 [**--cpu-period**[=*0*]]
19 19
 [**--cpu-quota**[=*0*]]
20
+[**--cpu-rt-period**[=*0*]]
21
+[**--cpu-rt-runtime**[=*0*]]
20 22
 [**--cpuset-cpus**[=*CPUSET-CPUS*]]
21 23
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
22 24
 [**--device**[=*[]*]]
... ...
@@ -123,6 +125,8 @@ The initial status of the container created with **docker create** is 'created'.
123 123
 **--cpu-period**=*0*
124 124
     Limit the CPU CFS (Completely Fair Scheduler) period
125 125
 
126
+    Limit the container's CPU usage. This flag tell the kernel to restrict the container's CPU usage to the period you specify.
127
+
126 128
 **--cpuset-cpus**=""
127 129
    CPUs in which to allow execution (0-3, 0,1)
128 130
 
... ...
@@ -136,6 +140,19 @@ two memory nodes.
136 136
 **--cpu-quota**=*0*
137 137
    Limit the CPU CFS (Completely Fair Scheduler) quota
138 138
 
139
+**--cpu-rt-period**=0
140
+   Limit the CPU real-time period in microseconds
141
+
142
+   Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify.
143
+
144
+**--cpu-rt-runtime**=0
145
+   Limit the CPU real-time runtime in microseconds
146
+
147
+   Limit the containers Real Time CPU usage. This flag tells the kernel to limit the amount of time in a given CPU period Real Time tasks may consume. Ex:
148
+   Period of 1,000,000us and Runtime of 950,000us means that this container could consume 95% of available CPU and leave the remaining 5% to normal priority tasks.
149
+
150
+   The sum of all runtimes across containers cannot exceed the amount alotted to the parent cgroup.
151
+
139 152
 **--device**=[]
140 153
    Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)
141 154
 
... ...
@@ -17,6 +17,8 @@ docker-run - Run a command in a new container
17 17
 [**--cidfile**[=*CIDFILE*]]
18 18
 [**--cpu-period**[=*0*]]
19 19
 [**--cpu-quota**[=*0*]]
20
+[**--cpu-rt-period**[=*0*]]
21
+[**--cpu-rt-runtime**[=*0*]]
20 22
 [**--cpuset-cpus**[=*CPUSET-CPUS*]]
21 23
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
22 24
 [**-d**|**--detach**]
... ...
@@ -192,6 +194,19 @@ two memory nodes.
192 192
 CPU resource. This flag tell the kernel to restrict the container's CPU usage
193 193
 to the quota you specify.
194 194
 
195
+**--cpu-rt-period**=0
196
+   Limit the CPU real-time period in microseconds
197
+
198
+   Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify.
199
+
200
+**--cpu-rt-runtime**=0
201
+   Limit the CPU real-time runtime in microseconds
202
+
203
+   Limit the containers Real Time CPU usage. This flag tells the kernel to limit the amount of time in a given CPU period Real Time tasks may consume. Ex:
204
+   Period of 1,000,000us and Runtime of 950,000us means that this container could consume 95% of available CPU and leave the remaining 5% to normal priority tasks.
205
+
206
+   The sum of all runtimes across containers cannot exceed the amount alotted to the parent cgroup.
207
+
195 208
 **-d**, **--detach**=*true*|*false*
196 209
    Detached mode: run the container in the background and print the new container ID. The default is *false*.
197 210
 
... ...
@@ -10,6 +10,8 @@ docker-update - Update configuration of one or more containers
10 10
 [**--cpu-shares**[=*0*]]
11 11
 [**--cpu-period**[=*0*]]
12 12
 [**--cpu-quota**[=*0*]]
13
+[**--cpu-rt-period**[=*0*]]
14
+[**--cpu-rt-runtime**[=*0*]]
13 15
 [**--cpuset-cpus**[=*CPUSET-CPUS*]]
14 16
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
15 17
 [**--help**]
... ...
@@ -44,9 +46,24 @@ a running container with kernel memory initialized.
44 44
 **--cpu-period**=0
45 45
    Limit the CPU CFS (Completely Fair Scheduler) period
46 46
 
47
+   Limit the container's CPU usage. This flag tell the kernel to restrict the container's CPU usage to the period you specify.
48
+
47 49
 **--cpu-quota**=0
48 50
    Limit the CPU CFS (Completely Fair Scheduler) quota
49 51
 
52
+**--cpu-rt-period**=0
53
+   Limit the CPU real-time period in microseconds
54
+
55
+   Limit the container's Real Time CPU usage. This flag tell the kernel to restrict the container's Real Time CPU usage to the period you specify.
56
+
57
+**--cpu-rt-runtime**=0
58
+   Limit the CPU real-time runtime in microseconds
59
+
60
+   Limit the containers Real Time CPU usage. This flag tells the kernel to limit the amount of time in a given CPU period Real Time tasks may consume. Ex:
61
+   Period of 1,000,000us and Runtime of 950,000us means that this container could consume 95% of available CPU and leave the remaining 5% to normal priority tasks.
62
+
63
+   The sum of all runtimes across containers cannot exceed the amount alotted to the parent cgroup.
64
+
50 65
 **--cpuset-cpus**=""
51 66
    CPUs in which to allow execution (0-3, 0,1)
52 67
 
... ...
@@ -58,6 +58,12 @@ type cgroupCPUInfo struct {
58 58
 
59 59
 	// Whether CPU CFS(Completely Fair Scheduler) quota is supported or not
60 60
 	CPUCfsQuota bool
61
+
62
+	// Whether CPU real-time period is supported or not
63
+	CPURealtimePeriod bool
64
+
65
+	// Whether CPU real-time runtime is supported or not
66
+	CPURealtimeRuntime bool
61 67
 }
62 68
 
63 69
 type cgroupBlkioInfo struct {
... ...
@@ -135,10 +135,23 @@ func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
135 135
 	if !quiet && !cpuCfsQuota {
136 136
 		logrus.Warn("Your kernel does not support cgroup cfs quotas")
137 137
 	}
138
+
139
+	cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us")
140
+	if !quiet && !cpuRealtimePeriod {
141
+		logrus.Warn("Your kernel does not support cgroup rt period")
142
+	}
143
+
144
+	cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
145
+	if !quiet && !cpuRealtimeRuntime {
146
+		logrus.Warn("Your kernel does not support cgroup rt runtime")
147
+	}
148
+
138 149
 	return cgroupCPUInfo{
139
-		CPUShares:    cpuShares,
140
-		CPUCfsPeriod: cpuCfsPeriod,
141
-		CPUCfsQuota:  cpuCfsQuota,
150
+		CPUShares:          cpuShares,
151
+		CPUCfsPeriod:       cpuCfsPeriod,
152
+		CPUCfsQuota:        cpuCfsQuota,
153
+		CPURealtimePeriod:  cpuRealtimePeriod,
154
+		CPURealtimeRuntime: cpuRealtimeRuntime,
142 155
 	}
143 156
 }
144 157
 
... ...
@@ -77,9 +77,11 @@ func setCgroupMem(quiet bool) cgroupMemInfo {
77 77
 func setCgroupCPU(quiet bool) cgroupCPUInfo {
78 78
 
79 79
 	return cgroupCPUInfo{
80
-		CPUShares:    true,
81
-		CPUCfsPeriod: false,
82
-		CPUCfsQuota:  true,
80
+		CPUShares:          true,
81
+		CPUCfsPeriod:       false,
82
+		CPUCfsQuota:        true,
83
+		CPURealtimePeriod:  false,
84
+		CPURealtimeRuntime: false,
83 85
 	}
84 86
 }
85 87
 
... ...
@@ -7,6 +7,7 @@ import (
7 7
 
8 8
 	"github.com/docker/docker/api/types/container"
9 9
 	networktypes "github.com/docker/docker/api/types/network"
10
+	"github.com/docker/docker/pkg/sysinfo"
10 11
 	"github.com/docker/docker/volume"
11 12
 )
12 13
 
... ...
@@ -68,6 +69,10 @@ func DecodeContainerConfig(src io.Reader) (*container.Config, *container.HostCon
68 68
 		return nil, nil, nil, err
69 69
 	}
70 70
 
71
+	// Validate Resources
72
+	if err := ValidateResources(hc, sysinfo.New(true)); err != nil {
73
+		return nil, nil, nil, err
74
+	}
71 75
 	return w.Config, hc, w.NetworkingConfig, nil
72 76
 }
73 77
 
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"strings"
6 6
 
7 7
 	"github.com/docker/docker/api/types/container"
8
+	"github.com/docker/docker/pkg/sysinfo"
8 9
 )
9 10
 
10 11
 // DefaultDaemonNetworkMode returns the default network stack the daemon should
... ...
@@ -45,3 +46,8 @@ func ValidateIsolation(hc *container.HostConfig) error {
45 45
 func ValidateQoS(hc *container.HostConfig) error {
46 46
 	return nil
47 47
 }
48
+
49
+// ValidateResources performs platform specific validation of the resource settings
50
+func ValidateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
51
+	return nil
52
+}
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"testing"
10 10
 
11 11
 	"github.com/docker/docker/api/types/container"
12
+	"github.com/docker/docker/pkg/sysinfo"
12 13
 )
13 14
 
14 15
 // TODO Windows: This will need addressing for a Windows daemon.
... ...
@@ -220,3 +221,63 @@ func TestDecodeHostConfig(t *testing.T) {
220 220
 		}
221 221
 	}
222 222
 }
223
+
224
+func TestValidateResources(t *testing.T) {
225
+	type resourceTest struct {
226
+		ConfigCPURealtimePeriod   int64
227
+		ConfigCPURealtimeRuntime  int64
228
+		SysInfoCPURealtimePeriod  bool
229
+		SysInfoCPURealtimeRuntime bool
230
+		ErrorExpected             bool
231
+		FailureMsg                string
232
+	}
233
+
234
+	tests := []resourceTest{
235
+		{
236
+			ConfigCPURealtimePeriod:   1000,
237
+			ConfigCPURealtimeRuntime:  1000,
238
+			SysInfoCPURealtimePeriod:  true,
239
+			SysInfoCPURealtimeRuntime: true,
240
+			ErrorExpected:             false,
241
+			FailureMsg:                "Expected valid configuration",
242
+		},
243
+		{
244
+			ConfigCPURealtimePeriod:   5000,
245
+			ConfigCPURealtimeRuntime:  5000,
246
+			SysInfoCPURealtimePeriod:  false,
247
+			SysInfoCPURealtimeRuntime: true,
248
+			ErrorExpected:             true,
249
+			FailureMsg:                "Expected failure when cpu-rt-period is set but kernel doesn't support it",
250
+		},
251
+		{
252
+			ConfigCPURealtimePeriod:   5000,
253
+			ConfigCPURealtimeRuntime:  5000,
254
+			SysInfoCPURealtimePeriod:  true,
255
+			SysInfoCPURealtimeRuntime: false,
256
+			ErrorExpected:             true,
257
+			FailureMsg:                "Expected failure when cpu-rt-runtime is set but kernel doesn't support it",
258
+		},
259
+		{
260
+			ConfigCPURealtimePeriod:   5000,
261
+			ConfigCPURealtimeRuntime:  10000,
262
+			SysInfoCPURealtimePeriod:  true,
263
+			SysInfoCPURealtimeRuntime: false,
264
+			ErrorExpected:             true,
265
+			FailureMsg:                "Expected failure when cpu-rt-runtime is greater than cpu-rt-period",
266
+		},
267
+	}
268
+
269
+	for _, rt := range tests {
270
+		var hc container.HostConfig
271
+		hc.Resources.CPURealtimePeriod = rt.ConfigCPURealtimePeriod
272
+		hc.Resources.CPURealtimeRuntime = rt.ConfigCPURealtimeRuntime
273
+
274
+		var si sysinfo.SysInfo
275
+		si.CPURealtimePeriod = rt.SysInfoCPURealtimePeriod
276
+		si.CPURealtimeRuntime = rt.SysInfoCPURealtimeRuntime
277
+
278
+		if err := ValidateResources(&hc, &si); (err != nil) != rt.ErrorExpected {
279
+			t.Fatal(rt.FailureMsg, err)
280
+		}
281
+	}
282
+}
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"strings"
9 9
 
10 10
 	"github.com/docker/docker/api/types/container"
11
+	"github.com/docker/docker/pkg/sysinfo"
11 12
 )
12 13
 
13 14
 // DefaultDaemonNetworkMode returns the default network stack the daemon should
... ...
@@ -104,3 +105,25 @@ func ValidateQoS(hc *container.HostConfig) error {
104 104
 	}
105 105
 	return nil
106 106
 }
107
+
108
+// ValidateResources performs platform specific validation of the resource settings
109
+// cpu-rt-runtime and cpu-rt-period can not be greater than their parent, cpu-rt-runtime requires sys_nice
110
+func ValidateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
111
+	// We may not be passed a host config, such as in the case of docker commit
112
+	if hc == nil {
113
+		return nil
114
+	}
115
+
116
+	if hc.Resources.CPURealtimePeriod > 0 && !si.CPURealtimePeriod {
117
+		return fmt.Errorf("invalid --cpu-rt-period: Your kernel does not support cgroup rt period")
118
+	}
119
+
120
+	if hc.Resources.CPURealtimeRuntime > 0 && !si.CPURealtimeRuntime {
121
+		return fmt.Errorf("invalid --cpu-rt-runtime: Your kernel does not support cgroup rt runtime")
122
+	}
123
+
124
+	if hc.Resources.CPURealtimePeriod != 0 && hc.Resources.CPURealtimeRuntime != 0 && hc.Resources.CPURealtimeRuntime > hc.Resources.CPURealtimePeriod {
125
+		return fmt.Errorf("invalid --cpu-rt-runtime: rt runtime cannot be higher than rt period")
126
+	}
127
+	return nil
128
+}
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"strings"
6 6
 
7 7
 	"github.com/docker/docker/api/types/container"
8
+	"github.com/docker/docker/pkg/sysinfo"
8 9
 )
9 10
 
10 11
 // DefaultDaemonNetworkMode returns the default network stack the daemon should
... ...
@@ -49,3 +50,19 @@ func ValidateIsolation(hc *container.HostConfig) error {
49 49
 func ValidateQoS(hc *container.HostConfig) error {
50 50
 	return nil
51 51
 }
52
+
53
+// ValidateResources performs platform specific validation of the resource settings
54
+func ValidateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
55
+	// We may not be passed a host config, such as in the case of docker commit
56
+	if hc == nil {
57
+		return nil
58
+	}
59
+
60
+	if hc.Resources.CPURealtimePeriod != 0 {
61
+		return fmt.Errorf("invalid --cpu-rt-period: Windows does not support this feature")
62
+	}
63
+	if hc.Resources.CPURealtimeRuntime != 0 {
64
+		return fmt.Errorf("invalid --cpu-rt-runtime: Windows does not support this feature")
65
+	}
66
+	return nil
67
+}
... ...
@@ -23,90 +23,92 @@ import (
23 23
 
24 24
 // ContainerOptions is a data object with all the options for creating a container
25 25
 type ContainerOptions struct {
26
-	attach            opts.ListOpts
27
-	volumes           opts.ListOpts
28
-	tmpfs             opts.ListOpts
29
-	blkioWeightDevice WeightdeviceOpt
30
-	deviceReadBps     ThrottledeviceOpt
31
-	deviceWriteBps    ThrottledeviceOpt
32
-	links             opts.ListOpts
33
-	aliases           opts.ListOpts
34
-	linkLocalIPs      opts.ListOpts
35
-	deviceReadIOps    ThrottledeviceOpt
36
-	deviceWriteIOps   ThrottledeviceOpt
37
-	env               opts.ListOpts
38
-	labels            opts.ListOpts
39
-	devices           opts.ListOpts
40
-	ulimits           *UlimitOpt
41
-	sysctls           *opts.MapOpts
42
-	publish           opts.ListOpts
43
-	expose            opts.ListOpts
44
-	dns               opts.ListOpts
45
-	dnsSearch         opts.ListOpts
46
-	dnsOptions        opts.ListOpts
47
-	extraHosts        opts.ListOpts
48
-	volumesFrom       opts.ListOpts
49
-	envFile           opts.ListOpts
50
-	capAdd            opts.ListOpts
51
-	capDrop           opts.ListOpts
52
-	groupAdd          opts.ListOpts
53
-	securityOpt       opts.ListOpts
54
-	storageOpt        opts.ListOpts
55
-	labelsFile        opts.ListOpts
56
-	loggingOpts       opts.ListOpts
57
-	privileged        bool
58
-	pidMode           string
59
-	utsMode           string
60
-	usernsMode        string
61
-	publishAll        bool
62
-	stdin             bool
63
-	tty               bool
64
-	oomKillDisable    bool
65
-	oomScoreAdj       int
66
-	containerIDFile   string
67
-	entrypoint        string
68
-	hostname          string
69
-	memoryString      string
70
-	memoryReservation string
71
-	memorySwap        string
72
-	kernelMemory      string
73
-	user              string
74
-	workingDir        string
75
-	cpuShares         int64
76
-	cpuPercent        int64
77
-	cpuPeriod         int64
78
-	cpuQuota          int64
79
-	cpusetCpus        string
80
-	cpusetMems        string
81
-	blkioWeight       uint16
82
-	ioMaxBandwidth    string
83
-	ioMaxIOps         uint64
84
-	swappiness        int64
85
-	netMode           string
86
-	macAddress        string
87
-	ipv4Address       string
88
-	ipv6Address       string
89
-	ipcMode           string
90
-	pidsLimit         int64
91
-	restartPolicy     string
92
-	readonlyRootfs    bool
93
-	loggingDriver     string
94
-	cgroupParent      string
95
-	volumeDriver      string
96
-	stopSignal        string
97
-	stopTimeout       int
98
-	isolation         string
99
-	shmSize           string
100
-	noHealthcheck     bool
101
-	healthCmd         string
102
-	healthInterval    time.Duration
103
-	healthTimeout     time.Duration
104
-	healthRetries     int
105
-	runtime           string
106
-	autoRemove        bool
107
-	init              bool
108
-	initPath          string
109
-	credentialSpec    string
26
+	attach             opts.ListOpts
27
+	volumes            opts.ListOpts
28
+	tmpfs              opts.ListOpts
29
+	blkioWeightDevice  WeightdeviceOpt
30
+	deviceReadBps      ThrottledeviceOpt
31
+	deviceWriteBps     ThrottledeviceOpt
32
+	links              opts.ListOpts
33
+	aliases            opts.ListOpts
34
+	linkLocalIPs       opts.ListOpts
35
+	deviceReadIOps     ThrottledeviceOpt
36
+	deviceWriteIOps    ThrottledeviceOpt
37
+	env                opts.ListOpts
38
+	labels             opts.ListOpts
39
+	devices            opts.ListOpts
40
+	ulimits            *UlimitOpt
41
+	sysctls            *opts.MapOpts
42
+	publish            opts.ListOpts
43
+	expose             opts.ListOpts
44
+	dns                opts.ListOpts
45
+	dnsSearch          opts.ListOpts
46
+	dnsOptions         opts.ListOpts
47
+	extraHosts         opts.ListOpts
48
+	volumesFrom        opts.ListOpts
49
+	envFile            opts.ListOpts
50
+	capAdd             opts.ListOpts
51
+	capDrop            opts.ListOpts
52
+	groupAdd           opts.ListOpts
53
+	securityOpt        opts.ListOpts
54
+	storageOpt         opts.ListOpts
55
+	labelsFile         opts.ListOpts
56
+	loggingOpts        opts.ListOpts
57
+	privileged         bool
58
+	pidMode            string
59
+	utsMode            string
60
+	usernsMode         string
61
+	publishAll         bool
62
+	stdin              bool
63
+	tty                bool
64
+	oomKillDisable     bool
65
+	oomScoreAdj        int
66
+	containerIDFile    string
67
+	entrypoint         string
68
+	hostname           string
69
+	memoryString       string
70
+	memoryReservation  string
71
+	memorySwap         string
72
+	kernelMemory       string
73
+	user               string
74
+	workingDir         string
75
+	cpuShares          int64
76
+	cpuPercent         int64
77
+	cpuPeriod          int64
78
+	cpuRealtimePeriod  int64
79
+	cpuRealtimeRuntime int64
80
+	cpuQuota           int64
81
+	cpusetCpus         string
82
+	cpusetMems         string
83
+	blkioWeight        uint16
84
+	ioMaxBandwidth     string
85
+	ioMaxIOps          uint64
86
+	swappiness         int64
87
+	netMode            string
88
+	macAddress         string
89
+	ipv4Address        string
90
+	ipv6Address        string
91
+	ipcMode            string
92
+	pidsLimit          int64
93
+	restartPolicy      string
94
+	readonlyRootfs     bool
95
+	loggingDriver      string
96
+	cgroupParent       string
97
+	volumeDriver       string
98
+	stopSignal         string
99
+	stopTimeout        int
100
+	isolation          string
101
+	shmSize            string
102
+	noHealthcheck      bool
103
+	healthCmd          string
104
+	healthInterval     time.Duration
105
+	healthTimeout      time.Duration
106
+	healthRetries      int
107
+	runtime            string
108
+	autoRemove         bool
109
+	init               bool
110
+	initPath           string
111
+	credentialSpec     string
110 112
 
111 113
 	Image string
112 114
 	Args  []string
... ...
@@ -225,6 +227,8 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions {
225 225
 	flags.Int64Var(&copts.cpuPercent, "cpu-percent", 0, "CPU percent (Windows only)")
226 226
 	flags.Int64Var(&copts.cpuPeriod, "cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period")
227 227
 	flags.Int64Var(&copts.cpuQuota, "cpu-quota", 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
228
+	flags.Int64Var(&copts.cpuRealtimePeriod, "cpu-rt-period", 0, "Limit CPU real-time period in microseconds")
229
+	flags.Int64Var(&copts.cpuRealtimeRuntime, "cpu-rt-runtime", 0, "Limit CPU real-time runtime in microseconds")
228 230
 	flags.Int64VarP(&copts.cpuShares, "cpu-shares", "c", 0, "CPU shares (relative weight)")
229 231
 	flags.Var(&copts.deviceReadBps, "device-read-bps", "Limit read rate (bytes per second) from a device")
230 232
 	flags.Var(&copts.deviceReadIOps, "device-read-iops", "Limit read rate (IO per second) from a device")
... ...
@@ -521,6 +525,8 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c
521 521
 		CpusetCpus:           copts.cpusetCpus,
522 522
 		CpusetMems:           copts.cpusetMems,
523 523
 		CPUQuota:             copts.cpuQuota,
524
+		CPURealtimePeriod:    copts.cpuRealtimePeriod,
525
+		CPURealtimeRuntime:   copts.cpuRealtimeRuntime,
524 526
 		PidsLimit:            copts.pidsLimit,
525 527
 		BlkioWeight:          copts.blkioWeight,
526 528
 		BlkioWeightDevice:    copts.blkioWeightDevice.GetList(),