Skip to content

Commit

Permalink
cgroups/systemd: add cgroup-v2 path to the list when using hybrid mode
Browse files Browse the repository at this point in the history
Currently the parent process of the container is moved to the right
cgroup-v2 tree when systemd is using a hybrid model (last line with 0::):

$ runc --systemd-cgroup run myid
/ # cat /proc/self/cgroup
12:cpuset:/system.slice/runc-myid.scope
11:blkio:/system.slice/runc-myid.scope
10:devices:/system.slice/runc-myid.scope
9:hugetlb:/system.slice/runc-myid.scope
8:memory:/system.slice/runc-myid.scope
7:rdma:/
6:perf_event:/system.slice/runc-myid.scope
5:net_cls,net_prio:/system.slice/runc-myid.scope
4:freezer:/system.slice/runc-myid.scope
3:pids:/system.slice/runc-myid.scope
2:cpu,cpuacct:/system.slice/runc-myid.scope
1:name=systemd:/system.slice/runc-myid.scope
0::/system.slice/runc-myid.scope

However, if a second process is executed in the same container, it is
not moved to the right cgroup-v2 tree:

$ runc exec myid /bin/sh -c 'cat /proc/self/cgroup'
12:cpuset:/system.slice/runc-myid.scope
11:blkio:/system.slice/runc-myid.scope
10:devices:/system.slice/runc-myid.scope
9:hugetlb:/system.slice/runc-myid.scope
8:memory:/system.slice/runc-myid.scope
7:rdma:/
6:perf_event:/system.slice/runc-myid.scope
5:net_cls,net_prio:/system.slice/runc-myid.scope
4:freezer:/system.slice/runc-myid.scope
3:pids:/system.slice/runc-myid.scope
2:cpu,cpuacct:/system.slice/runc-myid.scope
1:name=systemd:/system.slice/runc-myid.scope
0::/user.slice/user-1000.slice/session-8.scope

Having the processes of the container in its own cgroup-v2 is useful
for any BPF programs that rely on bpf_get_current_cgroup_id(), like
https://github.com/kinvolk/inspektor-gadget/ for instance.

This commit makes that processes executed with exec are placed into the
right cgroup-v2 tree. The implementation checks if systemd is using a
hybrid mode (by checking if cgroups-v2 is mounted in
/sys/fs/cgroup/unified), if yes, the path of the cgroup-v2 slice for
this container is saved into the cgroup path list.

Signed-off-by: Mauricio Vásquez <[email protected]>
  • Loading branch information
mauriciovasquezbernal committed Feb 5, 2021
1 parent b4cb54c commit b9df855
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 0 deletions.
13 changes: 13 additions & 0 deletions libcontainer/cgroups/systemd/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,19 @@ func (m *legacyManager) Apply(pid int) error {
}
paths[s.Name()] = subsystemPath
}

// If systemd is using cgroups-hybrid mode then add the slice path of
// this container to the paths so the following process executed with
// "runc exec" joins that cgroup as well.
if cgroups.IsCgroup2HybridMode() {
// "" means cgroup-hybrid path
cgroupsHybridPath, err := getSubsystemPath(m.cgroups, "")
if err != nil && cgroups.IsNotFound(err) {
return err
}
paths[""] = cgroupsHybridPath
}

m.paths = paths

if err := m.joinCgroups(pid); err != nil {
Expand Down
21 changes: 21 additions & 0 deletions libcontainer/cgroups/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ import (
const (
CgroupProcesses = "cgroup.procs"
unifiedMountpoint = "/sys/fs/cgroup"
hybridMountpoint = "/sys/fs/cgroup/unified"
)

var (
isUnifiedOnce sync.Once
isUnified bool
isHybridOnce sync.Once
isHybrid bool
)

// IsCgroup2UnifiedMode returns whether we are running in cgroup v2 unified mode.
Expand All @@ -50,6 +53,24 @@ func IsCgroup2UnifiedMode() bool {
return isUnified
}

// IsCgroup2HybridMode returns whether we are running in cgroup v2 hybrid mode.
func IsCgroup2HybridMode() bool {
isHybridOnce.Do(func() {
var st unix.Statfs_t
err := unix.Statfs(hybridMountpoint, &st)
if err != nil {
if os.IsNotExist(err) {
// ignore the "not found" error
isHybrid = false
return
}
panic(fmt.Sprintf("cannot statfs cgroup root: %s", err))
}
isHybrid = st.Type == unix.CGROUP2_SUPER_MAGIC
})
return isHybrid
}

type Mount struct {
Mountpoint string
Root string
Expand Down
6 changes: 6 additions & 0 deletions libcontainer/cgroups/v1_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
return "", errUnified
}

// If subsystem is empty it means that we are looking for the
// cgroups2 path
if len(subsystem) == 0 {
return hybridMountpoint, nil
}

// Avoid parsing mountinfo by trying the default path first, if possible.
if path := tryDefaultPath(cgroupPath, subsystem); path != "" {
return path, nil
Expand Down

0 comments on commit b9df855

Please sign in to comment.