You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// TODO(filbranden): This logic belongs in libcontainer/cgroup/systemd instead.
Copyright2016TheKubernetes Authors.
LicensedundertheApacheLicense, Version2.0 (the"License");
youmaynotusethisfileexceptincompliancewiththe License.
YoumayobtainacopyoftheLicenseathttp://www.apache.org/licenses/LICENSE-2.0Unlessrequiredbyapplicablelaworagreedtoinwriting, softwaredistributedundertheLicenseisdistributedonan"AS IS"BASIS,
WITHOUTWARRANTIESORCONDITIONSOFANYKIND, eitherexpressor implied.
SeetheLicenseforthespecificlanguagegoverningpermissionsandlimitationsundertheLicense.
*/packagecmimport (
"fmt""io/ioutil""os""path""path/filepath""strings""sync""time"libcontainercgroups"github.com/opencontainers/runc/libcontainer/cgroups"cgroupfs"github.com/opencontainers/runc/libcontainer/cgroups/fs"cgroupfs2"github.com/opencontainers/runc/libcontainer/cgroups/fs2"cgroupsystemd"github.com/opencontainers/runc/libcontainer/cgroups/systemd"libcontainerconfigs"github.com/opencontainers/runc/libcontainer/configs""k8s.io/klog/v2"v1helper"k8s.io/kubernetes/pkg/apis/core/v1/helper"utilruntime"k8s.io/apimachinery/pkg/util/runtime""k8s.io/apimachinery/pkg/util/sets"cmutil"k8s.io/kubernetes/pkg/kubelet/cm/util""k8s.io/kubernetes/pkg/kubelet/metrics"
)
// libcontainerCgroupManagerType defines how to interface with libcontainertypelibcontainerCgroupManagerTypestringconst (
// libcontainerCgroupfs means use libcontainer with cgroupfslibcontainerCgroupfslibcontainerCgroupManagerType="cgroupfs"// libcontainerSystemd means use libcontainer with systemdlibcontainerSystemdlibcontainerCgroupManagerType="systemd"// systemdSuffix is the cgroup name suffix for systemdsystemdSuffixstring=".slice"
)
varRootCgroupName=CgroupName([]string{})
// NewCgroupName composes a new cgroup name.// Use RootCgroupName as base to start at the root.// This function does some basic check for invalid characters at the name.funcNewCgroupName(baseCgroupName, components...string) CgroupName {
for_, component:=rangecomponents {
// Forbit using "_" in internal names. When remapping internal// names to systemd cgroup driver, we want to remap "-" => "_",// so we forbid "_" so that we can always reverse the mapping.ifstrings.Contains(component, "/") ||strings.Contains(component, "_") {
panic(fmt.Errorf("invalid character in component [%q] of CgroupName", component))
}
}
returnCgroupName(append(append([]string{}, base...), components...))
}
funcescapeSystemdCgroupName(partstring) string {
returnstrings.Replace(part, "-", "_", -1)
}
funcunescapeSystemdCgroupName(partstring) string {
returnstrings.Replace(part, "_", "-", -1)
}
// cgroupName.ToSystemd converts the internal cgroup name to a systemd name.// For example, the name {"kubepods", "burstable", "pod1234-abcd-5678-efgh"} becomes// "/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod1234_abcd_5678_efgh.slice"// This function always expands the systemd name into the cgroupfs form. If only// the last part is needed, use path.Base(...) on it to discard the rest.func (cgroupNameCgroupName) ToSystemd() string {
iflen(cgroupName) ==0|| (len(cgroupName) ==1&&cgroupName[0] =="") {
return"/"
}
newparts:= []string{}
for_, part:=rangecgroupName {
part=escapeSystemdCgroupName(part)
newparts=append(newparts, part)
}
result, err:=cgroupsystemd.ExpandSlice(strings.Join(newparts, "-") +systemdSuffix)
iferr!=nil {
// Should never happen...panic(fmt.Errorf("error converting cgroup name [%v] to systemd format: %v", cgroupName, err))
}
returnresult
}
funcParseSystemdToCgroupName(namestring) CgroupName {
driverName:=path.Base(name)
driverName=strings.TrimSuffix(driverName, systemdSuffix)
parts:=strings.Split(driverName, "-")
result:= []string{}
for_, part:=rangeparts {
result=append(result, unescapeSystemdCgroupName(part))
}
returnCgroupName(result)
}
func (cgroupNameCgroupName) ToCgroupfs() string {
return"/"+path.Join(cgroupName...)
}
funcParseCgroupfsToCgroupName(namestring) CgroupName {
components:=strings.Split(strings.TrimPrefix(name, "/"), "/")
iflen(components) ==1&&components[0] =="" {
components= []string{}
}
returnCgroupName(components)
}
funcIsSystemdStyleName(namestring) bool {
returnstrings.HasSuffix(name, systemdSuffix)
}
// libcontainerAdapter provides a simplified interface to libcontainer based on libcontainer type.typelibcontainerAdapterstruct {
// cgroupManagerType defines how to interface with libcontainercgroupManagerTypelibcontainerCgroupManagerType
}
// newLibcontainerAdapter returns a configured libcontainerAdapter for specified manager.// it does any initialization required by that manager to function.funcnewLibcontainerAdapter(cgroupManagerTypelibcontainerCgroupManagerType) *libcontainerAdapter {
return&libcontainerAdapter{cgroupManagerType: cgroupManagerType}
}
// newManager returns an implementation of cgroups.Managerfunc (l*libcontainerAdapter) newManager(cgroups*libcontainerconfigs.Cgroup, pathsmap[string]string) (libcontainercgroups.Manager, error) {
switchl.cgroupManagerType {
caselibcontainerCgroupfs:
iflibcontainercgroups.IsCgroup2UnifiedMode() {
returncgroupfs2.NewManager(cgroups, paths["memory"], false)
}
returncgroupfs.NewManager(cgroups, paths, false), nilcaselibcontainerSystemd:
// this means you asked systemd to manage cgroups, but systemd was not on the host, so all you can do is panic...if!cgroupsystemd.IsRunningSystemd() {
panic("systemd cgroup manager not available")
}
iflibcontainercgroups.IsCgroup2UnifiedMode() {
returncgroupsystemd.NewUnifiedManager(cgroups, paths["memory"], false), nil
}
returncgroupsystemd.NewLegacyManager(cgroups, paths), nil
}
returnnil, fmt.Errorf("invalid cgroup manager configuration")
}
// CgroupSubsystems holds information about the mounted cgroup subsystemstypeCgroupSubsystemsstruct {
// Cgroup subsystem mounts.// e.g.: "/sys/fs/cgroup/cpu" -> ["cpu", "cpuacct"]Mounts []libcontainercgroups.Mount// Cgroup subsystem to their mount location.// e.g.: "cpu" -> "/sys/fs/cgroup/cpu"MountPointsmap[string]string
}
// 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.typecgroupManagerImplstruct {
// subsystems holds information about all the// mounted cgroup subsystems on the nodesubsystems*CgroupSubsystems// simplifies interaction with libcontainer and its cgroup managersadapter*libcontainerAdapter
}
// Make sure that cgroupManagerImpl implements the CgroupManager interfacevar_CgroupManager=&cgroupManagerImpl{}
// NewCgroupManager is a factory method that returns a CgroupManagerfuncNewCgroupManager(cs*CgroupSubsystems, cgroupDriverstring) CgroupManager {
managerType:=libcontainerCgroupfsifcgroupDriver==string(libcontainerSystemd) {
managerType=libcontainerSystemd
}
return&cgroupManagerImpl{
subsystems: cs,
adapter: newLibcontainerAdapter(managerType),
}
}
// Name converts the cgroup to the driver specific value in cgroupfs form.// This always returns a valid cgroupfs path even when systemd driver is in use!func (m*cgroupManagerImpl) Name(nameCgroupName) string {
ifm.adapter.cgroupManagerType==libcontainerSystemd {
returnname.ToSystemd()
}
returnname.ToCgroupfs()
}
// CgroupName converts the literal cgroupfs name on the host to an internal identifier.func (m*cgroupManagerImpl) CgroupName(namestring) CgroupName {
ifm.adapter.cgroupManagerType==libcontainerSystemd {
returnParseSystemdToCgroupName(name)
}
returnParseCgroupfsToCgroupName(name)
}
// buildCgroupPaths builds a path to each cgroup subsystem for the specified name.func (m*cgroupManagerImpl) buildCgroupPaths(nameCgroupName) map[string]string {
cgroupFsAdaptedName:=m.Name(name)
cgroupPaths:=make(map[string]string, len(m.subsystems.MountPoints))
forkey, val:=rangem.subsystems.MountPoints {
cgroupPaths[key] =path.Join(val, cgroupFsAdaptedName)
}
returncgroupPaths
}
// buildCgroupUnifiedPath builds a path to the specified name.func (m*cgroupManagerImpl) buildCgroupUnifiedPath(nameCgroupName) string {
cgroupFsAdaptedName:=m.Name(name)
returnpath.Join(cmutil.CgroupRoot, cgroupFsAdaptedName)
}
// TODO(filbranden): This logic belongs in libcontainer/cgroup/systemd instead.// It should take a libcontainerconfigs.Cgroup.Path field (rather than Name and Parent)// and split it appropriately, using essentially the logic below.// This was done for cgroupfs in opencontainers/runc#497 but a counterpart// for systemd was never introduced.funcupdateSystemdCgroupInfo(cgroupConfig*libcontainerconfigs.Cgroup, cgroupNameCgroupName) {
dir, base:=path.Split(cgroupName.ToSystemd())
ifdir=="/" {
dir="-.slice"
} else {
dir=path.Base(dir)
}
cgroupConfig.Parent=dircgroupConfig.Name=base
}
// Exists checks if all subsystem cgroups already existfunc (m*cgroupManagerImpl) Exists(nameCgroupName) bool {
iflibcontainercgroups.IsCgroup2UnifiedMode() {
cgroupPath:=m.buildCgroupUnifiedPath(name)
neededControllers:=getSupportedUnifiedControllers()
enabledControllers, err:=readUnifiedControllers(cgroupPath)
iferr!=nil {
returnfalse
}
difference:=neededControllers.Difference(enabledControllers)
ifdifference.Len() >0 {
klog.V(4).Infof("The Cgroup %v has some missing controllers: %v", name, difference)
returnfalse
}
returntrue
}
// Get map of all cgroup paths on the system for the particular cgroupcgroupPaths:=m.buildCgroupPaths(name)
// the presence of alternative control groups not known to runc confuses// the kubelet existence checks.// ideally, we would have a mechanism in runc to support Exists() logic// scoped to the set control groups it understands. this is being discussed// in /~https://github.com/opencontainers/runc/issues/1440// once resolved, we can remove this code.whitelistControllers:=sets.NewString("cpu", "cpuacct", "cpuset", "memory", "systemd", "pids")
if_, ok:=m.subsystems.MountPoints["hugetlb"]; ok {
whitelistControllers.Insert("hugetlb")
}
varmissingPaths []string// If even one cgroup path doesn't exist, then the cgroup doesn't exist.forcontroller, path:=rangecgroupPaths {
// ignore mounts we don't care aboutif!whitelistControllers.Has(controller) {
continue
}
if!libcontainercgroups.PathExists(path) {
missingPaths=append(missingPaths, path)
}
}
iflen(missingPaths) >0 {
klog.V(4).Infof("The Cgroup %v has some missing paths: %v", name, missingPaths)
returnfalse
}
returntrue
}
// Destroy destroys the specified cgroupfunc (m*cgroupManagerImpl) Destroy(cgroupConfig*CgroupConfig) error {
start:=time.Now()
deferfunc() {
metrics.CgroupManagerDuration.WithLabelValues("destroy").Observe(metrics.SinceInSeconds(start))
}()
cgroupPaths:=m.buildCgroupPaths(cgroupConfig.Name)
libcontainerCgroupConfig:=&libcontainerconfigs.Cgroup{}
// libcontainer consumes a different field and expects a different syntax// depending on the cgroup driver in use, so we need this conditional here.ifm.adapter.cgroupManagerType==libcontainerSystemd {
updateSystemdCgroupInfo(libcontainerCgroupConfig, cgroupConfig.Name)
} else {
libcontainerCgroupConfig.Path=cgroupConfig.Name.ToCgroupfs()
}
manager, err:=m.adapter.newManager(libcontainerCgroupConfig, cgroupPaths)
iferr!=nil {
returnerr
}
// Delete cgroups using libcontainers Managers Destroy() methodiferr=manager.Destroy(); err!=nil {
returnfmt.Errorf("unable to destroy cgroup paths for cgroup %v : %v", cgroupConfig.Name, err)
}
returnnil
}
typesubsysteminterface {
// Name returns the name of the subsystem.Name() string// Set the cgroup represented by cgroup.Set(pathstring, cgroup*libcontainerconfigs.Cgroup) error// GetStats returns the statistics associated with the cgroupGetStats(pathstring, stats*libcontainercgroups.Stats) error
}
// getSupportedSubsystems returns a map of subsystem and if it must be mounted for the kubelet to function.funcgetSupportedSubsystems() map[subsystem]bool {
supportedSubsystems:=map[subsystem]bool{
&cgroupfs.MemoryGroup{}: true,
&cgroupfs.CpuGroup{}: true,
&cgroupfs.PidsGroup{}: true,
}
// not all hosts support hugetlb cgroup, and in the absent of hugetlb, we will fail silently by reporting no capacity.supportedSubsystems[&cgroupfs.HugetlbGroup{}] =falsereturnsupportedSubsystems
}
// setSupportedSubsystemsV1 sets cgroup resource limits on cgroup v1 only on the supported// subsystems. ie. cpu and memory. We don't use libcontainer's cgroup/fs/Set()// method as it doesn't allow us to skip updates on the devices cgroup// Allowing or denying all devices by writing 'a' to devices.allow or devices.deny is// not possible once the device cgroups has children. Once the pod level cgroup are// created under the QOS level cgroup we cannot update the QOS level device cgroup.// We would like to skip setting any values on the device cgroup in this case// but this is not possible with libcontainers Set() method// See /~https://github.com/opencontainers/runc/issues/932funcsetSupportedSubsystemsV1(cgroupConfig*libcontainerconfigs.Cgroup) error {
forsys, required:=rangegetSupportedSubsystems() {
if_, ok:=cgroupConfig.Paths[sys.Name()]; !ok {
ifrequired {
returnfmt.Errorf("failed to find subsystem mount for required subsystem: %v", sys.Name())
}
// the cgroup is not mounted, but its not required so continue...klog.V(6).Infof("Unable to find subsystem mount for optional subsystem: %v", sys.Name())
continue
}
iferr:=sys.Set(cgroupConfig.Paths[sys.Name()], cgroupConfig); err!=nil {
returnfmt.Errorf("failed to set config for supported subsystems : %v", err)
}
}
returnnil
}
// getCpuWeight converts from the range [2, 262144] to [1, 10000]funcgetCpuWeight(cpuShares*uint64) uint64 {
ifcpuShares==nil {
return0
}
if*cpuShares>=262144 {
return10000
}
return1+ ((*cpuShares-2)*9999)/262142
}
// readUnifiedControllers reads the controllers available at the specified cgroupfuncreadUnifiedControllers(pathstring) (sets.String, error) {
controllersFileContent, err:=ioutil.ReadFile(filepath.Join(path, "cgroup.controllers"))
iferr!=nil {
returnnil, err
}
controllers:=strings.Fields(string(controllersFileContent))
returnsets.NewString(controllers...), nil
}
var (
availableRootControllersOnce sync.OnceavailableRootControllers sets.String
)
// getSupportedUnifiedControllers returns a set of supported controllers when running on cgroup v2funcgetSupportedUnifiedControllers() sets.String {
// This is the set of controllers used by the KubeletsupportedControllers:=sets.NewString("cpu", "cpuset", "memory", "hugetlb", "pids")
// Memoize the set of controllers that are present in the root cgroupavailableRootControllersOnce.Do(func() {
varerrerroravailableRootControllers, err=readUnifiedControllers(cmutil.CgroupRoot)
iferr!=nil {
panic(fmt.Errorf("cannot read cgroup controllers at %s", cmutil.CgroupRoot))
}
})
// Return the set of controllers that are supported both by the Kubelet and by the kernelreturnsupportedControllers.Intersection(availableRootControllers)
}
// propagateControllers on an unified hierarchy enables all the supported controllers for the specified cgroupfuncpropagateControllers(pathstring) error {
iferr:=os.MkdirAll(filepath.Join(cmutil.CgroupRoot, path), 0755); err!=nil {
returnfmt.Errorf("failed to create cgroup %q : %v", path, err)
}
// Retrieve all the supported controllers from the cgroup rootcontrollersFileContent, err:=ioutil.ReadFile(filepath.Join(cmutil.CgroupRoot, "cgroup.controllers"))
iferr!=nil {
returnfmt.Errorf("failed to read controllers from %q : %v", cmutil.CgroupRoot, err)
}
supportedControllers:=getSupportedUnifiedControllers()
// The retrieved content looks like: "cpuset cpu io memory hugetlb pids". Prepend each of the controllers// with '+', so we have something like "+cpuset +cpu +io +memory +hugetlb +pids"controllers:=""for_, controller:=rangestrings.Fields(string(controllersFileContent)) {
// ignore controllers we don't care aboutif!supportedControllers.Has(controller) {
continue
}
sep:=" +"ifcontrollers=="" {
sep="+"
}
controllers=controllers+sep+controller
}
current:=cmutil.CgroupRoot// Write the controllers list to each "cgroup.subtree_control" file until it reaches the parent cgroup.// For the /foo/bar/baz cgroup, controllers must be enabled sequentially in the files:// - /sys/fs/cgroup/foo/cgroup.subtree_control// - /sys/fs/cgroup/foo/bar/cgroup.subtree_controlfor_, p:=rangestrings.Split(filepath.Dir(path), "/") {
current=filepath.Join(current, p)
iferr:=ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), []byte(controllers), 0755); err!=nil {
returnfmt.Errorf("failed to enable controllers on %q: %v", cmutil.CgroupRoot, err)
}
}
returnnil
}
// setResourcesV2 sets cgroup resource limits on cgroup v2funcsetResourcesV2(cgroupConfig*libcontainerconfigs.Cgroup) error {
iferr:=propagateControllers(cgroupConfig.Path); err!=nil {
returnerr
}
cgroupConfig.Resources.Devices= []*libcontainerconfigs.DeviceRule{
{
Type: 'a',
Permissions: "rwm",
Allow: true,
Minor: libcontainerconfigs.Wildcard,
Major: libcontainerconfigs.Wildcard,
},
}
cgroupConfig.Resources.SkipDevices=true// if the hugetlb controller is missingsupportedControllers:=getSupportedUnifiedControllers()
if!supportedControllers.Has("hugetlb") {
cgroupConfig.Resources.HugetlbLimit=nil// the cgroup is not present, but its not required so skip itklog.V(6).Infof("Optional subsystem not supported: hugetlb")
}
manager, err:=cgroupfs2.NewManager(cgroupConfig, filepath.Join(cmutil.CgroupRoot, cgroupConfig.Path), false)
iferr!=nil {
returnfmt.Errorf("failed to create cgroup v2 manager: %v", err)
}
config:=&libcontainerconfigs.Config{
Cgroups: cgroupConfig,
}
returnmanager.Set(config)
}
func (m*cgroupManagerImpl) toResources(resourceConfig*ResourceConfig) *libcontainerconfigs.Resources {
resources:=&libcontainerconfigs.Resources{
Devices: []*libcontainerconfigs.DeviceRule{
{
Type: 'a',
Permissions: "rwm",
Allow: true,
Minor: libcontainerconfigs.Wildcard,
Major: libcontainerconfigs.Wildcard,
},
},
SkipDevices: true,
}
ifresourceConfig==nil {
returnresources
}
ifresourceConfig.Memory!=nil {
resources.Memory=*resourceConfig.Memory
}
ifresourceConfig.CpuShares!=nil {
iflibcontainercgroups.IsCgroup2UnifiedMode() {
resources.CpuWeight=getCpuWeight(resourceConfig.CpuShares)
} else {
resources.CpuShares=*resourceConfig.CpuShares
}
}
ifresourceConfig.CpuQuota!=nil {
resources.CpuQuota=*resourceConfig.CpuQuota
}
ifresourceConfig.CpuPeriod!=nil {
resources.CpuPeriod=*resourceConfig.CpuPeriod
}
ifresourceConfig.PidsLimit!=nil {
resources.PidsLimit=*resourceConfig.PidsLimit
}
// if huge pages are enabled, we set them in libcontainer// for each page size enumerated, set that valuepageSizes:=sets.NewString()
forpageSize, limit:=rangeresourceConfig.HugePageLimit {
sizeString, err:=v1helper.HugePageUnitSizeFromByteSize(pageSize)
iferr!=nil {
klog.Warningf("pageSize is invalid: %v", err)
continue
}
resources.HugetlbLimit=append(resources.HugetlbLimit, &libcontainerconfigs.HugepageLimit{
Pagesize: sizeString,
Limit: uint64(limit),
})
pageSizes.Insert(sizeString)
}
// for each page size omitted, limit to 0for_, pageSize:=rangecgroupfs.HugePageSizes {
ifpageSizes.Has(pageSize) {
continue
}
resources.HugetlbLimit=append(resources.HugetlbLimit, &libcontainerconfigs.HugepageLimit{
Pagesize: pageSize,
Limit: uint64(0),
})
}
returnresources
}
// Update updates the cgroup with the specified Cgroup Configurationfunc (m*cgroupManagerImpl) Update(cgroupConfig*CgroupConfig) error {
start:=time.Now()
deferfunc() {
metrics.CgroupManagerDuration.WithLabelValues("update").Observe(metrics.SinceInSeconds(start))
}()
// Extract the cgroup resource parametersresourceConfig:=cgroupConfig.ResourceParametersresources:=m.toResources(resourceConfig)
libcontainerCgroupConfig:=&libcontainerconfigs.Cgroup{
Resources: resources,
}
unified:=libcontainercgroups.IsCgroup2UnifiedMode()
ifunified {
libcontainerCgroupConfig.Path=cgroupConfig.Name.ToCgroupfs()
} else {
libcontainerCgroupConfig.Paths=m.buildCgroupPaths(cgroupConfig.Name)
}
// libcontainer consumes a different field and expects a different syntax// depending on the cgroup driver in use, so we need this conditional here.ifm.adapter.cgroupManagerType==libcontainerSystemd {
updateSystemdCgroupInfo(libcontainerCgroupConfig, cgroupConfig.Name)
}
ifcgroupConfig.ResourceParameters!=nil&&cgroupConfig.ResourceParameters.PidsLimit!=nil {
libcontainerCgroupConfig.PidsLimit=*cgroupConfig.ResourceParameters.PidsLimit
}
ifunified {
iferr:=setResourcesV2(libcontainerCgroupConfig); err!=nil {
returnfmt.Errorf("failed to set resources for cgroup %v: %v", cgroupConfig.Name, err)
}
} else {
iferr:=setSupportedSubsystemsV1(libcontainerCgroupConfig); err!=nil {
returnfmt.Errorf("failed to set supported cgroup subsystems for cgroup %v: %v", cgroupConfig.Name, err)
}
}
returnnil
}
// Create creates the specified cgroupfunc (m*cgroupManagerImpl) Create(cgroupConfig*CgroupConfig) error {
start:=time.Now()
deferfunc() {
metrics.CgroupManagerDuration.WithLabelValues("create").Observe(metrics.SinceInSeconds(start))
}()
resources:=m.toResources(cgroupConfig.ResourceParameters)
libcontainerCgroupConfig:=&libcontainerconfigs.Cgroup{
Resources: resources,
}
// libcontainer consumes a different field and expects a different syntax// depending on the cgroup driver in use, so we need this conditional here.ifm.adapter.cgroupManagerType==libcontainerSystemd {
updateSystemdCgroupInfo(libcontainerCgroupConfig, cgroupConfig.Name)
} else {
libcontainerCgroupConfig.Path=cgroupConfig.Name.ToCgroupfs()
}
ifcgroupConfig.ResourceParameters!=nil&&cgroupConfig.ResourceParameters.PidsLimit!=nil {
libcontainerCgroupConfig.PidsLimit=*cgroupConfig.ResourceParameters.PidsLimit
}
// get the manager with the specified cgroup configurationmanager, err:=m.adapter.newManager(libcontainerCgroupConfig, nil)
iferr!=nil {
returnerr
}
// Apply(-1) is a hack to create the cgroup directories for each resource// subsystem. The function [cgroups.Manager.apply()] applies cgroup// configuration to the process with the specified pid.// It creates cgroup files for each subsystems and writes the pid// in the tasks file. We use the function to create all the required// cgroup files but not attach any "real" pid to the cgroup.iferr:=manager.Apply(-1); err!=nil {
returnerr
}
// it may confuse why we call set after we do apply, but the issue is that runc// follows a similar pattern. it's needed to ensure cpu quota is set properly.iferr:=m.Update(cgroupConfig); err!=nil {
utilruntime.HandleError(fmt.Errorf("cgroup update failed %v", err))
}
returnnil
}
// Scans through all subsystems to find pids associated with specified cgroup.func (m*cgroupManagerImpl) Pids(nameCgroupName) []int {
// we need the driver specific namecgroupFsName:=m.Name(name)
// Get a list of processes that we need to killpidsToKill:=sets.NewInt()
varpids []intfor_, val:=rangem.subsystems.MountPoints {
dir:=path.Join(val, cgroupFsName)
_, err:=os.Stat(dir)
ifos.IsNotExist(err) {
// The subsystem pod cgroup is already deleted// do nothing, continuecontinue
}
// Get a list of pids that are still charged to the pod's cgrouppids, err=getCgroupProcs(dir)
iferr!=nil {
continue
}
pidsToKill.Insert(pids...)
// WalkFunc which is called for each file and directory in the pod cgroup dirvisitor:=func(pathstring, info os.FileInfo, errerror) error {
iferr!=nil {
klog.V(4).Infof("cgroup manager encountered error scanning cgroup path %q: %v", path, err)
returnfilepath.SkipDir
}
if!info.IsDir() {
returnnil
}
pids, err=getCgroupProcs(path)
iferr!=nil {
klog.V(4).Infof("cgroup manager encountered error getting procs for cgroup path %q: %v", path, err)
returnfilepath.SkipDir
}
pidsToKill.Insert(pids...)
returnnil
}
// Walk through the pod cgroup directory to check if// container cgroups haven't been GCed yet. Get attached processes to// all such unwanted containers under the pod cgroupiferr=filepath.Walk(dir, visitor); err!=nil {
klog.V(4).Infof("cgroup manager encountered error scanning pids for directory: %q: %v", dir, err)
}
}
returnpidsToKill.List()
}
// ReduceCPULimits reduces the cgroup's cpu shares to the lowest possible valuefunc (m*cgroupManagerImpl) ReduceCPULimits(cgroupNameCgroupName) error {
// Set lowest possible CpuShares value for the cgroupminimumCPUShares:=uint64(MinShares)
resources:=&ResourceConfig{
CpuShares: &minimumCPUShares,
}
containerConfig:=&CgroupConfig{
Name: cgroupName,
ResourceParameters: resources,
}
returnm.Update(containerConfig)
}
funcgetStatsSupportedSubsystems(cgroupPathsmap[string]string) (*libcontainercgroups.Stats, error) {
stats:=libcontainercgroups.NewStats()
forsys, required:=rangegetSupportedSubsystems() {
if_, ok:=cgroupPaths[sys.Name()]; !ok {
ifrequired {
returnnil, fmt.Errorf("failed to find subsystem mount for required subsystem: %v", sys.Name())
}
// the cgroup is not mounted, but its not required so continue...klog.V(6).Infof("Unable to find subsystem mount for optional subsystem: %v", sys.Name())
continue
}
iferr:=sys.GetStats(cgroupPaths[sys.Name()], stats); err!=nil {
returnnil, fmt.Errorf("failed to get stats for supported subsystems : %v", err)
}
}
returnstats, nil
}
functoResourceStats(stats*libcontainercgroups.Stats) *ResourceStats {
return&ResourceStats{
MemoryStats: &MemoryStats{
Usage: int64(stats.MemoryStats.Usage.Usage),
},
}
}
// Get sets the ResourceParameters of the specified cgroup as read from the cgroup fsfunc (m*cgroupManagerImpl) GetResourceStats(nameCgroupName) (*ResourceStats, error) {
varerrerrorvarstats*libcontainercgroups.Statsiflibcontainercgroups.IsCgroup2UnifiedMode() {
cgroupPath:=m.buildCgroupUnifiedPath(name)
manager, err:=cgroupfs2.NewManager(nil, cgroupPath, false)
iferr!=nil {
returnnil, fmt.Errorf("failed to create cgroup v2 manager: %v", err)
}
stats, err=manager.GetStats()
iferr!=nil {
returnnil, fmt.Errorf("failed to get stats for cgroup %v: %v", name, err)
}
} else {
cgroupPaths:=m.buildCgroupPaths(name)
stats, err=getStatsSupportedSubsystems(cgroupPaths)
iferr!=nil {
returnnil, fmt.Errorf("failed to get stats supported cgroup subsystems for cgroup %v: %v", name, err)
}
}
returntoResourceStats(stats), nil
}
ewfilemode100644ndex0000000000000..5c4a6b6392b61++b/pkg/kubelet/cm/cgroup_manager_linux_test.go
6e453f7549e77d4a94415d0f21eebea994bf6d63
The text was updated successfully, but these errors were encountered:
[filbranden] This logic belongs in libcontainer/cgroup/systemd instead.
It should take a libcontainerconfigs.Cgroup.Path field (rather than Name and Parent)
and split it appropriately, using essentially the logic below.
This was done for cgroupfs in opencontainers/runc#497 but a counterpart
for systemd was never introduced.
kubernetes/pkg/kubelet/cm/cgroup_manager_linux.go
Line 234 in dcda038
6e453f7549e77d4a94415d0f21eebea994bf6d63
The text was updated successfully, but these errors were encountered: