mirror of https://github.com/containers/podman.git
Merge pull request #12403 from giuseppe/improve-cgroup-detection
libpod: improve heuristic to detect cgroup
This commit is contained in:
commit
12f73d5f88
|
@ -6,9 +6,11 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
types040 "github.com/containernetworking/cni/pkg/types/040"
|
types040 "github.com/containernetworking/cni/pkg/types/040"
|
||||||
|
"github.com/containers/common/pkg/config"
|
||||||
"github.com/containers/common/pkg/secrets"
|
"github.com/containers/common/pkg/secrets"
|
||||||
"github.com/containers/image/v5/manifest"
|
"github.com/containers/image/v5/manifest"
|
||||||
"github.com/containers/podman/v3/libpod/define"
|
"github.com/containers/podman/v3/libpod/define"
|
||||||
|
@ -963,6 +965,29 @@ func (c *Container) cGroupPath() (string, error) {
|
||||||
return "", errors.Errorf("could not find any cgroup in %q", procPath)
|
return "", errors.Errorf("could not find any cgroup in %q", procPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cgroupManager := c.CgroupManager()
|
||||||
|
switch {
|
||||||
|
case c.config.CgroupsMode == cgroupSplit:
|
||||||
|
name := fmt.Sprintf("/libpod-payload-%s/", c.ID())
|
||||||
|
if index := strings.LastIndex(cgroupPath, name); index >= 0 {
|
||||||
|
return cgroupPath[:index+len(name)-1], nil
|
||||||
|
}
|
||||||
|
case cgroupManager == config.CgroupfsCgroupsManager:
|
||||||
|
name := fmt.Sprintf("/libpod-%s/", c.ID())
|
||||||
|
if index := strings.LastIndex(cgroupPath, name); index >= 0 {
|
||||||
|
return cgroupPath[:index+len(name)-1], nil
|
||||||
|
}
|
||||||
|
case cgroupManager == config.SystemdCgroupsManager:
|
||||||
|
// When running under systemd, try to detect the scope that was requested
|
||||||
|
// to be created. It improves the heuristic since we report the first
|
||||||
|
// cgroup that was created instead of the cgroup where PID 1 might have
|
||||||
|
// moved to.
|
||||||
|
name := fmt.Sprintf("/libpod-%s.scope/", c.ID())
|
||||||
|
if index := strings.LastIndex(cgroupPath, name); index >= 0 {
|
||||||
|
return cgroupPath[:index+len(name)-1], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cgroupPath, nil
|
return cgroupPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,16 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cgroupPath, err := c.cGroupPath()
|
||||||
|
if err != nil {
|
||||||
|
// Handle the case where the container is not running or has no cgroup.
|
||||||
|
if errors.Is(err, define.ErrNoCgroups) || errors.Is(err, define.ErrCtrStopped) {
|
||||||
|
cgroupPath = ""
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data := &define.InspectContainerData{
|
data := &define.InspectContainerData{
|
||||||
ID: config.ID,
|
ID: config.ID,
|
||||||
Created: config.CreatedTime,
|
Created: config.CreatedTime,
|
||||||
|
@ -116,6 +126,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
|
||||||
StartedAt: runtimeInfo.StartedTime,
|
StartedAt: runtimeInfo.StartedTime,
|
||||||
FinishedAt: runtimeInfo.FinishedTime,
|
FinishedAt: runtimeInfo.FinishedTime,
|
||||||
Checkpointed: runtimeInfo.Checkpointed,
|
Checkpointed: runtimeInfo.Checkpointed,
|
||||||
|
CgroupPath: cgroupPath,
|
||||||
},
|
},
|
||||||
Image: config.RootfsImageID,
|
Image: config.RootfsImageID,
|
||||||
ImageName: config.RootfsImageName,
|
ImageName: config.RootfsImageName,
|
||||||
|
|
|
@ -2618,7 +2618,7 @@ func (c *Container) getOCICgroupPath() (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return filepath.Join(selfCgroup, "container"), nil
|
return filepath.Join(selfCgroup, fmt.Sprintf("libpod-payload-%s", c.ID())), nil
|
||||||
case cgroupManager == config.SystemdCgroupsManager:
|
case cgroupManager == config.SystemdCgroupsManager:
|
||||||
// When the OCI runtime is set to use Systemd as a cgroup manager, it
|
// When the OCI runtime is set to use Systemd as a cgroup manager, it
|
||||||
// expects cgroups to be passed as follows:
|
// expects cgroups to be passed as follows:
|
||||||
|
|
|
@ -204,6 +204,7 @@ type InspectContainerState struct {
|
||||||
FinishedAt time.Time `json:"FinishedAt"`
|
FinishedAt time.Time `json:"FinishedAt"`
|
||||||
Health HealthCheckResults `json:"Health,omitempty"`
|
Health HealthCheckResults `json:"Health,omitempty"`
|
||||||
Checkpointed bool `json:"Checkpointed,omitempty"`
|
Checkpointed bool `json:"Checkpointed,omitempty"`
|
||||||
|
CgroupPath string `json:"CgroupPath,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Healthcheck returns the HealthCheckResults. This is used for old podman compat
|
// Healthcheck returns the HealthCheckResults. This is used for old podman compat
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
package libpod
|
package libpod
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
@ -68,7 +69,7 @@ func (c *Container) GetContainerStats(previousStats *define.ContainerStats) (*de
|
||||||
stats.AvgCPU = calculateAvgCPU(stats.CPU, previousStats.AvgCPU, previousStats.DataPoints)
|
stats.AvgCPU = calculateAvgCPU(stats.CPU, previousStats.AvgCPU, previousStats.DataPoints)
|
||||||
stats.DataPoints = previousStats.DataPoints + 1
|
stats.DataPoints = previousStats.DataPoints + 1
|
||||||
stats.MemUsage = cgroupStats.Memory.Usage.Usage
|
stats.MemUsage = cgroupStats.Memory.Usage.Usage
|
||||||
stats.MemLimit = getMemLimit(cgroupStats.Memory.Usage.Limit)
|
stats.MemLimit = c.getMemLimit()
|
||||||
stats.MemPerc = (float64(stats.MemUsage) / float64(stats.MemLimit)) * 100
|
stats.MemPerc = (float64(stats.MemUsage) / float64(stats.MemLimit)) * 100
|
||||||
stats.PIDs = 0
|
stats.PIDs = 0
|
||||||
if conState == define.ContainerStateRunning || conState == define.ContainerStatePaused {
|
if conState == define.ContainerStateRunning || conState == define.ContainerStatePaused {
|
||||||
|
@ -91,22 +92,29 @@ func (c *Container) GetContainerStats(previousStats *define.ContainerStats) (*de
|
||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMemory limit returns the memory limit for a given cgroup
|
// getMemory limit returns the memory limit for a container
|
||||||
// If the configured memory limit is larger than the total memory on the sys, the
|
func (c *Container) getMemLimit() uint64 {
|
||||||
// physical system memory size is returned
|
memLimit := uint64(math.MaxUint64)
|
||||||
func getMemLimit(cgroupLimit uint64) uint64 {
|
|
||||||
|
if c.config.Spec.Linux != nil && c.config.Spec.Linux.Resources != nil &&
|
||||||
|
c.config.Spec.Linux.Resources.Memory != nil && c.config.Spec.Linux.Resources.Memory.Limit != nil {
|
||||||
|
memLimit = uint64(*c.config.Spec.Linux.Resources.Memory.Limit)
|
||||||
|
}
|
||||||
|
|
||||||
si := &syscall.Sysinfo_t{}
|
si := &syscall.Sysinfo_t{}
|
||||||
err := syscall.Sysinfo(si)
|
err := syscall.Sysinfo(si)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cgroupLimit
|
return memLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unconvert
|
//nolint:unconvert
|
||||||
physicalLimit := uint64(si.Totalram)
|
physicalLimit := uint64(si.Totalram)
|
||||||
if cgroupLimit > physicalLimit {
|
|
||||||
|
if memLimit <= 0 || memLimit > physicalLimit {
|
||||||
return physicalLimit
|
return physicalLimit
|
||||||
}
|
}
|
||||||
return cgroupLimit
|
|
||||||
|
return memLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateCPUPercent calculates the cpu usage using the latest measurement in stats.
|
// calculateCPUPercent calculates the cpu usage using the latest measurement in stats.
|
||||||
|
|
|
@ -109,6 +109,11 @@ WantedBy=multi-user.target
|
||||||
stats := podmanTest.Podman([]string{"stats", "--no-stream", ctrName})
|
stats := podmanTest.Podman([]string{"stats", "--no-stream", ctrName})
|
||||||
stats.WaitWithDefaultTimeout()
|
stats.WaitWithDefaultTimeout()
|
||||||
Expect(stats).Should(Exit(0))
|
Expect(stats).Should(Exit(0))
|
||||||
|
|
||||||
|
cgroupPath := podmanTest.Podman([]string{"inspect", "--format='{{.State.CgroupPath}}'", ctrName})
|
||||||
|
cgroupPath.WaitWithDefaultTimeout()
|
||||||
|
Expect(cgroupPath).Should(Exit(0))
|
||||||
|
Expect(result.OutputToString()).To(Not(ContainSubstring("init.scope")))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman create container with systemd entrypoint triggers systemd mode", func() {
|
It("podman create container with systemd entrypoint triggers systemd mode", func() {
|
||||||
|
|
Loading…
Reference in New Issue