#从这里的输出可以看到,cpuset被挂载在了/sys/fs/cgroup/cpuset, #而cpu和cpuacct一起挂载到了/sys/fs/cgroup/cpu,cpuacct下面 dev@ubuntu:~$ mount|grep cpu cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
#进入/sys/fs/cgroup/cpu,cpuacct并创建子cgroup dev@ubuntu:~$ cd /sys/fs/cgroup/cpu,cpuacct dev@ubuntu:/sys/fs/cgroup/cpu,cpuacct$ sudo mkdir test dev@ubuntu:/sys/fs/cgroup/cpu,cpuacct$ cd test dev@ubuntu:/sys/fs/cgroup/cpu,cpuacct/test$ ls cgroup.clone_children cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.stat tasks cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.shares notify_on_release
func (s *MemoryGroup) Apply(d *cgroupData) (err error) { path, err := d.path("memory") if err != nil && !cgroups.IsNotFound(err) { return err } else if path == "" { return nil } if memoryAssigned(d.config) { if _, err := os.Stat(path); os.IsNotExist(err) { if err := os.MkdirAll(path, 0755); err != nil { return err } // 只有内核内存可以动态设置 if err := EnableKernelMemoryAccounting(path); err != nil { return err } } } ... }
func EnableKernelMemoryAccounting(path string) error { // Check if kernel memory is enabled // We have to limit the kernel memory here as it won't be accounted at all // until a limit is set on the cgroup and limit cannot be set once the // cgroup has children, or if there are already tasks in the cgroup. for _, i := range []int64{1, -1} { if err := setKernelMemory(path, i); err != nil { return err } } return nil }
func (s *CpuGroup) Apply(d *cgroupData) error { // We always want to join the cpu group, to allow fair cpu scheduling // on a container basis path, err := d.path("cpu") if err != nil && !cgroups.IsNotFound(err) { return err } return s.ApplyDir(path, d.config, d.pid) }
func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error { // This might happen if we have no cpu cgroup mounted. // Just do nothing and don't fail. if path == "" { return nil } if err := os.MkdirAll(path, 0755); err != nil { return err } // We should set the real-Time group scheduling settings before moving // in the process because if the process is already in SCHED_RR mode // and no RT bandwidth is set, adding it will fail. if err := s.SetRtSched(path, cgroup); err != nil { return err } // because we are not using d.join we need to place the pid into the procs file // unlike the other subsystems if err := cgroups.WriteCgroupProc(path, pid); err != nil { return err }
// cgroupManagerImpl implements the CgroupManager interface. // Its a stateless object which can be used to // update,create or delete any number of cgroups // It uses the Libcontainer raw fs cgroup manager for cgroup management. type cgroupManagerImpl struct { // subsystems holds information about all the // mounted cgroup subsystems on the node subsystems *CgroupSubsystems // simplifies interaction with libcontainer and its cgroup managers adapter *libcontainerAdapter }
// ResourceConfigForPod takes the input pod and outputs the cgroup resource config. func ResourceConfigForPod(pod *v1.Pod) *ResourceConfig { // sum requests and limits. reqs, limits := resource.PodRequestsAndLimits(pod)
cpuRequests := int64(0) cpuLimits := int64(0) memoryLimits := int64(0) if request, found := reqs[v1.ResourceCPU]; found { cpuRequests = request.MilliValue() } if limit, found := limits[v1.ResourceCPU]; found { cpuLimits = limit.MilliValue() } if limit, found := limits[v1.ResourceMemory]; found { memoryLimits = limit.Value() }
// MilliCPUToShares converts the milliCPU to CFS shares. func MilliCPUToShares(milliCPU int64) uint64 { if milliCPU == 0 { // Docker converts zero milliCPU to unset, which maps to kernel default // for unset: 1024. Return 2 here to really match kernel default for // zero milliCPU. return MinShares } // Conceptually (milliCPU / milliCPUToCPU) * sharesPerCPU, but factored to improve rounding. shares := (milliCPU * SharesPerCPU) / MilliCPUToCPU if shares < MinShares { return MinShares } return uint64(shares) }
// MilliCPUToQuota converts milliCPU to CFS quota and period values. func MilliCPUToQuota(milliCPU int64) (quota int64, period uint64) { // CFS quota is measured in two values: // - cfs_period_us=100ms (the amount of time to measure usage across) // - cfs_quota=20ms (the amount of cpu time allowed to be used across a period) // so in the above example, you are limited to 20% of a single CPU // for multi-cpu environments, you just scale equivalent amounts
if milliCPU == 0 { return }
// we set the period to 100ms by default period = QuotaPeriod
// we then convert your milliCPU to a value normalized over a period quota = (milliCPU * QuotaPeriod) / MilliCPUToCPU
// quota needs to be a minimum of 1ms. if quota < MinQuotaPeriod { quota = MinQuotaPeriod }
return }
const ( // Taken from lmctfy https://github.com/google/lmctfy/blob/master/lmctfy/controllers/cpu_controller.cc MinShares = 2 SharesPerCPU = 1024 MilliCPUToCPU = 1000
// 100000 is equivalent to 100ms QuotaPeriod = 100000 MinQuotaPeriod = 1000 )
设置的代码:
1 2 3 4 5 6 7 8 9 10 11 12
func setSupportedSubsystems(cgroupConfig *libcontainerconfigs.Cgroup) error { for _, sys := range getSupportedSubsystems() { if _, ok := cgroupConfig.Paths[sys.Name()]; !ok { return fmt.Errorf("Failed to find subsystem mount for subsystem: %v", sys.Name()) } // 调用前面的cgroup.Set()方法 if err := sys.Set(cgroupConfig.Paths[sys.Name()], cgroupConfig); err != nil { return fmt.Errorf("Failed to set config for supported subsystems : %v", err) } } return nil }