Skip to content

fix: ensure kubelet and containerd in kube.slice via systemd drop-ins#8958

Merged
mxj220 merged 23 commits into
mainfrom
fix-test-ensure-kubelet-and
Jul 24, 2026
Merged

fix: ensure kubelet and containerd in kube.slice via systemd drop-ins#8958
mxj220 merged 23 commits into
mainfrom
fix-test-ensure-kubelet-and

Conversation

@titilambert

@titilambert titilambert commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

When node hardening is enabled, ensureKubeletCgroupHierarchy() creates a dedicated kubelet.slice for kube-reserved cgroup enforcement. However the existing drop-in for kubelet.service only declared Wants= and After= ordering — it did not set Slice=kubelet.slice, so kubelet remained in system.slice. Additionally, containerd.service had no drop-in at all and was never placed in the slice.

This PR fixes both issues:

  1. Adds Slice=kubelet.slice to the kubelet drop-in so kubelet actually runs inside the dedicated slice.
  2. Creates an equivalent drop-in for containerd.service (10-kubelet-slice.conf) so containerd is co-located in the same slice.

Without this fix, cgroup resource accounting under kubelet.slice is incomplete — node hardening's kube-reserved budget doesn't capture the real resource usage of kubelet and containerd, which blocks nodes to be ready since they are affected to system.slice which has a low max memory limit

Testing:

  • Updated ShellSpec tests to validate both drop-ins are written with the
    correct [Service] Slice=kubelet.slice directive.
  •  $ systemctl status containerd | grep "CGroup"
     CGroup: /kubelet.slice/containerd.service
     $ systemctl status kubelet | grep "CGroup"
     CGroup: /kubelet.slice/kubelet.service
    

Which issue(s) this PR fixes:

Fixes #

@titilambert

Copy link
Copy Markdown
Contributor Author

This change is part of the following stack:

Change managed by git-spice.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Linux CSE helper responsible for Node Memory Hardening cgroup hierarchy setup so that both kubelet and containerd are configured to run under kubelet.slice, and adjusts ShellSpec coverage accordingly.

Changes:

  • Extend ensureKubeletCgroupHierarchy to set Slice=kubelet.slice for kubelet.service and add a matching drop-in for containerd.service.
  • Update ShellSpec assertions to validate the additional systemd drop-in content for containerd.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
parts/linux/cloud-init/artifacts/cse_helpers.sh Adds systemd drop-ins to place kubelet and containerd into kubelet.slice when hardening cgroups are enabled.
spec/parts/linux/cloud-init/artifacts/cse_helpers_spec.sh Updates tests to assert Slice= and validates the containerd drop-in is created.

Comment thread parts/linux/cloud-init/artifacts/cse_helpers.sh Outdated
Comment thread spec/parts/linux/cloud-init/artifacts/cse_helpers_spec.sh
Copilot AI review requested due to automatic review settings July 15, 2026 19:42
@titilambert
titilambert force-pushed the fix-test-ensure-kubelet-and branch from 39476df to 4045739 Compare July 15, 2026 19:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread parts/linux/cloud-init/artifacts/cse_helpers.sh Outdated
Comment thread spec/parts/linux/cloud-init/artifacts/cse_helpers_spec.sh
@titilambert titilambert changed the title fix(test): ensure kubelet and containerd are in kubelet.slice when node hardening is on fix: place kubelet and containerd in kubelet.slice via systemd drop-ins Jul 15, 2026

@SriHarsha001 SriHarsha001 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to look into the AI's comments, apart from that changes look good to me.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • aks-node-controller/pkg/gen/aksnodeconfig/v1/kubelet_config.pb.go: Generated file
Comments suppressed due to low confidence (3)

pkg/agent/utils.go:512

  • isNodeHardeningEnabled() only strips surrounding '[' and ']' from --enforce-node-allocatable, but existing test data documents values that can be additionally wrapped in quotes (e.g. "[pods]"). In that case hardening detection will be skipped and the cgroup flags won’t be set/overwritten as intended.
	raw := strings.TrimSpace(kubeletFlags["--enforce-node-allocatable"])
	raw = strings.TrimPrefix(raw, "[")
	raw = strings.TrimSuffix(raw, "]")
	enforced := strings.Split(raw, ",")

parts/linux/cloud-init/artifacts/cse_config.sh:392

  • This logs_to_events key uses the ensureKubelet prefix even though it’s executed from ensureContainerd(), which can make event attribution/telemetry confusing when diagnosing provisioning failures.
      if ! logs_to_events "AKS.CSE.ensureKubelet.ensureKubeletCgroupHierarchy" ensureKubeletCgroupHierarchy; then

parts/linux/cloud-init/artifacts/cse_config.sh:888

  • This rewrites /etc/systemd/system/kubelet.service.d/10-containerd-base-flag.conf but does not ensure the drop-in directory exists first. On images/scenarios where kubelet.service.d isn’t present yet, tee will fail and kubelet may start without the intended --runtime-cgroups refresh.
    tee "/etc/systemd/system/kubelet.service.d/10-containerd-base-flag.conf" > /dev/null <<EOF
[Service]
Environment="KUBELET_CONTAINERD_FLAGS=--runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock --runtime-cgroups=${containerd_runtime_cgroups}"
EOF

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • aks-node-controller/pkg/gen/aksnodeconfig/v1/kubelet_config.pb.go: Generated file
Comments suppressed due to low confidence (2)

parts/linux/cloud-init/artifacts/cse_helpers.sh:1490

  • The PR description and title still refer to placing services under kubelet.slice / Slice=kubelet.slice, but the code and tests in this PR consistently use kubereserved.slice. Please update the PR description (or rename the slice) so reviewers/operators aren’t left with conflicting slice names.
# It MUST be called before kubelet starts so that /kubereserved.slice and /system.slice
# exist and are managed by systemd before the first kubelet enforcement pass.
#
# The function:

parts/linux/cloud-init/artifacts/cse_config.sh:393

  • This logs_to_events tag is emitted from ensureContainerd, but the event name is prefixed with ensureKubelet. This makes telemetry harder to query/triage (the same helper is already tagged correctly under ensureContainerd.* elsewhere in this function).
  resolveKubeletReservedCgroups
  if [ -n "${KUBE_RESERVED_CGROUP}" ] || [ -n "${SYSTEM_RESERVED_CGROUP}" ]; then
      if ! logs_to_events "AKS.CSE.ensureKubelet.ensureKubeletCgroupHierarchy" ensureKubeletCgroupHierarchy; then
          exit $ERR_KUBELET_START_FAIL

Comment thread parts/linux/cloud-init/artifacts/cse_helpers.sh
titilambert and others added 21 commits July 23, 2026 10:52
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • aks-node-controller/pkg/gen/aksnodeconfig/v1/kubelet_config.pb.go: Generated file

Comment on lines +1611 to +1616
# Enable the slice for subsequent boots AND materialise the cgroup tree
# at /sys/fs/cgroup/kubereserved.slice on this boot before kubelet starts.
# systemctlEnableAndStart wraps both operations with retry logic to
# survive transient systemd failures during CSE.
if ! systemctlEnableAndStart kubereserved.slice 30; then
echo "ensureKubeletCgroupHierarchy: failed to enable and start kubereserved.slice"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • aks-node-controller/pkg/gen/aksnodeconfig/v1/kubelet_config.pb.go: Generated file
Comments suppressed due to low confidence (1)

parts/linux/cloud-init/artifacts/cse_config.sh:394

  • This is inside ensureContainerd(), but failures from ensureKubeletCgroupHierarchy are logged under the ensureKubelet event name and exit with ERR_KUBELET_START_FAIL. That makes telemetry/error classification misleading for containerd startup failures (and can confuse troubleshooting). Use an ensureContainerd-scoped event name and an error code consistent with other systemctl failures in this function.
      if ! logs_to_events "AKS.CSE.ensureKubelet.ensureKubeletCgroupHierarchy" ensureKubeletCgroupHierarchy; then
          exit $ERR_KUBELET_START_FAIL
      fi

Comment thread e2e/vmss.go Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • aks-node-controller/pkg/gen/aksnodeconfig/v1/kubelet_config.pb.go: Generated file
Comments suppressed due to low confidence (2)

parts/linux/cloud-init/artifacts/cse_helpers.sh:1616

  • ensureKubeletCgroupHierarchy calls systemctlEnableAndStart for kubereserved.slice, but systemctlEnableAndStart uses systemctl restart internally. For a slice unit, restart is more disruptive than necessary and can impact already-running units in that slice during the idempotent refresh path (e.g., nodePrep). Prefer enabling + starting the slice explicitly with retries (without restart).
        if ! systemctlEnableAndStart kubereserved.slice 30; then
            echo "ensureKubeletCgroupHierarchy: failed to enable and start kubereserved.slice"

parts/linux/cloud-init/artifacts/cse_config.sh:394

  • In ensureContainerd, a failure to create the hardening slice/drop-ins is not a kubelet start failure; it’s a systemd/unit setup failure before containerd is started. Exiting with ERR_KUBELET_START_FAIL (34) will misclassify the failure; ERR_SYSTEMCTL_START_FAIL (4) is a closer match.
  resolveKubeletReservedCgroups
  if [ -n "${KUBE_RESERVED_CGROUP}" ] || [ -n "${SYSTEM_RESERVED_CGROUP}" ]; then
      if ! logs_to_events "AKS.CSE.ensureKubelet.ensureKubeletCgroupHierarchy" ensureKubeletCgroupHierarchy; then
          exit $ERR_KUBELET_START_FAIL
      fi

Comment thread pkg/agent/utils.go
Comment on lines +487 to +491
// Node Hardening cgroup slice names. AgentBaker is the single
// source of truth for these values: cse_helpers.sh::ensureKubeletCgroupHierarchy
// is what actually creates (or validates) the systemd slice unit on the node, so
// the name must be decided here rather than accepted verbatim from the RP.
const (
Comment on lines +879 to +888
# Refresh --runtime-cgroups for PIS nodes where basePrep may have baked an older
# 10-containerd-base-flag.conf pointing at /system.slice/containerd.service.
local containerd_runtime_cgroups="/system.slice/containerd.service"
if [ "${KUBE_RESERVED_CGROUP:-}" = "/kubereserved.slice" ] || [ "${KUBE_RESERVED_CGROUP:-}" = "kubereserved.slice" ]; then
containerd_runtime_cgroups="/kubereserved.slice/containerd.service"
fi
tee "/etc/systemd/system/kubelet.service.d/10-containerd-base-flag.conf" > /dev/null <<EOF
[Service]
Environment="KUBELET_CONTAINERD_FLAGS=--runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock --runtime-cgroups=${containerd_runtime_cgroups}"
EOF
Comment thread e2e/validators.go
Comment on lines +3488 to +3495

// ValidateServiceInSlice asserts that the given systemd service is running in the expected slice.
func ValidateServiceInSlice(ctx context.Context, s *Scenario, service, expectedSlice string) {
s.T.Helper()
// Avoid accidental shell injection / option smuggling.
if !regexp.MustCompile(`^[A-Za-z0-9_.@:-]+$`).MatchString(service) {
s.T.Fatalf("invalid systemd unit name: %q", service)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants