Forráskód Böngészése

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 9 éve
szülő
commit
56f77d5ade

+ 4 - 2
api/types/container/host_config.go

@@ -243,8 +243,10 @@ type Resources struct {
 	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
+	CPUPeriod            int64           `json:"CpuPeriod"`          // CPU CFS (Completely Fair Scheduler) period
+	CPUQuota             int64           `json:"CpuQuota"`           // CPU CFS (Completely Fair Scheduler) quota
+	CPURealtimePeriod    int64           `json:"CpuRealtimePeriod"`  // CPU real-time period
+	CPURealtimeRuntime   int64           `json:"CpuRealtimeRuntime"` // CPU real-time runtime
 	CpusetCpus           string          // CpusetCpus 0-2, 0,1
 	CpusetMems           string          // CpusetMems 0-2, 0,1
 	Devices              []DeviceMapping // List of devices to map inside the container

+ 27 - 21
cli/command/container/update.go

@@ -15,17 +15,19 @@ import (
 )
 
 type updateOptions struct {
-	blkioWeight       uint16
-	cpuPeriod         int64
-	cpuQuota          int64
-	cpusetCpus        string
-	cpusetMems        string
-	cpuShares         int64
-	memoryString      string
-	memoryReservation string
-	memorySwap        string
-	kernelMemory      string
-	restartPolicy     string
+	blkioWeight        uint16
+	cpuPeriod          int64
+	cpuQuota           int64
+	cpuRealtimePeriod  int64
+	cpuRealtimeRuntime int64
+	cpusetCpus         string
+	cpusetMems         string
+	cpuShares          int64
+	memoryString       string
+	memoryReservation  string
+	memorySwap         string
+	kernelMemory       string
+	restartPolicy      string
 
 	nFlag int
 
@@ -51,6 +53,8 @@ func NewUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
 	flags.Uint16Var(&opts.blkioWeight, "blkio-weight", 0, "Block IO (relative weight), between 10 and 1000")
 	flags.Int64Var(&opts.cpuPeriod, "cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period")
 	flags.Int64Var(&opts.cpuQuota, "cpu-quota", 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
+	flags.Int64Var(&opts.cpuRealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds")
+	flags.Int64Var(&opts.cpuRealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds")
 	flags.StringVar(&opts.cpusetCpus, "cpuset-cpus", "", "CPUs in which to allow execution (0-3, 0,1)")
 	flags.StringVar(&opts.cpusetMems, "cpuset-mems", "", "MEMs in which to allow execution (0-3, 0,1)")
 	flags.Int64VarP(&opts.cpuShares, "cpu-shares", "c", 0, "CPU shares (relative weight)")
@@ -115,16 +119,18 @@ func runUpdate(dockerCli *command.DockerCli, opts *updateOptions) error {
 	}
 
 	resources := containertypes.Resources{
-		BlkioWeight:       opts.blkioWeight,
-		CpusetCpus:        opts.cpusetCpus,
-		CpusetMems:        opts.cpusetMems,
-		CPUShares:         opts.cpuShares,
-		Memory:            memory,
-		MemoryReservation: memoryReservation,
-		MemorySwap:        memorySwap,
-		KernelMemory:      kernelMemory,
-		CPUPeriod:         opts.cpuPeriod,
-		CPUQuota:          opts.cpuQuota,
+		BlkioWeight:        opts.blkioWeight,
+		CpusetCpus:         opts.cpusetCpus,
+		CpusetMems:         opts.cpusetMems,
+		CPUShares:          opts.cpuShares,
+		Memory:             memory,
+		MemoryReservation:  memoryReservation,
+		MemorySwap:         memorySwap,
+		KernelMemory:       kernelMemory,
+		CPUPeriod:          opts.cpuPeriod,
+		CPUQuota:           opts.cpuQuota,
+		CPURealtimePeriod:  opts.cpuRealtimePeriod,
+		CPURealtimeRuntime: opts.cpuRealtimeRuntime,
 	}
 
 	updateConfig := containertypes.UpdateConfig{

+ 4 - 0
contrib/completion/bash/docker

@@ -1316,6 +1316,8 @@ _docker_container_run() {
 		--cidfile
 		--cpu-period
 		--cpu-quota
+		--cpu-rt-period
+		--cpu-rt-runtime
 		--cpuset-cpus
 		--cpuset-mems
 		--cpu-shares -c
@@ -1667,6 +1669,8 @@ _docker_container_update() {
 		--blkio-weight
 		--cpu-period
 		--cpu-quota
+		--cpu-rt-period
+		--cpu-rt-runtime
 		--cpuset-cpus
 		--cpuset-mems
 		--cpu-shares -c

+ 2 - 0
contrib/completion/zsh/_docker

@@ -1433,6 +1433,8 @@ __docker_subcommand() {
         "($help -c --cpu-shares)"{-c=,--cpu-shares=}"[CPU shares (relative weight)]:CPU shares:(0 10 100 200 500 800 1000)"
         "($help)--cpu-period=[Limit the CPU CFS (Completely Fair Scheduler) period]:CPU period: "
         "($help)--cpu-quota=[Limit the CPU CFS (Completely Fair Scheduler) quota]:CPU quota: "
+        "($help)--cpu-rt-period=[Limit the CPU real-time period]:CPU real-time period in microseconds: "
+        "($help)--cpu-rt-runtime=[Limit the CPU real-time runtime]:CPU real-time runtime in microseconds: "
         "($help)--cpuset-cpus=[CPUs in which to allow execution]:CPUs: "
         "($help)--cpuset-mems=[MEMs in which to allow execution]:MEMs: "
         "($help -m --memory)"{-m=,--memory=}"[Memory limit]:Memory limit: "

+ 4 - 0
daemon/config_unix.go

@@ -34,6 +34,8 @@ type Config struct {
 	Ulimits              map[string]*units.Ulimit `json:"default-ulimits,omitempty"`
 	Runtimes             map[string]types.Runtime `json:"runtimes,omitempty"`
 	DefaultRuntime       string                   `json:"default-runtime,omitempty"`
+	CPURealtimePeriod    int64                    `json:"cpu-rt-period,omitempty"`
+	CPURealtimeRuntime   int64                    `json:"cpu-rt-runtime,omitempty"`
 	OOMScoreAdjust       int                      `json:"oom-score-adjust,omitempty"`
 	Init                 bool                     `json:"init,omitempty"`
 	InitPath             string                   `json:"init-path,omitempty"`
@@ -97,6 +99,8 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
 	flags.IntVar(&config.OOMScoreAdjust, "oom-score-adjust", -500, "Set the oom_score_adj for the daemon")
 	flags.BoolVar(&config.Init, "init", false, "Run an init in the container to forward signals and reap processes")
 	flags.StringVar(&config.InitPath, "init-path", "", "Path to the docker-init binary")
+	flags.Int64Var(&config.CPURealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds")
+	flags.Int64Var(&config.CPURealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds")
 
 	config.attachExperimentalFlags(flags)
 }

+ 43 - 1
daemon/daemon_unix.go

@@ -36,10 +36,11 @@ import (
 	"github.com/docker/libnetwork/options"
 	lntypes "github.com/docker/libnetwork/types"
 	"github.com/golang/protobuf/ptypes"
+	"github.com/opencontainers/runc/libcontainer/cgroups"
 	"github.com/opencontainers/runc/libcontainer/label"
 	rsystem "github.com/opencontainers/runc/libcontainer/system"
 	"github.com/opencontainers/runc/libcontainer/user"
-	"github.com/opencontainers/runtime-spec/specs-go"
+	specs "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/vishvananda/netlink"
 )
 
@@ -118,6 +119,16 @@ func getCPUResources(config containertypes.Resources) *specs.CPU {
 		cpu.Quota = &quota
 	}
 
+	if config.CPURealtimePeriod != 0 {
+		period := uint64(config.CPURealtimePeriod)
+		cpu.RealtimePeriod = &period
+	}
+
+	if config.CPURealtimeRuntime != 0 {
+		runtime := uint64(config.CPURealtimeRuntime)
+		cpu.RealtimeRuntime = &runtime
+	}
+
 	return &cpu
 }
 
@@ -1184,3 +1195,34 @@ func setupOOMScoreAdj(score int) error {
 	f.Close()
 	return err
 }
+
+func (daemon *Daemon) initCgroupsPath(path string) error {
+	if path == "/" || path == "." {
+		return nil
+	}
+
+	daemon.initCgroupsPath(filepath.Dir(path))
+
+	_, root, err := cgroups.FindCgroupMountpointAndRoot("cpu")
+	if err != nil {
+		return err
+	}
+
+	path = filepath.Join(root, path)
+	sysinfo := sysinfo.New(false)
+	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
+		return err
+	}
+	if sysinfo.CPURealtimePeriod && daemon.configStore.CPURealtimePeriod != 0 {
+		if err := ioutil.WriteFile(filepath.Join(path, "cpu.rt_period_us"), []byte(strconv.FormatInt(daemon.configStore.CPURealtimePeriod, 10)), 0700); err != nil {
+			return err
+		}
+	}
+	if sysinfo.CPURealtimeRuntime && daemon.configStore.CPURealtimeRuntime != 0 {
+		if err := ioutil.WriteFile(filepath.Join(path, "cpu.rt_runtime_us"), []byte(strconv.FormatInt(daemon.configStore.CPURealtimeRuntime, 10)), 0700); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}

+ 25 - 1
daemon/oci_linux.go

@@ -21,9 +21,10 @@ import (
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/volume"
 	"github.com/opencontainers/runc/libcontainer/apparmor"
+	"github.com/opencontainers/runc/libcontainer/cgroups"
 	"github.com/opencontainers/runc/libcontainer/devices"
 	"github.com/opencontainers/runc/libcontainer/user"
-	"github.com/opencontainers/runtime-spec/specs-go"
+	specs "github.com/opencontainers/runtime-spec/specs-go"
 )
 
 func setResources(s *specs.Spec, r containertypes.Resources) error {
@@ -655,6 +656,29 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
 	}
 	s.Linux.Resources.OOMScoreAdj = &c.HostConfig.OomScoreAdj
 	s.Linux.Sysctl = c.HostConfig.Sysctls
+
+	p := *s.Linux.CgroupsPath
+	if useSystemd {
+		initPath, err := cgroups.GetInitCgroupDir("cpu")
+		if err != nil {
+			return nil, err
+		}
+		p, _ = cgroups.GetThisCgroupDir("cpu")
+		if err != nil {
+			return nil, err
+		}
+		p = filepath.Join(initPath, p)
+	}
+
+	// Clean path to guard against things like ../../../BAD
+	parentPath := filepath.Dir(p)
+	if !filepath.IsAbs(parentPath) {
+		parentPath = filepath.Clean("/" + parentPath)
+	}
+
+	if err := daemon.initCgroupsPath(parentPath); err != nil {
+		return nil, fmt.Errorf("linux init cgroups path: %v", err)
+	}
 	if err := setDevices(&s, c); err != nil {
 		return nil, fmt.Errorf("linux runtime spec devices: %v", err)
 	}

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

@@ -160,6 +160,7 @@ This section lists each version from latest to oldest.  Each listing includes a
 * `POST /volumes/prune` prunes unused volumes.
 * `POST /networks/prune` prunes unused networks.
 * Every API response now includes a `Docker-Experimental` header specifying if experimental features are enabled (value can be `true` or `false`).
+* 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.
 
 
 ### v1.24 API changes

+ 8 - 0
docs/reference/api/docker_remote_api_v1.25.md

@@ -304,6 +304,8 @@ Create a container
              "CpuPercent": 80,
              "CpuShares": 512,
              "CpuPeriod": 100000,
+             "CpuRealtimePeriod": 1000000,
+             "CpuRealtimeRuntime": 10000,
              "CpuQuota": 50000,
              "CpusetCpus": "0,1",
              "CpusetMems": "0,1",
@@ -426,6 +428,8 @@ Create a container
     -   **CpuShares** - An integer value containing the container's CPU Shares
           (ie. the relative weight vs other containers).
     -   **CpuPeriod** - The length of a CPU period in microseconds.
+    -   **CpuRealtimePeriod** - The length of a CPU real-time period in microseconds (0=no time allocated for rt tasks)
+    -   **CpuRealtimeRuntime** - The length of a CPU real-time runtime in microseconds (0=no time allocated for rt tasks)
     -   **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.
@@ -615,6 +619,8 @@ Return low-level information on the container `id`
 			"CpuPercent": 80,
 			"CpuShares": 0,
 			"CpuPeriod": 100000,
+			"CpuRealtimePeriod": 1000000,
+			"CpuRealtimeRuntime": 10000,
 			"Devices": [],
 			"Dns": null,
 			"DnsOptions": null,
@@ -1191,6 +1197,8 @@ Update configuration of one or more containers.
          "BlkioWeight": 300,
          "CpuShares": 512,
          "CpuPeriod": 100000,
+         "CpuRealtimePeriod": 1000000,
+         "CpuRealtimeRuntime": 10000,
          "CpuQuota": 50000,
          "CpusetCpus": "0,1",
          "CpusetMems": "0",

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

@@ -35,6 +35,8 @@ Options:
       --cpu-period int              Limit CPU CFS (Completely Fair Scheduler) period
       --cpu-quota int               Limit CPU CFS (Completely Fair Scheduler) quota
   -c, --cpu-shares int              CPU shares (relative weight)
+      --cpu-rt-period int           Limit the CPU real-time period in microseconds
+      --cpu-rt-runtime int          Limit the CPU real-time runtime in microseconds
       --cpuset-cpus string          CPUs in which to allow execution (0-3, 0,1)
       --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
       --device value                Add a host device to the container (default [])

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

@@ -33,6 +33,8 @@ Options:
       --cpu-period int              Limit CPU CFS (Completely Fair Scheduler) period
       --cpu-quota int               Limit CPU CFS (Completely Fair Scheduler) quota
   -c, --cpu-shares int              CPU shares (relative weight)
+      --cpu-rt-period int           Limit the CPU real-time period in microseconds
+      --cpu-rt-runtime int          Limit the CPU real-time runtime in microseconds
       --cpuset-cpus string          CPUs in which to allow execution (0-3, 0,1)
       --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
   -d, --detach                      Run container in background and print container ID

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

@@ -25,6 +25,8 @@ Options:
       --cpu-period int              Limit CPU CFS (Completely Fair Scheduler) period
       --cpu-quota int               Limit CPU CFS (Completely Fair Scheduler) quota
   -c, --cpu-shares int              CPU shares (relative weight)
+      --cpu-rt-period int           Limit the CPU real-time period in microseconds
+      --cpu-rt-runtime int          Limit the CPU real-time runtime in microseconds
       --cpuset-cpus string          CPUs in which to allow execution (0-3, 0,1)
       --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
       --help                        Print usage

+ 2 - 0
docs/reference/run.md

@@ -690,6 +690,8 @@ container:
 | `--cpuset-cpus=""`         | CPUs in which to allow execution (0-3, 0,1)                                                                                                     |
 | `--cpuset-mems=""`         | Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.                                                     |
 | `--cpu-quota=0`            | Limit the CPU CFS (Completely Fair Scheduler) quota                                                                                             |
+| `--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.    |
+| `--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.   |
 | `--blkio-weight=0`         | Block IO weight (relative weight) accepts a weight value between 10 and 1000.                                                                   |
 | `--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`. |

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

@@ -17,6 +17,8 @@ docker-create - Create a new container
 [**--cidfile**[=*CIDFILE*]]
 [**--cpu-period**[=*0*]]
 [**--cpu-quota**[=*0*]]
+[**--cpu-rt-period**[=*0*]]
+[**--cpu-rt-runtime**[=*0*]]
 [**--cpuset-cpus**[=*CPUSET-CPUS*]]
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
 [**--device**[=*[]*]]
@@ -123,6 +125,8 @@ The initial status of the container created with **docker create** is 'created'.
 **--cpu-period**=*0*
     Limit the CPU CFS (Completely Fair Scheduler) period
 
+    Limit the container's CPU usage. This flag tell the kernel to restrict the container's CPU usage to the period you specify.
+
 **--cpuset-cpus**=""
    CPUs in which to allow execution (0-3, 0,1)
 
@@ -136,6 +140,19 @@ two memory nodes.
 **--cpu-quota**=*0*
    Limit the CPU CFS (Completely Fair Scheduler) quota
 
+**--cpu-rt-period**=0
+   Limit the CPU real-time period in microseconds
+
+   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.
+
+**--cpu-rt-runtime**=0
+   Limit the CPU real-time runtime in microseconds
+
+   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:
+   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.
+
+   The sum of all runtimes across containers cannot exceed the amount alotted to the parent cgroup.
+
 **--device**=[]
    Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)
 

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

@@ -17,6 +17,8 @@ docker-run - Run a command in a new container
 [**--cidfile**[=*CIDFILE*]]
 [**--cpu-period**[=*0*]]
 [**--cpu-quota**[=*0*]]
+[**--cpu-rt-period**[=*0*]]
+[**--cpu-rt-runtime**[=*0*]]
 [**--cpuset-cpus**[=*CPUSET-CPUS*]]
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
 [**-d**|**--detach**]
@@ -192,6 +194,19 @@ two memory nodes.
 CPU resource. This flag tell the kernel to restrict the container's CPU usage
 to the quota you specify.
 
+**--cpu-rt-period**=0
+   Limit the CPU real-time period in microseconds
+
+   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.
+
+**--cpu-rt-runtime**=0
+   Limit the CPU real-time runtime in microseconds
+
+   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:
+   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.
+
+   The sum of all runtimes across containers cannot exceed the amount alotted to the parent cgroup.
+
 **-d**, **--detach**=*true*|*false*
    Detached mode: run the container in the background and print the new container ID. The default is *false*.
 

+ 17 - 0
man/docker-update.1.md

@@ -10,6 +10,8 @@ docker-update - Update configuration of one or more containers
 [**--cpu-shares**[=*0*]]
 [**--cpu-period**[=*0*]]
 [**--cpu-quota**[=*0*]]
+[**--cpu-rt-period**[=*0*]]
+[**--cpu-rt-runtime**[=*0*]]
 [**--cpuset-cpus**[=*CPUSET-CPUS*]]
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
 [**--help**]
@@ -44,9 +46,24 @@ a running container with kernel memory initialized.
 **--cpu-period**=0
    Limit the CPU CFS (Completely Fair Scheduler) period
 
+   Limit the container's CPU usage. This flag tell the kernel to restrict the container's CPU usage to the period you specify.
+
 **--cpu-quota**=0
    Limit the CPU CFS (Completely Fair Scheduler) quota
 
+**--cpu-rt-period**=0
+   Limit the CPU real-time period in microseconds
+
+   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.
+
+**--cpu-rt-runtime**=0
+   Limit the CPU real-time runtime in microseconds
+
+   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:
+   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.
+
+   The sum of all runtimes across containers cannot exceed the amount alotted to the parent cgroup.
+
 **--cpuset-cpus**=""
    CPUs in which to allow execution (0-3, 0,1)
 

+ 6 - 0
pkg/sysinfo/sysinfo.go

@@ -58,6 +58,12 @@ type cgroupCPUInfo struct {
 
 	// Whether CPU CFS(Completely Fair Scheduler) quota is supported or not
 	CPUCfsQuota bool
+
+	// Whether CPU real-time period is supported or not
+	CPURealtimePeriod bool
+
+	// Whether CPU real-time runtime is supported or not
+	CPURealtimeRuntime bool
 }
 
 type cgroupBlkioInfo struct {

+ 16 - 3
pkg/sysinfo/sysinfo_linux.go

@@ -135,10 +135,23 @@ func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
 	if !quiet && !cpuCfsQuota {
 		logrus.Warn("Your kernel does not support cgroup cfs quotas")
 	}
+
+	cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us")
+	if !quiet && !cpuRealtimePeriod {
+		logrus.Warn("Your kernel does not support cgroup rt period")
+	}
+
+	cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
+	if !quiet && !cpuRealtimeRuntime {
+		logrus.Warn("Your kernel does not support cgroup rt runtime")
+	}
+
 	return cgroupCPUInfo{
-		CPUShares:    cpuShares,
-		CPUCfsPeriod: cpuCfsPeriod,
-		CPUCfsQuota:  cpuCfsQuota,
+		CPUShares:          cpuShares,
+		CPUCfsPeriod:       cpuCfsPeriod,
+		CPUCfsQuota:        cpuCfsQuota,
+		CPURealtimePeriod:  cpuRealtimePeriod,
+		CPURealtimeRuntime: cpuRealtimeRuntime,
 	}
 }
 

+ 5 - 3
pkg/sysinfo/sysinfo_solaris.go

@@ -77,9 +77,11 @@ func setCgroupMem(quiet bool) cgroupMemInfo {
 func setCgroupCPU(quiet bool) cgroupCPUInfo {
 
 	return cgroupCPUInfo{
-		CPUShares:    true,
-		CPUCfsPeriod: false,
-		CPUCfsQuota:  true,
+		CPUShares:          true,
+		CPUCfsPeriod:       false,
+		CPUCfsQuota:        true,
+		CPURealtimePeriod:  false,
+		CPURealtimeRuntime: false,
 	}
 }
 

+ 5 - 0
runconfig/config.go

@@ -7,6 +7,7 @@ import (
 
 	"github.com/docker/docker/api/types/container"
 	networktypes "github.com/docker/docker/api/types/network"
+	"github.com/docker/docker/pkg/sysinfo"
 	"github.com/docker/docker/volume"
 )
 
@@ -68,6 +69,10 @@ func DecodeContainerConfig(src io.Reader) (*container.Config, *container.HostCon
 		return nil, nil, nil, err
 	}
 
+	// Validate Resources
+	if err := ValidateResources(hc, sysinfo.New(true)); err != nil {
+		return nil, nil, nil, err
+	}
 	return w.Config, hc, w.NetworkingConfig, nil
 }
 

+ 6 - 0
runconfig/hostconfig_solaris.go

@@ -5,6 +5,7 @@ import (
 	"strings"
 
 	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/pkg/sysinfo"
 )
 
 // DefaultDaemonNetworkMode returns the default network stack the daemon should
@@ -45,3 +46,8 @@ func ValidateIsolation(hc *container.HostConfig) error {
 func ValidateQoS(hc *container.HostConfig) error {
 	return nil
 }
+
+// ValidateResources performs platform specific validation of the resource settings
+func ValidateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
+	return nil
+}

+ 61 - 0
runconfig/hostconfig_test.go

@@ -9,6 +9,7 @@ import (
 	"testing"
 
 	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/pkg/sysinfo"
 )
 
 // TODO Windows: This will need addressing for a Windows daemon.
@@ -220,3 +221,63 @@ func TestDecodeHostConfig(t *testing.T) {
 		}
 	}
 }
+
+func TestValidateResources(t *testing.T) {
+	type resourceTest struct {
+		ConfigCPURealtimePeriod   int64
+		ConfigCPURealtimeRuntime  int64
+		SysInfoCPURealtimePeriod  bool
+		SysInfoCPURealtimeRuntime bool
+		ErrorExpected             bool
+		FailureMsg                string
+	}
+
+	tests := []resourceTest{
+		{
+			ConfigCPURealtimePeriod:   1000,
+			ConfigCPURealtimeRuntime:  1000,
+			SysInfoCPURealtimePeriod:  true,
+			SysInfoCPURealtimeRuntime: true,
+			ErrorExpected:             false,
+			FailureMsg:                "Expected valid configuration",
+		},
+		{
+			ConfigCPURealtimePeriod:   5000,
+			ConfigCPURealtimeRuntime:  5000,
+			SysInfoCPURealtimePeriod:  false,
+			SysInfoCPURealtimeRuntime: true,
+			ErrorExpected:             true,
+			FailureMsg:                "Expected failure when cpu-rt-period is set but kernel doesn't support it",
+		},
+		{
+			ConfigCPURealtimePeriod:   5000,
+			ConfigCPURealtimeRuntime:  5000,
+			SysInfoCPURealtimePeriod:  true,
+			SysInfoCPURealtimeRuntime: false,
+			ErrorExpected:             true,
+			FailureMsg:                "Expected failure when cpu-rt-runtime is set but kernel doesn't support it",
+		},
+		{
+			ConfigCPURealtimePeriod:   5000,
+			ConfigCPURealtimeRuntime:  10000,
+			SysInfoCPURealtimePeriod:  true,
+			SysInfoCPURealtimeRuntime: false,
+			ErrorExpected:             true,
+			FailureMsg:                "Expected failure when cpu-rt-runtime is greater than cpu-rt-period",
+		},
+	}
+
+	for _, rt := range tests {
+		var hc container.HostConfig
+		hc.Resources.CPURealtimePeriod = rt.ConfigCPURealtimePeriod
+		hc.Resources.CPURealtimeRuntime = rt.ConfigCPURealtimeRuntime
+
+		var si sysinfo.SysInfo
+		si.CPURealtimePeriod = rt.SysInfoCPURealtimePeriod
+		si.CPURealtimeRuntime = rt.SysInfoCPURealtimeRuntime
+
+		if err := ValidateResources(&hc, &si); (err != nil) != rt.ErrorExpected {
+			t.Fatal(rt.FailureMsg, err)
+		}
+	}
+}

+ 23 - 0
runconfig/hostconfig_unix.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 
 	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/pkg/sysinfo"
 )
 
 // DefaultDaemonNetworkMode returns the default network stack the daemon should
@@ -104,3 +105,25 @@ func ValidateQoS(hc *container.HostConfig) error {
 	}
 	return nil
 }
+
+// ValidateResources performs platform specific validation of the resource settings
+// cpu-rt-runtime and cpu-rt-period can not be greater than their parent, cpu-rt-runtime requires sys_nice
+func ValidateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
+	// We may not be passed a host config, such as in the case of docker commit
+	if hc == nil {
+		return nil
+	}
+
+	if hc.Resources.CPURealtimePeriod > 0 && !si.CPURealtimePeriod {
+		return fmt.Errorf("invalid --cpu-rt-period: Your kernel does not support cgroup rt period")
+	}
+
+	if hc.Resources.CPURealtimeRuntime > 0 && !si.CPURealtimeRuntime {
+		return fmt.Errorf("invalid --cpu-rt-runtime: Your kernel does not support cgroup rt runtime")
+	}
+
+	if hc.Resources.CPURealtimePeriod != 0 && hc.Resources.CPURealtimeRuntime != 0 && hc.Resources.CPURealtimeRuntime > hc.Resources.CPURealtimePeriod {
+		return fmt.Errorf("invalid --cpu-rt-runtime: rt runtime cannot be higher than rt period")
+	}
+	return nil
+}

+ 17 - 0
runconfig/hostconfig_windows.go

@@ -5,6 +5,7 @@ import (
 	"strings"
 
 	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/pkg/sysinfo"
 )
 
 // DefaultDaemonNetworkMode returns the default network stack the daemon should
@@ -49,3 +50,19 @@ func ValidateIsolation(hc *container.HostConfig) error {
 func ValidateQoS(hc *container.HostConfig) error {
 	return nil
 }
+
+// ValidateResources performs platform specific validation of the resource settings
+func ValidateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error {
+	// We may not be passed a host config, such as in the case of docker commit
+	if hc == nil {
+		return nil
+	}
+
+	if hc.Resources.CPURealtimePeriod != 0 {
+		return fmt.Errorf("invalid --cpu-rt-period: Windows does not support this feature")
+	}
+	if hc.Resources.CPURealtimeRuntime != 0 {
+		return fmt.Errorf("invalid --cpu-rt-runtime: Windows does not support this feature")
+	}
+	return nil
+}

+ 90 - 84
runconfig/opts/parse.go

@@ -23,90 +23,92 @@ import (
 
 // ContainerOptions is a data object with all the options for creating a container
 type ContainerOptions struct {
-	attach            opts.ListOpts
-	volumes           opts.ListOpts
-	tmpfs             opts.ListOpts
-	blkioWeightDevice WeightdeviceOpt
-	deviceReadBps     ThrottledeviceOpt
-	deviceWriteBps    ThrottledeviceOpt
-	links             opts.ListOpts
-	aliases           opts.ListOpts
-	linkLocalIPs      opts.ListOpts
-	deviceReadIOps    ThrottledeviceOpt
-	deviceWriteIOps   ThrottledeviceOpt
-	env               opts.ListOpts
-	labels            opts.ListOpts
-	devices           opts.ListOpts
-	ulimits           *UlimitOpt
-	sysctls           *opts.MapOpts
-	publish           opts.ListOpts
-	expose            opts.ListOpts
-	dns               opts.ListOpts
-	dnsSearch         opts.ListOpts
-	dnsOptions        opts.ListOpts
-	extraHosts        opts.ListOpts
-	volumesFrom       opts.ListOpts
-	envFile           opts.ListOpts
-	capAdd            opts.ListOpts
-	capDrop           opts.ListOpts
-	groupAdd          opts.ListOpts
-	securityOpt       opts.ListOpts
-	storageOpt        opts.ListOpts
-	labelsFile        opts.ListOpts
-	loggingOpts       opts.ListOpts
-	privileged        bool
-	pidMode           string
-	utsMode           string
-	usernsMode        string
-	publishAll        bool
-	stdin             bool
-	tty               bool
-	oomKillDisable    bool
-	oomScoreAdj       int
-	containerIDFile   string
-	entrypoint        string
-	hostname          string
-	memoryString      string
-	memoryReservation string
-	memorySwap        string
-	kernelMemory      string
-	user              string
-	workingDir        string
-	cpuShares         int64
-	cpuPercent        int64
-	cpuPeriod         int64
-	cpuQuota          int64
-	cpusetCpus        string
-	cpusetMems        string
-	blkioWeight       uint16
-	ioMaxBandwidth    string
-	ioMaxIOps         uint64
-	swappiness        int64
-	netMode           string
-	macAddress        string
-	ipv4Address       string
-	ipv6Address       string
-	ipcMode           string
-	pidsLimit         int64
-	restartPolicy     string
-	readonlyRootfs    bool
-	loggingDriver     string
-	cgroupParent      string
-	volumeDriver      string
-	stopSignal        string
-	stopTimeout       int
-	isolation         string
-	shmSize           string
-	noHealthcheck     bool
-	healthCmd         string
-	healthInterval    time.Duration
-	healthTimeout     time.Duration
-	healthRetries     int
-	runtime           string
-	autoRemove        bool
-	init              bool
-	initPath          string
-	credentialSpec    string
+	attach             opts.ListOpts
+	volumes            opts.ListOpts
+	tmpfs              opts.ListOpts
+	blkioWeightDevice  WeightdeviceOpt
+	deviceReadBps      ThrottledeviceOpt
+	deviceWriteBps     ThrottledeviceOpt
+	links              opts.ListOpts
+	aliases            opts.ListOpts
+	linkLocalIPs       opts.ListOpts
+	deviceReadIOps     ThrottledeviceOpt
+	deviceWriteIOps    ThrottledeviceOpt
+	env                opts.ListOpts
+	labels             opts.ListOpts
+	devices            opts.ListOpts
+	ulimits            *UlimitOpt
+	sysctls            *opts.MapOpts
+	publish            opts.ListOpts
+	expose             opts.ListOpts
+	dns                opts.ListOpts
+	dnsSearch          opts.ListOpts
+	dnsOptions         opts.ListOpts
+	extraHosts         opts.ListOpts
+	volumesFrom        opts.ListOpts
+	envFile            opts.ListOpts
+	capAdd             opts.ListOpts
+	capDrop            opts.ListOpts
+	groupAdd           opts.ListOpts
+	securityOpt        opts.ListOpts
+	storageOpt         opts.ListOpts
+	labelsFile         opts.ListOpts
+	loggingOpts        opts.ListOpts
+	privileged         bool
+	pidMode            string
+	utsMode            string
+	usernsMode         string
+	publishAll         bool
+	stdin              bool
+	tty                bool
+	oomKillDisable     bool
+	oomScoreAdj        int
+	containerIDFile    string
+	entrypoint         string
+	hostname           string
+	memoryString       string
+	memoryReservation  string
+	memorySwap         string
+	kernelMemory       string
+	user               string
+	workingDir         string
+	cpuShares          int64
+	cpuPercent         int64
+	cpuPeriod          int64
+	cpuRealtimePeriod  int64
+	cpuRealtimeRuntime int64
+	cpuQuota           int64
+	cpusetCpus         string
+	cpusetMems         string
+	blkioWeight        uint16
+	ioMaxBandwidth     string
+	ioMaxIOps          uint64
+	swappiness         int64
+	netMode            string
+	macAddress         string
+	ipv4Address        string
+	ipv6Address        string
+	ipcMode            string
+	pidsLimit          int64
+	restartPolicy      string
+	readonlyRootfs     bool
+	loggingDriver      string
+	cgroupParent       string
+	volumeDriver       string
+	stopSignal         string
+	stopTimeout        int
+	isolation          string
+	shmSize            string
+	noHealthcheck      bool
+	healthCmd          string
+	healthInterval     time.Duration
+	healthTimeout      time.Duration
+	healthRetries      int
+	runtime            string
+	autoRemove         bool
+	init               bool
+	initPath           string
+	credentialSpec     string
 
 	Image string
 	Args  []string
@@ -225,6 +227,8 @@ func AddFlags(flags *pflag.FlagSet) *ContainerOptions {
 	flags.Int64Var(&copts.cpuPercent, "cpu-percent", 0, "CPU percent (Windows only)")
 	flags.Int64Var(&copts.cpuPeriod, "cpu-period", 0, "Limit CPU CFS (Completely Fair Scheduler) period")
 	flags.Int64Var(&copts.cpuQuota, "cpu-quota", 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
+	flags.Int64Var(&copts.cpuRealtimePeriod, "cpu-rt-period", 0, "Limit CPU real-time period in microseconds")
+	flags.Int64Var(&copts.cpuRealtimeRuntime, "cpu-rt-runtime", 0, "Limit CPU real-time runtime in microseconds")
 	flags.Int64VarP(&copts.cpuShares, "cpu-shares", "c", 0, "CPU shares (relative weight)")
 	flags.Var(&copts.deviceReadBps, "device-read-bps", "Limit read rate (bytes per second) from a device")
 	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
 		CpusetCpus:           copts.cpusetCpus,
 		CpusetMems:           copts.cpusetMems,
 		CPUQuota:             copts.cpuQuota,
+		CPURealtimePeriod:    copts.cpuRealtimePeriod,
+		CPURealtimeRuntime:   copts.cpuRealtimeRuntime,
 		PidsLimit:            copts.pidsLimit,
 		BlkioWeight:          copts.blkioWeight,
 		BlkioWeightDevice:    copts.blkioWeightDevice.GetList(),