cgroup: initial support for cgroups v2
add some initial support for cgroups v2. Not all the stats supported on cgroups v1 are supported, e.g. it is not possible to read percpu usage. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
parent
4f0396f1cc
commit
60f064ee41
@ -19,6 +19,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -27,6 +28,7 @@ import (
|
||||
info "github.com/google/cadvisor/info/v1"
|
||||
"github.com/google/cadvisor/utils"
|
||||
"github.com/karrick/godirwalk"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"k8s.io/klog"
|
||||
@ -47,6 +49,25 @@ func DebugInfo(watches map[string][]string) map[string][]string {
|
||||
return out
|
||||
}
|
||||
|
||||
// findFileInAncestorDir returns the path to the parent directory that contains the specified file.
|
||||
// "" is returned if the lookup reaches the limit.
|
||||
func findFileInAncestorDir(current, file, limit string) (string, error) {
|
||||
for {
|
||||
fpath := path.Join(current, file)
|
||||
_, err := os.Stat(fpath)
|
||||
if err == nil {
|
||||
return current, nil
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
if current == limit {
|
||||
return "", nil
|
||||
}
|
||||
current = filepath.Dir(current)
|
||||
}
|
||||
}
|
||||
|
||||
func GetSpec(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoFactory, hasNetwork, hasFilesystem bool) (info.ContainerSpec, error) {
|
||||
var spec info.ContainerSpec
|
||||
|
||||
@ -100,7 +121,12 @@ func GetSpec(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoF
|
||||
if ok {
|
||||
if utils.FileExists(cpusetRoot) {
|
||||
spec.HasCpu = true
|
||||
mask := readString(cpusetRoot, "cpuset.cpus")
|
||||
mask := ""
|
||||
if cgroups.IsCgroup2UnifiedMode() {
|
||||
mask = readString(cpusetRoot, "cpuset.cpus.effective")
|
||||
} else {
|
||||
mask = readString(cpusetRoot, "cpuset.cpus")
|
||||
}
|
||||
spec.Cpu.Mask = utils.FixCpuMask(mask, mi.NumCores)
|
||||
}
|
||||
}
|
||||
@ -108,11 +134,24 @@ func GetSpec(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoF
|
||||
// Memory
|
||||
memoryRoot, ok := cgroupPaths["memory"]
|
||||
if ok {
|
||||
if utils.FileExists(memoryRoot) {
|
||||
spec.HasMemory = true
|
||||
spec.Memory.Limit = readUInt64(memoryRoot, "memory.limit_in_bytes")
|
||||
spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.memsw.limit_in_bytes")
|
||||
spec.Memory.Reservation = readUInt64(memoryRoot, "memory.soft_limit_in_bytes")
|
||||
if !cgroups.IsCgroup2UnifiedMode() {
|
||||
if utils.FileExists(memoryRoot) {
|
||||
spec.HasMemory = true
|
||||
spec.Memory.Limit = readUInt64(memoryRoot, "memory.limit_in_bytes")
|
||||
spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.memsw.limit_in_bytes")
|
||||
spec.Memory.Reservation = readUInt64(memoryRoot, "memory.soft_limit_in_bytes")
|
||||
}
|
||||
} else {
|
||||
memoryRoot, err := findFileInAncestorDir(memoryRoot, "memory.max", "/sys/fs/cgroup")
|
||||
if err != nil {
|
||||
return spec, err
|
||||
}
|
||||
if memoryRoot != "" {
|
||||
spec.HasMemory = true
|
||||
spec.Memory.Reservation = readUInt64(memoryRoot, "memory.high")
|
||||
spec.Memory.Limit = readUInt64(memoryRoot, "memory.max")
|
||||
spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.swap.max")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +167,11 @@ func GetSpec(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoF
|
||||
spec.HasNetwork = hasNetwork
|
||||
spec.HasFilesystem = hasFilesystem
|
||||
|
||||
if blkioRoot, ok := cgroupPaths["blkio"]; ok && utils.FileExists(blkioRoot) {
|
||||
ioControllerName := "blkio"
|
||||
if cgroups.IsCgroup2UnifiedMode() {
|
||||
ioControllerName = "io"
|
||||
}
|
||||
if blkioRoot, ok := cgroupPaths[ioControllerName]; ok && utils.FileExists(blkioRoot) {
|
||||
spec.HasDiskIo = true
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ func GetCgroupSubsystems(includedMetrics container.MetricSet) (CgroupSubsystems,
|
||||
//currently we only support disable blkio subsystem
|
||||
if !includedMetrics.Has(container.DiskIOMetrics) {
|
||||
disableCgroups["blkio"] = struct{}{}
|
||||
disableCgroups["io"] = struct{}{}
|
||||
}
|
||||
return getCgroupSubsystemsHelper(allCgroups, disableCgroups)
|
||||
}
|
||||
@ -109,6 +110,7 @@ var supportedSubsystems map[string]struct{} = map[string]struct{}{
|
||||
"pids": {},
|
||||
"cpuset": {},
|
||||
"blkio": {},
|
||||
"io": {},
|
||||
"devices": {},
|
||||
}
|
||||
|
||||
|
@ -185,6 +185,9 @@ func (c *containerData) getCgroupPath(cgroups string) (string, error) {
|
||||
if cgroups == "-" {
|
||||
return "/", nil
|
||||
}
|
||||
if strings.HasPrefix(cgroups, "0::") {
|
||||
return cgroups[3:], nil
|
||||
}
|
||||
matches := cgroupPathRegExp.FindSubmatch([]byte(cgroups))
|
||||
if len(matches) != 2 {
|
||||
klog.V(3).Infof("failed to get memory cgroup path from %q", cgroups)
|
||||
|
@ -918,13 +918,15 @@ func (m *manager) createContainerLocked(containerName string, watchSource watche
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
devicesCgroupPath, err := handler.GetCgroupPath("devices")
|
||||
if err != nil {
|
||||
klog.Warningf("Error getting devices cgroup path: %v", err)
|
||||
} else {
|
||||
cont.nvidiaCollector, err = m.nvidiaManager.GetCollector(devicesCgroupPath)
|
||||
if !cgroups.IsCgroup2UnifiedMode() {
|
||||
devicesCgroupPath, err := handler.GetCgroupPath("devices")
|
||||
if err != nil {
|
||||
klog.V(4).Infof("GPU metrics may be unavailable/incomplete for container %q: %v", cont.info.Name, err)
|
||||
klog.Warningf("Error getting devices cgroup path: %v", err)
|
||||
} else {
|
||||
cont.nvidiaCollector, err = m.nvidiaManager.GetCollector(devicesCgroupPath)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("GPU metrics may be unavailable/incomplete for container %q: %v", cont.info.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,6 +264,10 @@ function drawCpuPerCoreUsage(elementId, machineInfo, stats) {
|
||||
var prev = stats.stats[i - 1];
|
||||
var intervalNs = getInterval(cur.timestamp, prev.timestamp);
|
||||
|
||||
if (cur.cpu.usage.per_cpu_usage == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var elements = [];
|
||||
elements.push(cur.timestamp);
|
||||
for (var j = 0; j < machineInfo.num_cores; j++) {
|
||||
|
File diff suppressed because one or more lines are too long
@ -139,7 +139,7 @@ func validateCpuCfsBandwidth(available_cgroups map[string]int) string {
|
||||
if !ok {
|
||||
return "\tCpu cfs bandwidth status unknown: cpu cgroup not enabled.\n"
|
||||
}
|
||||
mnt, err := cgroups.FindCgroupMountpoint("cpu")
|
||||
mnt, err := cgroups.FindCgroupMountpoint("/", "cpu")
|
||||
if err != nil {
|
||||
return "\tCpu cfs bandwidth status unknown: cpu cgroup not mounted.\n"
|
||||
}
|
||||
@ -156,7 +156,7 @@ func validateMemoryAccounting(available_cgroups map[string]int) string {
|
||||
if !ok {
|
||||
return "\tHierarchical memory accounting status unknown: memory cgroup not enabled.\n"
|
||||
}
|
||||
mnt, err := cgroups.FindCgroupMountpoint("memory")
|
||||
mnt, err := cgroups.FindCgroupMountpoint("/", "memory")
|
||||
if err != nil {
|
||||
return "\tHierarchical memory accounting status unknown: memory cgroup not mounted.\n"
|
||||
}
|
||||
@ -216,7 +216,7 @@ func validateDockerInfo() (string, string) {
|
||||
func validateCgroupMounts() (string, string) {
|
||||
const recommendedMount = "/sys/fs/cgroup"
|
||||
desc := fmt.Sprintf("\tAny cgroup mount point that is detectible and accessible is supported. %s is recommended as a standard location.\n", recommendedMount)
|
||||
mnt, err := cgroups.FindCgroupMountpoint("cpu")
|
||||
mnt, err := cgroups.FindCgroupMountpoint("/", "cpu")
|
||||
if err != nil {
|
||||
out := "Could not locate cgroup mount point.\n"
|
||||
out += desc
|
||||
|
Loading…
Reference in New Issue
Block a user