зеркало из https://github.com/microsoft/docker.git
Merge pull request #10736 from coolljt0725/add_cpu_limit
Add support cpu cfs_quota
This commit is contained in:
Коммит
17d5450bc3
|
@ -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(),
|
||||
|
|
Загрузка…
Ссылка в новой задаче