Skip to content

Commit 13f6645

Browse files
fix(cli): improve container detection when cgroupns=private (coder#15156)
Fixes coder#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 c5a4095 commit 13f6645

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

cli/clistat/container.go

Lines changed: 12 additions & 0 deletions
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

Lines changed: 12 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy