k3s-io/k3s · critical

delegated cgroup v2 controllers are required for rootless

Error message

delegated cgroup v2 controllers are required for rootless

What it means

createRootlessConfig requires, for rootless k3s: the 'cpu' and 'pids' cgroup v2 controllers delegated to the user and /sys/fs/cgroup writable inside the user namespace (unix.Access W_OK). Missing any of the three returns this error; kubelet cannot enforce cpu/pids limits without delegation.

Source

Thrown at pkg/daemons/agent/agent_linux.go:32

	"github.com/k3s-io/k3s/pkg/util"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
	kubeletconfig "k8s.io/kubelet/config/v1beta1"
	utilsnet "k8s.io/utils/net"
	utilsptr "k8s.io/utils/ptr"
)

const socketPrefix = "unix://"

func createRootlessConfig(argsMap map[string]string, controllers map[string]bool) error {
	argsMap["feature-gates=KubeletInUserNamespace"] = "true"
	// "/sys/fs/cgroup" is namespaced
	cgroupfsWritable := unix.Access("/sys/fs/cgroup", unix.W_OK) == nil
	if controllers["cpu"] && controllers["pids"] && cgroupfsWritable {
		logrus.Info("cgroup v2 controllers are delegated for rootless.")
		return nil
	}
	return errors.New("delegated cgroup v2 controllers are required for rootless")
}

func kubeProxyArgs(cfg *config.Agent) map[string]string {
	bindAddress := "127.0.0.1"
	if utilsnet.IsIPv6(net.ParseIP(cfg.NodeIP)) {
		bindAddress = "::1"
	}
	argsMap := map[string]string{
		"proxy-mode":                        "iptables",
		"healthz-bind-address":              bindAddress,
		"kubeconfig":                        cfg.KubeConfigKubeProxy,
		"cluster-cidr":                      util.JoinIPNets(cfg.ClusterCIDRs),
		"conntrack-max-per-core":            "0",
		"conntrack-tcp-timeout-established": "0s",
		"conntrack-tcp-timeout-close-wait":  "0s",
	}
	if cfg.NodeName != "" {
		argsMap["hostname-override"] = cfg.NodeName

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Apply the standard rootless systemd override: mkdir -p ~/.config/systemd/user/service.d with [Service] Delegate=yes, then systemctl daemon-reload and re-login (see k3s rootless docs).
  2. Ensure the host boots with cgroup v2 unified mode only (systemd.unified_cgroup_hierarchy=1).
  3. cat /sys/fs/cgroup/cgroup.controllers from the user session and verify cpu and pids appear in cgroup.subtree_control after delegation.
  4. In containers, run the rootless container itself with delegated cgroups (e.g., podman run --cgroupns=host with systemd) rather than nesting k3s rootless.

Example fix

# before: no delegation, k3s rootless fails
# after
mkdir -p ~/.config/systemd/user/service.d
cat > ~/.config/systemd/user/service.d/delegate.conf <<EOF
[Service]
Delegate=yes
EOF
systemctl --user daemon-reload
loginctl enable-linger $USER
Defensive patterns

Strategy: validation

Validate before calling

// Reproduce createRootlessConfig's gate before launching:
func rootlessReady(controllers map[string]bool) error {
	if !controllers["cpu"] || !controllers["pids"] {
		return errors.New("delegate cpu and pids controllers to the user (systemd Delegate=yes)")
	}
	if unix.Access("/sys/fs/cgroup", unix.W_OK) != nil {
		return errors.New("/sys/fs/cgroup not writable: fix user-namespace mount/delegation")
	}
	return nil
}

Prevention

When it happens

Trigger: Running k3s rootless without systemd Delegate=yes for the user slice; cgroup v1 host (no delegation model); rootless inside a container/CI where /sys/fs/cgroup is mounted read-only; user@.service without enable-linger and proper drop-ins.

Common situations: Following rootless setup docs but skipping the systemd override; running rootless k3s inside Docker/Podman without --cgroupns=private and delegated controllers; host booted with hybrid cgroups.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/f4e9b7f2cff1159c. Report an issue: GitHub.