Skip to content

Commit 77f223d

Browse files
authored
Merge pull request #169 from coroot/cgroup_hybrid_mode
add support for hybrid cgroup mode with both V1 and V2 enabled
2 parents 75b0def + a73919b commit 77f223d

File tree

13 files changed

+142
-69
lines changed

13 files changed

+142
-69
lines changed

cgroup/cgroup.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import (
1414
)
1515

1616
var (
17-
cgRoot = *flags.CgroupRoot
17+
cgRoot = *flags.CgroupRoot
18+
cg2Root = *flags.CgroupRoot
1819

1920
baseCgroupPath = ""
2021

@@ -26,13 +27,6 @@ var (
2627
talosIdRegexp = regexp.MustCompile(`/(system|podruntime)/([^/]+)`)
2728
)
2829

29-
type Version uint8
30-
31-
const (
32-
V1 Version = iota
33-
V2
34-
)
35-
3630
type ContainerType uint8
3731

3832
const (
@@ -68,17 +62,23 @@ func (t ContainerType) String() string {
6862

6963
type Cgroup struct {
7064
Id string
71-
Version Version
7265
ContainerType ContainerType
7366
ContainerId string
7467

7568
subsystems map[string]string
7669
}
7770

7871
func (cg *Cgroup) CreatedAt() time.Time {
79-
p := path.Join(cgRoot, cg.subsystems[""]) //v2
80-
if cg.Version == V1 {
81-
p = path.Join(cgRoot, "cpu", cg.subsystems["cpu"])
72+
var p string
73+
if sp := cg.subsystems[""]; sp != "" { //v2
74+
p = path.Join(cg2Root, sp)
75+
} else if sp = cg.subsystems["cpu"]; sp != "" {
76+
p = path.Join(cgRoot, "cpu", sp)
77+
} else if sp = cg.subsystems["memory"]; sp != "" {
78+
p = path.Join(cgRoot, "memory", sp)
79+
}
80+
if p == "" {
81+
return time.Time{}
8282
}
8383
fi, err := os.Stat(p)
8484
if err != nil {
@@ -104,15 +104,22 @@ func NewFromProcessCgroupFile(filePath string) (*Cgroup, error) {
104104
continue
105105
}
106106
for _, cgType := range strings.Split(parts[1], ",") {
107-
cg.subsystems[cgType] = path.Join(baseCgroupPath, parts[2])
107+
p := path.Join(baseCgroupPath, parts[2])
108+
switch p {
109+
case "/", "/init.scope":
110+
continue
111+
}
112+
cg.subsystems[cgType] = p
108113
}
109114
}
110-
if cg.Id = cg.subsystems[""]; cg.Id != "" {
111-
cg.Version = V2
112-
} else if cg.Id = cg.subsystems["cpu"]; cg.Id != "" {
113-
cg.Version = V1
115+
cg.Id = cg.subsystems[""]
116+
if cg.Id == "" {
117+
cg.Id = cg.subsystems["cpu"]
118+
}
119+
if cg.Id == "" {
120+
cg.Id = cg.subsystems["memory"]
114121
}
115-
if (cg.Id == "" || cg.Id == "/") && cg.subsystems["name=systemd"] != "/" {
122+
if cg.Id == "" && cg.subsystems["name=systemd"] != "" {
116123
cg.Id = cg.subsystems["name=systemd"]
117124
}
118125
if cg.ContainerType, cg.ContainerId, err = containerByCgroup(cg.Id); err != nil {

cgroup/cgroup_linux.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package cgroup
22

33
import (
4+
"os"
5+
"path"
46
"runtime"
57

68
"github.com/vishvananda/netns"
79
"golang.org/x/sys/unix"
10+
"k8s.io/klog/v2"
811
)
912

1013
func Init() error {
@@ -18,25 +21,25 @@ func Init() error {
1821
return err
1922
}
2023
defer hostNs.Close()
21-
if selfNs.Equal(hostNs) {
22-
return nil
23-
}
24+
if !selfNs.Equal(hostNs) {
25+
runtime.LockOSThread()
26+
defer runtime.UnlockOSThread()
27+
if err := unix.Setns(int(hostNs), unix.CLONE_NEWCGROUP); err != nil {
28+
return err
29+
}
30+
cg, err := NewFromProcessCgroupFile("/proc/self/cgroup")
31+
if err != nil {
32+
return err
33+
}
34+
baseCgroupPath = cg.Id
2435

25-
runtime.LockOSThread()
26-
defer runtime.UnlockOSThread()
27-
if err := unix.Setns(int(hostNs), unix.CLONE_NEWCGROUP); err != nil {
28-
return err
36+
if err := unix.Setns(int(selfNs), unix.CLONE_NEWCGROUP); err != nil {
37+
return err
38+
}
2939
}
30-
31-
cg, err := NewFromProcessCgroupFile("/proc/self/cgroup")
32-
if err != nil {
33-
return err
40+
if _, err := os.Stat(path.Join(cgRoot, "unified")); err == nil {
41+
cg2Root = path.Join(cgRoot, "unified")
3442
}
35-
baseCgroupPath = cg.Id
36-
37-
if err := unix.Setns(int(selfNs), unix.CLONE_NEWCGROUP); err != nil {
38-
return err
39-
}
40-
43+
klog.Infoln("cgroup v2 root is", cg2Root)
4144
return nil
4245
}

cgroup/cgroup_test.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ func TestNewFromProcessCgroupFile(t *testing.T) {
1111
cg, err := NewFromProcessCgroupFile(path.Join("fixtures/proc/100/cgroup"))
1212
assert.Nil(t, err)
1313
assert.Equal(t, "/system.slice/docker.service", cg.Id)
14-
assert.Equal(t, V1, cg.Version)
1514
assert.Equal(t, "/system.slice/docker.service", cg.ContainerId)
1615
assert.Equal(t, ContainerTypeSystemdService, cg.ContainerType)
1716

@@ -20,65 +19,52 @@ func TestNewFromProcessCgroupFile(t *testing.T) {
2019
"blkio": "/system.slice/docker.service",
2120
"cpu": "/system.slice/docker.service",
2221
"cpuacct": "/system.slice/docker.service",
23-
"cpuset": "/",
2422
"devices": "/system.slice/docker.service",
25-
"freezer": "/",
26-
"hugetlb": "/",
2723
"memory": "/system.slice/docker.service",
2824
"name=systemd": "/system.slice/docker.service",
29-
"net_cls": "/",
30-
"net_prio": "/",
31-
"perf_event": "/",
3225
"pids": "/system.slice/docker.service",
3326
},
3427
cg.subsystems,
3528
)
3629

3730
cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/200/cgroup"))
3831
assert.Nil(t, err)
39-
assert.Equal(t, V1, cg.Version)
4032
assert.Equal(t, "/docker/b43d92bf1e5c6f78bb9b7bc6f40721280299855ba692092716e3a1b6c0b86f3f", cg.Id)
4133
assert.Equal(t, "b43d92bf1e5c6f78bb9b7bc6f40721280299855ba692092716e3a1b6c0b86f3f", cg.ContainerId)
4234
assert.Equal(t, ContainerTypeDocker, cg.ContainerType)
4335

4436
cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/300/cgroup"))
4537
assert.Nil(t, err)
46-
assert.Equal(t, V1, cg.Version)
4738
assert.Equal(t, "/kubepods/burstable/pod6a4ce4a0-ba47-11ea-b2a7-0cc47ac5979e/17db96a24ae1e9dd57143e62b1cb0d2d35e693c65c774c7470e87b0572e07c1a", cg.Id)
4839
assert.Equal(t, "17db96a24ae1e9dd57143e62b1cb0d2d35e693c65c774c7470e87b0572e07c1a", cg.ContainerId)
4940
assert.Equal(t, ContainerTypeDocker, cg.ContainerType)
5041

5142
cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/400/cgroup"))
5243
assert.Nil(t, err)
53-
assert.Equal(t, V2, cg.Version)
5444
assert.Equal(t, "/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod8712f785_1a3e_41ec_a00b_e2dcc77431cb.slice/docker-73051af271105c07e1f493b34856a77e665e3b0b4fc72f76c807dfbffeb881bd.scope", cg.Id)
5545
assert.Equal(t, "73051af271105c07e1f493b34856a77e665e3b0b4fc72f76c807dfbffeb881bd", cg.ContainerId)
5646
assert.Equal(t, ContainerTypeDocker, cg.ContainerType)
5747

5848
cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/600/cgroup"))
5949
assert.Nil(t, err)
60-
assert.Equal(t, V1, cg.Version)
6150
assert.Equal(t, "/system.slice/springboot.service", cg.Id)
6251
assert.Equal(t, "/system.slice/springboot.service", cg.ContainerId)
6352
assert.Equal(t, ContainerTypeSystemdService, cg.ContainerType)
6453

6554
cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/700/cgroup"))
6655
assert.Nil(t, err)
67-
assert.Equal(t, V2, cg.Version)
6856
assert.Equal(t, "/podruntime/runtime", cg.Id)
6957
assert.Equal(t, "/talos/runtime", cg.ContainerId)
7058
assert.Equal(t, ContainerTypeTalosRuntime, cg.ContainerType)
7159

7260
cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/800/cgroup"))
7361
assert.Nil(t, err)
74-
assert.Equal(t, V2, cg.Version)
7562
assert.Equal(t, "/system.slice/docker-cf87ba651579c9231db817909e7865e5747bd7abcac0c57ce23cf4abbaee046b.scope", cg.Id)
7663
assert.Equal(t, "cf87ba651579c9231db817909e7865e5747bd7abcac0c57ce23cf4abbaee046b", cg.ContainerId)
7764
assert.Equal(t, ContainerTypeDocker, cg.ContainerType)
7865

7966
cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/900/cgroup"))
8067
assert.Nil(t, err)
81-
assert.Equal(t, V1, cg.Version)
8268
assert.Equal(t, "/system.slice/python-app.service", cg.Id)
8369
assert.Equal(t, "/system.slice/python-app.service", cg.ContainerId)
8470
assert.Equal(t, ContainerTypeSystemdService, cg.ContainerType)
@@ -89,7 +75,6 @@ func TestNewFromProcessCgroupFile(t *testing.T) {
8975
}()
9076
cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/500/cgroup"))
9177
assert.Nil(t, err)
92-
assert.Equal(t, V2, cg.Version)
9378
assert.Equal(t, "/system.slice/docker-ba7b10d15d16e10e3de7a2dcd408a3d971169ae303f46cfad4c5453c6326fee2.scope", cg.Id)
9479
assert.Equal(t, "ba7b10d15d16e10e3de7a2dcd408a3d971169ae303f46cfad4c5453c6326fee2", cg.ContainerId)
9580
assert.Equal(t, ContainerTypeDocker, cg.ContainerType)

cgroup/cpu.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@ type CPUStat struct {
1717
}
1818

1919
func (cg Cgroup) CpuStat() *CPUStat {
20-
if cg.Version == V1 {
21-
st, _ := cg.cpuStatV1()
20+
cpu, cpuacct := cg.subsystems["cpu"], cg.subsystems["cpuacct"]
21+
if cpu == "" || cpuacct == "" {
22+
st, _ := cg.cpuStatV2()
2223
return st
2324
}
24-
st, _ := cg.cpuStatV2()
25+
st, _ := cg.cpuStatV1()
2526
return st
2627
}
2728

2829
func (cg Cgroup) cpuStatV1() (*CPUStat, error) {
29-
if cg.subsystems["cpu"] == "/" || cg.subsystems["cpuacct"] == "/" {
30+
if cg.subsystems["cpu"] == "" || cg.subsystems["cpuacct"] == "" {
3031
return nil, nil
3132
}
3233
throttling, err := readVariablesFromFile(path.Join(cgRoot, "cpu", cg.subsystems["cpu"], "cpu.stat"))
@@ -56,15 +57,18 @@ func (cg Cgroup) cpuStatV1() (*CPUStat, error) {
5657
}
5758

5859
func (cg Cgroup) cpuStatV2() (*CPUStat, error) {
59-
vars, err := readVariablesFromFile(path.Join(cgRoot, cg.subsystems[""], "cpu.stat"))
60+
if cg.subsystems[""] == "" {
61+
return nil, nil
62+
}
63+
vars, err := readVariablesFromFile(path.Join(cg2Root, cg.subsystems[""], "cpu.stat"))
6064
if err != nil {
6165
return nil, err
6266
}
6367
res := &CPUStat{
6468
UsageSeconds: float64(vars["usage_usec"]) / 1e6,
6569
ThrottledTimeSeconds: float64(vars["throttled_usec"]) / 1e6,
6670
}
67-
if payload, err := os.ReadFile(path.Join(cgRoot, cg.subsystems[""], "cpu.max")); err == nil {
71+
if payload, err := os.ReadFile(path.Join(cg2Root, cg.subsystems[""], "cpu.max")); err == nil {
6872
data := strings.TrimSpace(string(payload))
6973
parts := strings.Fields(data)
7074
if len(parts) != 2 {

cgroup/cpu_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
func TestCgroup_CpuStat(t *testing.T) {
1111
cgRoot = "fixtures/cgroup"
12+
cg2Root = "fixtures/cgroup"
1213

1314
cg, _ := NewFromProcessCgroupFile(path.Join("fixtures/proc/100/cgroup"))
1415
s := cg.CpuStat()
@@ -36,4 +37,11 @@ func TestCgroup_CpuStat(t *testing.T) {
3637
s, err := cg.cpuStatV1()
3738
assert.NoError(t, err)
3839
assert.Nil(t, s)
40+
41+
cg2Root = "fixtures/cgroup/unified"
42+
cg, _ = NewFromProcessCgroupFile(path.Join("fixtures/proc/550/cgroup"))
43+
s = cg.CpuStat()
44+
assert.Equal(t, 0., s.LimitCores)
45+
assert.Equal(t, 0., s.ThrottledTimeSeconds)
46+
assert.Equal(t, 151.439967, s.UsageSeconds)
3947
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
9223372036854771712
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
cache 7299072
2+
rss 3637248
3+
rss_huge 0
4+
shmem 0
5+
mapped_file 2703360
6+
dirty 0
7+
writeback 0
8+
pgpgin 1584132
9+
pgpgout 1581454
10+
pgfault 3320328
11+
pgmajfault 0
12+
inactive_anon 0
13+
active_anon 3649536
14+
inactive_file 3514368
15+
active_file 3514368
16+
unevictable 0
17+
hierarchical_memory_limit 9223372036854771712
18+
total_cache 7299072
19+
total_rss 3637248
20+
total_rss_huge 0
21+
total_shmem 0
22+
total_mapped_file 2703360
23+
total_dirty 0
24+
total_writeback 0
25+
total_pgpgin 1584132
26+
total_pgpgout 1581454
27+
total_pgfault 3320328
28+
total_pgmajfault 0
29+
total_inactive_anon 0
30+
total_active_anon 3649536
31+
total_inactive_file 3514368
32+
total_active_file 3514368
33+
total_unevictable 0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
usage_usec 151439967
2+
user_usec 99140470
3+
system_usec 52299496

cgroup/fixtures/proc/550/cgroup

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
12:perf_event:/
2+
11:devices:/system.slice/ssh.service
3+
10:freezer:/
4+
9:hugetlb:/
5+
8:cpuset:/
6+
7:blkio:/
7+
6:memory:/system.slice/ssh.service
8+
5:pids:/system.slice/ssh.service
9+
4:cpu,cpuacct:/
10+
3:net_cls,net_prio:/
11+
2:rdma:/
12+
1:name=systemd:/system.slice/ssh.service
13+
0::/system.slice/ssh.service

cgroup/io.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package cgroup
22

33
import (
4-
"io/ioutil"
4+
"os"
55
"path"
66
"strconv"
77
"strings"
@@ -17,16 +17,17 @@ type IOStat struct {
1717
}
1818

1919
func (cg *Cgroup) IOStat() map[string]IOStat {
20-
if cg.Version == V1 {
21-
st, _ := cg.ioStatV1()
20+
blkio := cg.subsystems["blkio"]
21+
if blkio == "" {
22+
st, _ := cg.ioStatV2()
2223
return st
2324
}
24-
st, _ := cg.ioStatV2()
25+
st, _ := cg.ioStatV1()
2526
return st
2627
}
2728

2829
func (cg *Cgroup) ioStatV1() (map[string]IOStat, error) {
29-
if cg.subsystems["blkio"] == "/" {
30+
if cg.subsystems["blkio"] == "" {
3031
return nil, nil
3132
}
3233
ops, err := readBlkioStatFile(path.Join(cgRoot, "blkio", cg.subsystems["blkio"], "blkio.throttle.io_serviced"))
@@ -62,7 +63,10 @@ func (cg *Cgroup) ioStatV1() (map[string]IOStat, error) {
6263
}
6364

6465
func (cg *Cgroup) ioStatV2() (map[string]IOStat, error) {
65-
payload, err := ioutil.ReadFile(path.Join(cgRoot, cg.subsystems[""], "io.stat"))
66+
if cg.subsystems[""] == "" {
67+
return nil, nil
68+
}
69+
payload, err := os.ReadFile(path.Join(cg2Root, cg.subsystems[""], "io.stat"))
6670
if err != nil {
6771
return nil, err
6872
}
@@ -103,7 +107,7 @@ type blkioVariable struct {
103107
}
104108

105109
func readBlkioStatFile(filePath string) ([]blkioVariable, error) {
106-
data, err := ioutil.ReadFile(filePath)
110+
data, err := os.ReadFile(filePath)
107111
if err != nil {
108112
return nil, err
109113
}

0 commit comments

Comments
 (0)