Skip to content

Commit 559b4c3

Browse files
DanielleMaywooddefelmnq
authored andcommitted
fix(cli): improve container detection when cgroupns=private (#15156)
Fixes #12721 If a container in docker is started with `--cgroupns=private` (which is the default behaviour in docker) then `/proc/1/cgroup` has the following content: ``` 0::/ ``` If a container in docker is started with `--cgroupns=host` then `/proc/1/cgroup` has the following content (hash will vary): ``` 0::/docker/aa86ac98959eeedeae0ecb6e0c9ddd8ae8b97a9d0fdccccf7ea7a474f4e0bb1f ``` Currently we are determining if a host is containerized by assuming the second scenario. This means the existing behaviour of sniffing `/proc/1/cgroup` is not always sufficient for checking if a host is containerized. According to [the cgroups(7) man-page](https://man7.org/linux/man-pages/man7/cgroups.7.html) there exists a `cgroup.type` file in a nonroot cgroup. This exists in Linux versions after `4.14`. > Linux 4.14 added thread mode for cgroups v2. > With the addition of thread mode, each nonroot cgroup now contains a new file, cgroup.type This means we can check for the existence of `/sys/fs/cgroup/cgroup.type` to see if we are in a container or not.
1 parent 6e26339 commit 559b4c3

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

cli/clistat/container.go

+12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
const (
1313
procMounts = "/proc/mounts"
1414
procOneCgroup = "/proc/1/cgroup"
15+
sysCgroupType = "/sys/fs/cgroup/cgroup.type"
1516
kubernetesDefaultServiceAccountToken = "/var/run/secrets/kubernetes.io/serviceaccount/token" //nolint:gosec
1617
)
1718

@@ -65,6 +66,17 @@ func IsContainerized(fs afero.Fs) (ok bool, err error) {
6566
}
6667
}
6768

69+
// Adapted from https://github.com/systemd/systemd/blob/88bbf187a9b2ebe0732caa1e886616ae5f8186da/src/basic/virt.c#L603-L605
70+
// The file `/sys/fs/cgroup/cgroup.type` does not exist on the root cgroup.
71+
// If this file exists we can be sure we're in a container.
72+
cgTypeExists, err := afero.Exists(fs, sysCgroupType)
73+
if err != nil {
74+
return false, xerrors.Errorf("check file exists %s: %w", sysCgroupType, err)
75+
}
76+
if cgTypeExists {
77+
return true, nil
78+
}
79+
6880
// If we get here, we are _probably_ not running in a container.
6981
return false, nil
7082
}

cli/clistat/stat_internal_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,12 @@ func TestIsContainerized(t *testing.T) {
309309
Expected: true,
310310
Error: "",
311311
},
312+
{
313+
Name: "Docker (Cgroupns=private)",
314+
FS: fsContainerCgroupV2PrivateCgroupns,
315+
Expected: true,
316+
Error: "",
317+
},
312318
} {
313319
tt := tt
314320
t.Run(tt.Name, func(t *testing.T) {
@@ -374,6 +380,12 @@ proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
374380
cgroupV2MemoryUsageBytes: "536870912",
375381
cgroupV2MemoryStat: "inactive_file 268435456",
376382
}
383+
fsContainerCgroupV2PrivateCgroupns = map[string]string{
384+
procOneCgroup: "0::/",
385+
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0
386+
proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
387+
sysCgroupType: "domain",
388+
}
377389
fsContainerCgroupV1 = map[string]string{
378390
procOneCgroup: "0::/docker/aa86ac98959eeedeae0ecb6e0c9ddd8ae8b97a9d0fdccccf7ea7a474f4e0bb1f",
379391
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0

0 commit comments

Comments
 (0)