Merge pull request #10736 from coolljt0725/add_cpu_limit

Add support cpu cfs_quota
This commit is contained in:
Jessie Frazelle 2015-04-20 17:55:01 -07:00
Родитель e562495d56 dcc50e1d59
Коммит 17d5450bc3
15 изменённых файлов: 84 добавлений и 0 удалений

Просмотреть файл

@ -132,6 +132,7 @@ type Info struct {
DriverStatus [][2]string
MemoryLimit bool
SwapLimit bool
CpuCfsQuota bool
IPv4Forwarding bool
Debug bool
NFd int

Просмотреть файл

@ -770,6 +770,7 @@ _docker_run() {
--cidfile
--cpuset
--cpu-shares -c
--cpu-quota
--device
--dns
--dns-search

Просмотреть файл

@ -356,6 +356,7 @@ func populateCommand(c *Container, env []string) error {
CpuShares: c.hostConfig.CpuShares,
CpusetCpus: c.hostConfig.CpusetCpus,
CpusetMems: c.hostConfig.CpusetMems,
CpuQuota: c.hostConfig.CpuQuota,
Rlimits: rlimits,
}

Просмотреть файл

@ -1250,6 +1250,10 @@ func (daemon *Daemon) verifyHostConfig(hostConfig *runconfig.HostConfig) ([]stri
if hostConfig.Memory == 0 && hostConfig.MemorySwap > 0 {
return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.")
}
if hostConfig.CpuQuota > 0 && !daemon.SystemConfig().CpuCfsQuota {
warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.")
hostConfig.CpuQuota = 0
}
return warnings, nil
}

Просмотреть файл

@ -111,6 +111,7 @@ type Resources struct {
CpuShares int64 `json:"cpu_shares"`
CpusetCpus string `json:"cpuset_cpus"`
CpusetMems string `json:"cpuset_mems"`
CpuQuota int64 `json:"cpu_quota"`
Rlimits []*ulimit.Rlimit `json:"rlimits"`
}
@ -206,6 +207,7 @@ func SetupCgroups(container *configs.Config, c *Command) error {
container.Cgroups.MemorySwap = c.Resources.MemorySwap
container.Cgroups.CpusetCpus = c.Resources.CpusetCpus
container.Cgroups.CpusetMems = c.Resources.CpusetMems
container.Cgroups.CpuQuota = c.Resources.CpuQuota
}
return nil

Просмотреть файл

@ -113,6 +113,9 @@ lxc.cgroup.cpuset.cpus = {{.Resources.CpusetCpus}}
{{if .Resources.CpusetMems}}
lxc.cgroup.cpuset.mems = {{.Resources.CpusetMems}}
{{end}}
{{if .Resources.CpuQuota}}
lxc.cgroup.cpu.cfs_quota_us = {{.Resources.CpuQuota}}
{{end}}
{{end}}
{{if .LxcConfig}}

Просмотреть файл

@ -60,6 +60,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
DriverStatus: daemon.GraphDriver().Status(),
MemoryLimit: daemon.SystemConfig().MemoryLimit,
SwapLimit: daemon.SystemConfig().SwapLimit,
CpuCfsQuota: daemon.SystemConfig().CpuCfsQuota,
IPv4Forwarding: !daemon.SystemConfig().IPv4ForwardingDisabled,
Debug: os.Getenv("DEBUG") != "",
NFd: fileutils.GetTotalUsedFds(),

Просмотреть файл

@ -14,6 +14,7 @@ docker-create - Create a new container
[**--cidfile**[=*CIDFILE*]]
[**--cpuset-cpus**[=*CPUSET-CPUS*]]
[**--cpuset-mems**[=*CPUSET-MEMS*]]
[**--cpu-quota**[=*0*]]
[**--device**[=*[]*]]
[**--dns-search**[=*[]*]]
[**--dns**[=*[]*]]
@ -82,6 +83,9 @@ IMAGE [COMMAND] [ARG...]
then processes in your Docker container will only use memory from the first
two memory nodes.
**-cpu-quota**=0
Limit the CPU CFS (Completely Fair Scheduler) quota
**--device**=[]
Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)

Просмотреть файл

@ -15,6 +15,7 @@ docker-run - Run a command in a new container
[**--cpuset-cpus**[=*CPUSET-CPUS*]]
[**--cpuset-mems**[=*CPUSET-MEMS*]]
[**-d**|**--detach**[=*false*]]
[**--cpu-quota**[=*0*]]
[**--device**[=*[]*]]
[**--dns-search**[=*[]*]]
[**--dns**[=*[]*]]
@ -142,6 +143,13 @@ division of CPU shares:
then processes in your Docker container will only use memory from the first
two memory nodes.
**--cpu-quota**=0
Limit the CPU CFS (Completely Fair Scheduler) quota
Limit the container's CPU usage. By default, containers run with the full
CPU resource. This flag tell the kernel to restrict the container's CPU usage
to the quota you specify.
**-d**, **--detach**=*true*|*false*
Detached mode: run the container in the background and print the new container ID. The default is *false*.

Просмотреть файл

@ -925,6 +925,7 @@ Creates a new container.
--cidfile="" Write the container ID to the file
--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)
--cpu-quota=0 Limit the CPU CFS (Completely Fair Scheduler) quota
--device=[] Add a host device to the container
--dns=[] Set custom DNS servers
--dns-search=[] Set custom DNS search domains
@ -1879,6 +1880,7 @@ To remove an image using its digest:
--cidfile="" Write the container ID to the file
--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)
--cpu-quota=0 Limit the CPU CFS (Completely Fair Scheduler) quota
-d, --detach=false Run container in background and print container ID
--device=[] Add a host device to the container
--dns=[] Set custom DNS servers

Просмотреть файл

@ -475,6 +475,7 @@ container:
-c, --cpu-shares=0: CPU shares (relative weight)
--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
### Memory constraints
@ -615,6 +616,15 @@ memory nodes 1 and 3.
This example restricts the processes in the container to only use memory from
memory nodes 0, 1 and 2.
### CPU quota constraint
The `--cpu-quota` flag limits the container's CPU usage. The default 0 value
allows the container to take 100% of a CPU resource (1 CPU). The CFS (Completely Fair
Scheduler) handles resource allocation for executing processes and is default
Linux Scheduler used by the kernel. Set this value to 50000 to limit the container
to 50% of a CPU resource. For multiple CPUs, adjust the `--cpu-quota` as necessary.
For more information, see the [CFS documentation on bandwidth limiting](https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt).
## Runtime privilege, Linux capabilities, and LXC configuration
--cap-add: Add Linux capabilities

Просмотреть файл

@ -105,6 +105,36 @@ func TestRunEchoStdoutWithCPUAndMemoryLimit(t *testing.T) {
logDone("run - echo with CPU and memory limit")
}
// "test" should be printed
func TestRunEchoStdoutWitCPUQuota(t *testing.T) {
defer deleteAllContainers()
runCmd := exec.Command(dockerBinary, "run", "--cpu-quota", "8000", "--name", "test", "busybox", "echo", "test")
out, _, _, err := runCommandWithStdoutStderr(runCmd)
if err != nil {
t.Fatalf("failed to run container: %v, output: %q", err, out)
}
out = strings.TrimSpace(out)
if strings.Contains(out, "Your kernel does not support CPU cfs quota") {
t.Skip("Your kernel does not support CPU cfs quota, skip this test")
}
if out != "test" {
t.Errorf("container should've printed 'test'")
}
cmd := exec.Command(dockerBinary, "inspect", "-f", "{{.HostConfig.CpuQuota}}", "test")
out, _, err = runCommandWithOutput(cmd)
if err != nil {
t.Fatalf("failed to inspect container: %s, %v", out, err)
}
out = strings.TrimSpace(out)
if out != "8000" {
t.Errorf("setting the CPU CFS quota failed")
}
logDone("run - echo with CPU quota")
}
// "test" should be printed
func TestRunEchoNamedContainer(t *testing.T) {
defer deleteAllContainers()

Просмотреть файл

@ -13,6 +13,7 @@ import (
type SysInfo struct {
MemoryLimit bool
SwapLimit bool
CpuCfsQuota bool
IPv4ForwardingDisabled bool
AppArmor bool
}
@ -39,6 +40,19 @@ func New(quiet bool) *SysInfo {
}
}
if cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu"); err != nil {
if !quiet {
logrus.Warnf("WARING: %s\n", err)
}
} else {
_, err1 := ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_quota_us"))
logrus.Warnf("%s", cgroupCpuMountpoint)
sysInfo.CpuCfsQuota = err1 == nil
if !sysInfo.CpuCfsQuota && !quiet {
logrus.Warnf("WARING: Your kernel does not support cgroup cfs quotas")
}
}
// Check if AppArmor is supported.
if _, err := os.Stat("/sys/kernel/security/apparmor"); os.IsNotExist(err) {
sysInfo.AppArmor = false

Просмотреть файл

@ -167,6 +167,7 @@ type HostConfig struct {
CpuShares int64 // CPU shares (relative weight vs. other containers)
CpusetCpus string // CpusetCpus 0-2, 0,1
CpusetMems string // CpusetMems 0-2, 0,1
CpuQuota int64
Privileged bool
PortBindings nat.PortMap
Links []string

Просмотреть файл

@ -65,6 +65,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
flCpusetCpus = cmd.String([]string{"#-cpuset", "-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
flCpusetMems = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
flCpuQuota = cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container")
flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
flIpcMode = cmd.String([]string{"-ipc"}, "", "IPC namespace to use")
@ -312,6 +313,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
CpuShares: *flCpuShares,
CpusetCpus: *flCpusetCpus,
CpusetMems: *flCpusetMems,
CpuQuota: *flCpuQuota,
Privileged: *flPrivileged,
PortBindings: portBindings,
Links: flLinks.GetAll(),