Commit 333311c7 authored by Brad Davidson's avatar Brad Davidson Committed by Brad Davidson

Add systemd cgroup controller support

parent 1caae631
...@@ -45,18 +45,22 @@ func setupContainerdConfig(ctx context.Context, cfg *config.Node) error { ...@@ -45,18 +45,22 @@ func setupContainerdConfig(ctx context.Context, cfg *config.Node) error {
} }
isRunningInUserNS := userns.RunningInUserNS() isRunningInUserNS := userns.RunningInUserNS()
_, _, hasCFS, hasPIDs := cgroups.CheckCgroups() _, _, controllers := cgroups.CheckCgroups()
// "/sys/fs/cgroup" is namespaced // "/sys/fs/cgroup" is namespaced
cgroupfsWritable := unix.Access("/sys/fs/cgroup", unix.W_OK) == nil cgroupfsWritable := unix.Access("/sys/fs/cgroup", unix.W_OK) == nil
disableCgroup := isRunningInUserNS && (!hasCFS || !hasPIDs || !cgroupfsWritable) disableCgroup := isRunningInUserNS && (!controllers["cpu"] || !controllers["pids"] || !cgroupfsWritable)
if disableCgroup { if disableCgroup {
logrus.Warn("cgroup v2 controllers are not delegated for rootless. Disabling cgroup.") logrus.Warn("cgroup v2 controllers are not delegated for rootless. Disabling cgroup.")
} }
systemdCgroup := controllers["cpuset"] && os.Getenv("NOTIFY_SOCKET") != ""
cfg.AgentConfig.Systemd = systemdCgroup
var containerdTemplate string var containerdTemplate string
containerdConfig := templates.ContainerdConfig{ containerdConfig := templates.ContainerdConfig{
NodeConfig: cfg, NodeConfig: cfg,
DisableCgroup: disableCgroup, DisableCgroup: disableCgroup,
SystemdCgroup: systemdCgroup,
IsRunningInUserNS: isRunningInUserNS, IsRunningInUserNS: isRunningInUserNS,
PrivateRegistryConfig: privRegistries.Registry, PrivateRegistryConfig: privRegistries.Registry,
ExtraRuntimes: findNvidiaContainerRuntimes(os.DirFS(string(os.PathSeparator))), ExtraRuntimes: findNvidiaContainerRuntimes(os.DirFS(string(os.PathSeparator))),
......
...@@ -45,6 +45,7 @@ func setupContainerdConfig(ctx context.Context, cfg *config.Node) error { ...@@ -45,6 +45,7 @@ func setupContainerdConfig(ctx context.Context, cfg *config.Node) error {
containerdConfig := templates.ContainerdConfig{ containerdConfig := templates.ContainerdConfig{
NodeConfig: cfg, NodeConfig: cfg,
DisableCgroup: true, DisableCgroup: true,
SystemdCgroup: false,
IsRunningInUserNS: false, IsRunningInUserNS: false,
PrivateRegistryConfig: privRegistries.Registry, PrivateRegistryConfig: privRegistries.Registry,
} }
......
...@@ -14,6 +14,7 @@ type ContainerdRuntimeConfig struct { ...@@ -14,6 +14,7 @@ type ContainerdRuntimeConfig struct {
type ContainerdConfig struct { type ContainerdConfig struct {
NodeConfig *config.Node NodeConfig *config.Node
DisableCgroup bool DisableCgroup bool
SystemdCgroup bool
IsRunningInUserNS bool IsRunningInUserNS bool
PrivateRegistryConfig *registries.Registry PrivateRegistryConfig *registries.Registry
ExtraRuntimes map[string]ContainerdRuntimeConfig ExtraRuntimes map[string]ContainerdRuntimeConfig
......
...@@ -81,6 +81,9 @@ enable_keychain = true ...@@ -81,6 +81,9 @@ enable_keychain = true
[plugins.cri.containerd.runtimes.runc] [plugins.cri.containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2" runtime_type = "io.containerd.runc.v2"
[plugins.cri.containerd.runtimes.runc.options]
SystemdCgroup = {{ .SystemdCgroup }}
{{ if .PrivateRegistryConfig }} {{ if .PrivateRegistryConfig }}
{{ if .PrivateRegistryConfig.Mirrors }} {{ if .PrivateRegistryConfig.Mirrors }}
[plugins.cri.registry.mirrors]{{end}} [plugins.cri.registry.mirrors]{{end}}
......
...@@ -65,34 +65,30 @@ func validateCgroupsV2() error { ...@@ -65,34 +65,30 @@ func validateCgroupsV2() error {
return nil return nil
} }
func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) { func CheckCgroups() (kubeletRoot, runtimeRoot string, controllers map[string]bool) {
cgroupsModeV2 := cgroups.Mode() == cgroups.Unified cgroupsModeV2 := cgroups.Mode() == cgroups.Unified
controllers = make(map[string]bool)
// For Unified (v2) cgroups we can directly check to see what controllers are mounted // For Unified (v2) cgroups we can directly check to see what controllers are mounted
// under the unified hierarchy. // under the unified hierarchy.
if cgroupsModeV2 { if cgroupsModeV2 {
m, err := cgroupsv2.LoadManager("/sys/fs/cgroup", "/") m, err := cgroupsv2.LoadManager("/sys/fs/cgroup", "/")
if err != nil { if err != nil {
return "", "", false, false return
} }
controllers, err := m.Controllers() enabledControllers, err := m.Controllers()
if err != nil { if err != nil {
return "", "", false, false return
} }
// Intentionally using an expressionless switch to match the logic below // Intentionally using an expressionless switch to match the logic below
for _, controller := range controllers { for _, controller := range enabledControllers {
switch { controllers[controller] = true
case controller == "cpu":
hasCFS = true
case controller == "pids":
hasPIDs = true
}
} }
} }
f, err := os.Open("/proc/self/cgroup") f, err := os.Open("/proc/self/cgroup")
if err != nil { if err != nil {
return "", "", false, false return
} }
defer f.Close() defer f.Close()
...@@ -102,10 +98,10 @@ func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) { ...@@ -102,10 +98,10 @@ func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) {
if len(parts) < 3 { if len(parts) < 3 {
continue continue
} }
controllers := strings.Split(parts[1], ",") enabledControllers := strings.Split(parts[1], ",")
// For v1 or hybrid, controller can be a single value {"blkio"}, or a comounted set {"cpu","cpuacct"} // For v1 or hybrid, controller can be a single value {"blkio"}, or a comounted set {"cpu","cpuacct"}
// For v2, controllers = {""} (only contains a single empty string) // For v2, controllers = {""} (only contains a single empty string) so this section is not used.
for _, controller := range controllers { for _, controller := range enabledControllers {
switch { switch {
case controller == "name=systemd" || cgroupsModeV2: case controller == "name=systemd" || cgroupsModeV2:
// If we detect that we are running under a `.scope` unit with systemd // If we detect that we are running under a `.scope` unit with systemd
...@@ -128,10 +124,10 @@ func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) { ...@@ -128,10 +124,10 @@ func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) {
// can fail if we use the comma-separated name. Instead, we check for the controller using the symlink. // can fail if we use the comma-separated name. Instead, we check for the controller using the symlink.
p := filepath.Join("/sys/fs/cgroup", controller, parts[2], "cpu.cfs_period_us") p := filepath.Join("/sys/fs/cgroup", controller, parts[2], "cpu.cfs_period_us")
if _, err := os.Stat(p); err == nil { if _, err := os.Stat(p); err == nil {
hasCFS = true controllers[controller] = true
} }
case controller == "pids": default:
hasPIDs = true controllers[controller] = true
} }
} }
} }
...@@ -146,7 +142,7 @@ func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) { ...@@ -146,7 +142,7 @@ func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) {
// a host PID scenario but we don't support this. // a host PID scenario but we don't support this.
g, err := os.Open("/proc/1/cgroup") g, err := os.Open("/proc/1/cgroup")
if err != nil { if err != nil {
return "", "", false, false return
} }
defer g.Close() defer g.Close()
scan = bufio.NewScanner(g) scan = bufio.NewScanner(g)
...@@ -170,5 +166,5 @@ func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) { ...@@ -170,5 +166,5 @@ func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) {
} }
} }
} }
return kubeletRoot, runtimeRoot, hasCFS, hasPIDs return
} }
//go:build windows
// +build windows // +build windows
package cgroups package cgroups
...@@ -6,6 +7,6 @@ func Validate() error { ...@@ -6,6 +7,6 @@ func Validate() error {
return nil return nil
} }
func CheckCgroups() (kubeletRoot, runtimeRoot string, hasCFS, hasPIDs bool) { func CheckCgroups() (kubeletRoot, runtimeRoot string, controllers map[string]bool) {
return "", "", false, false return
} }
...@@ -18,17 +18,15 @@ import ( ...@@ -18,17 +18,15 @@ import (
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
) )
func createRootlessConfig(argsMap map[string]string, hasCFS, hasPIDs bool) { func createRootlessConfig(argsMap map[string]string, controllers map[string]bool) {
argsMap["feature-gates=KubeletInUserNamespace"] = "true" argsMap["feature-gates=KubeletInUserNamespace"] = "true"
// "/sys/fs/cgroup" is namespaced // "/sys/fs/cgroup" is namespaced
cgroupfsWritable := unix.Access("/sys/fs/cgroup", unix.W_OK) == nil cgroupfsWritable := unix.Access("/sys/fs/cgroup", unix.W_OK) == nil
if hasCFS && hasPIDs && cgroupfsWritable { if controllers["cpu"] && controllers["pids"] && cgroupfsWritable {
logrus.Info("cgroup v2 controllers are delegated for rootless.") logrus.Info("cgroup v2 controllers are delegated for rootless.")
// cgroupfs v2, delegated for rootless by systemd return
argsMap["cgroup-driver"] = "cgroupfs"
} else {
logrus.Fatal("delegated cgroup v2 controllers are required for rootless.")
} }
logrus.Fatal("delegated cgroup v2 controllers are required for rootless.")
} }
func checkRuntimeEndpoint(cfg *config.Agent, argsMap map[string]string) { func checkRuntimeEndpoint(cfg *config.Agent, argsMap map[string]string) {
...@@ -67,14 +65,13 @@ func kubeletArgs(cfg *config.Agent) map[string]string { ...@@ -67,14 +65,13 @@ func kubeletArgs(cfg *config.Agent) map[string]string {
bindAddress = "::1" bindAddress = "::1"
} }
argsMap := map[string]string{ argsMap := map[string]string{
"healthz-bind-address": bindAddress, "healthz-bind-address": bindAddress,
"read-only-port": "0", "read-only-port": "0",
"cluster-domain": cfg.ClusterDomain, "cluster-domain": cfg.ClusterDomain,
"kubeconfig": cfg.KubeConfigKubelet, "kubeconfig": cfg.KubeConfigKubelet,
"eviction-hard": "imagefs.available<5%,nodefs.available<5%", "eviction-hard": "imagefs.available<5%,nodefs.available<5%",
"eviction-minimum-reclaim": "imagefs.available=10%,nodefs.available=10%", "eviction-minimum-reclaim": "imagefs.available=10%,nodefs.available=10%",
"fail-swap-on": "false", "fail-swap-on": "false",
//"cgroup-root": "/k3s",
"cgroup-driver": "cgroupfs", "cgroup-driver": "cgroupfs",
"authentication-token-webhook": "true", "authentication-token-webhook": "true",
"anonymous-auth": "false", "anonymous-auth": "false",
...@@ -138,13 +135,13 @@ func kubeletArgs(cfg *config.Agent) map[string]string { ...@@ -138,13 +135,13 @@ func kubeletArgs(cfg *config.Agent) map[string]string {
if err != nil || defaultIP.String() != cfg.NodeIP { if err != nil || defaultIP.String() != cfg.NodeIP {
argsMap["node-ip"] = cfg.NodeIP argsMap["node-ip"] = cfg.NodeIP
} }
kubeletRoot, runtimeRoot, hasCFS, hasPIDs := cgroups.CheckCgroups() kubeletRoot, runtimeRoot, controllers := cgroups.CheckCgroups()
if !hasCFS { if !controllers["cpu"] {
logrus.Warn("Disabling CPU quotas due to missing cpu.cfs_period_us") logrus.Warn("Disabling CPU quotas due to missing cpu controller or cpu.cfs_period_us")
argsMap["cpu-cfs-quota"] = "false" argsMap["cpu-cfs-quota"] = "false"
} }
if !hasPIDs { if !controllers["pids"] {
logrus.Fatal("PIDS cgroup support not found") logrus.Fatal("pids cgroup controller not found")
} }
if kubeletRoot != "" { if kubeletRoot != "" {
argsMap["kubelet-cgroups"] = kubeletRoot argsMap["kubelet-cgroups"] = kubeletRoot
...@@ -172,7 +169,11 @@ func kubeletArgs(cfg *config.Agent) map[string]string { ...@@ -172,7 +169,11 @@ func kubeletArgs(cfg *config.Agent) map[string]string {
} }
if cfg.Rootless { if cfg.Rootless {
createRootlessConfig(argsMap, hasCFS, hasCFS) createRootlessConfig(argsMap, controllers)
}
if cfg.Systemd {
argsMap["cgroup-driver"] = "systemd"
} }
if cfg.ProtectKernelDefaults { if cfg.ProtectKernelDefaults {
......
...@@ -90,6 +90,7 @@ type Agent struct { ...@@ -90,6 +90,7 @@ type Agent struct {
ExtraKubeProxyArgs []string ExtraKubeProxyArgs []string
PauseImage string PauseImage string
Snapshotter string Snapshotter string
Systemd bool
CNIPlugin bool CNIPlugin bool
NodeTaints []string NodeTaints []string
NodeLabels []string NodeLabels []string
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment