kubelet Explained: The Node Agent

Khimananda Oli 8 min read Virtualization
kubelet Explained: The Node Agent

By Khimananda Oli | Last reviewed: August 2026

When a pod fails to start or a node shows NotReady, the root cause usually lies with the node agent itself. Kubelet Explained: The Node Agent is your reference for understanding how this critical component bridges the Kubernetes control plane and the actual containers running on your hardware. It is the primary actor responsible for translating API server declarations into running processes, making its correct configuration essential for any production cluster.

What does kubelet actually do as the Kubernetes node agent?

The kubelet acts as the local supervisor for every node in your cluster. Unlike the API server or scheduler which run centrally, the kubelet runs locally on each machine and maintains a persistent gRPC connection to both the container runtime and the Kubernetes API. Its responsibilities are distinct from other components like kube-proxy or the CNI plugin.

Node Architecture: Kubelet as Central CoordinatorAPI ServerKubelet(Node Agent)Container Runtime (CRI)Pod APod BVolume PluginCNI / NetworkWatch PodsgRPC CRI
Kubelet explained: central coordination between API server, container runtime, and pod infrastructure on each node

In practice, the kubelet performs four non-negotiable functions that define its role as the node agent:

  • Node Registration: On startup, it creates or updates the Node object in the API server, reporting capacity (CPU, memory, ephemeral storage), allocatable resources, and conditions like disk pressure or memory pressure.
  • Pod Lifecycle Management: It watches for PodSpecs assigned to its node, then calls the Container Runtime Interface (CRI) to pull images, create sandboxes, and start containers in the correct order.
  • Status Reporting: Every few seconds, it sends heartbeats and detailed status updates including container states, restart counts, and resource usage metrics back to the control plane.
  • Resource Enforcement: It works with cgroups to ensure containers stay within their requested CPU and memory limits, killing or evicting pods when node-level thresholds are breached.

Understanding these boundaries prevents confusion with Kubernetes resource limits and requests, which the kubelet enforces but does not calculate. The scheduler decides placement; the kubelet executes it.

How does kubelet interact with CRI and the container runtime?

Since Kubernetes v1.24 removed dockershim, the kubelet no longer speaks Docker directly. Instead, it uses the Container Runtime Interface (CRI), a standardized gRPC protocol that decouples the node agent from any specific runtime. This abstraction is why you can swap containerd for CRI-O without changing kubelet code.

CRI Communication Flow

  1. Socket Connection: Kubelet connects to the runtime via a Unix domain socket, typically /run/containerd/containerd.sock or /var/run/crio/crio.sock.
  2. Sandbox Creation: Before starting application containers, kubelet requests a pause sandbox (infra container) that holds network namespaces and cgroup configurations.
  3. Image Pull: Kubelet issues PullImage RPCs. If image pull secrets are needed, they are passed through the CRI auth mechanism.
  4. Container Start: After the sandbox is ready, kubelet sends CreateContainer and StartContainer calls with the full OCI spec derived from the PodSpec.
  5. Streaming & Exec: For kubectl logs or kubectl exec, kubelet proxies streaming requests through CRI endpoints rather than handling I/O directly.
<!-- Example: Checking CRI socket status -->
$ crictl info
{
  "config": {
    "containerdEndpoint": "/run/containerd/containerd.sock",
    "runtimeEndpoint": "/run/containerd/containerd.sock"
  },
  "runtimeVersion": "v1.30.2"
}

A common mistake in 2026 is assuming the kubelet manages networking. It does not. The kubelet invokes the CNI plugin via the runtime’s sandbox setup, but IP allocation and route programming happen entirely outside the kubelet process. For deeper networking context, see Kubernetes network policies explained.

How do you configure kubelet for production stability?

Default kubelet settings work for development but often fail under production load or compliance requirements. Configuration lives in two places: command-line flags (legacy) and the structured KubeletConfiguration file (recommended since v1.28+).

Critical Production Parameters

ParameterRecommended ValueWhy It Matters
maxPods110–250 (node-size dependent)Prevents PID exhaustion and API server overload from excessive watch events
serializeImagePullsfalseEnables parallel image pulls; reduces deployment latency by 40–60%
imageGCHighThresholdPercent85Triggers garbage collection before disk pressure causes evictions
evictionHard.memory.available500MiReserves kernel memory; prevents OOM kills of system daemons
rotateCertificatestrueAuto-renews client certs; mandatory for SOC 2 / ISO 27001 audit trails
# /etc/kubernetes/kubelet-config.yaml (KubeletConfiguration v1beta1)
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
maxPods: 150
serializeImagePulls: false
imageGCHighThresholdPercent: 85
imageGCLowThresholdPercent: 70
evictionHard:
  memory.available: "500Mi"
  nodefs.available: "10%"
rotateCertificates: true
serverTLSBootstrap: true
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true

In Nepal-based deployments where bandwidth to global registries is limited, setting serializeImagePulls: false combined with a local registry mirror dramatically improves pod startup times during scaling events. Always validate config changes with kubelet --config /path/to/config.yaml --dry-run before restarting the service.

How do you debug kubelet when pods fail to start?

When kubectl describe pod shows ContainerCreating indefinitely or ErrImagePull without clear cause, the kubelet logs are your primary diagnostic tool. Unlike application logs, kubelet output reveals infrastructure-layer failures that never reach the pod’s stdout.

Kubelet Debugging Decision TreePod Stuck / FailedCheck Node ConditionsInspect Kubelet LogsVerify CRI SocketDisk/Mem Pressure?Auth/Image Errors?Socket Missing?Clean Disk / Adjust EvictionFix Secret / Registry MirrorRestart Runtime + Kubelet
Systematic kubelet troubleshooting flow for pod startup failures in production environments

Essential Diagnostic Commands

# View live kubelet logs with context
journalctl -u kubelet -f --no-pager -n 200

# Check node conditions for pressure signals
kubectl get node <node-name> -o jsonpath='{.status.conditions}' | jq

# Validate CRI connectivity
crictl ps -a
crictl pods

# Inspect specific pod sandbox failure
crictl inspectp <sandbox-id>

# Verify kubelet config is loaded correctly
kubelet --config /etc/kubernetes/kubelet-config.yaml --dry-run 2>&1 | head -20

For CrashLoopBackOff issues specifically tied to resource constraints, cross-reference kubelet eviction logs with your manifest limits. My guide on debugging CrashLoopBackOff in Kubernetes covers the application-side correlation.

Kubelet vs kube-proxy: what’s the difference in responsibilities?

Engineers new to Kubernetes often conflate these two node-level daemons because both run on every worker. Their functions are completely orthogonal, and confusing them leads to wasted debugging time.

Kubelet vs Kube-Proxy: Separation of ConcernsKUBELET (Node Agent)• Registers node with API server• Pulls images & starts containers via CRI• Reports pod status & node conditions• Enforces cgroup resource limits• Handles liveness/readiness probes• Manages volume mounts & secretsLAYER: Process & LifecycleKUBE-PROXY (Network Agent)• Watches Service & EndpointSlices• Programs iptables/IPVS/nftables rules• Load balances traffic to pod IPs• Handles ClusterIP & NodePort routing• No container lifecycle involvement• Independent of CRI/runtimeLAYER: Network DataplaneNo Direct Interaction
Kubelet handles pod lifecycle and resource enforcement while kube-proxy manages service networking independently

The kubelet owns everything related to running containers: image pulls, cgroup enforcement, probe execution, volume mounting, and status reporting. Kube-proxy owns everything related to reaching containers: translating Service abstractions into kernel-level routing rules so traffic arrives at the correct pod IP. You can delete kube-proxy entirely in eBPF-based clusters (e.g., Cilium) and the kubelet continues functioning perfectly. Conversely, if kubelet dies, pods stop being managed regardless of whether networking is healthy.

This separation matters for incident response. If pods are running but unreachable, investigate kube-proxy, CNI, or network policies. If pods aren’t starting or keep restarting, investigate kubelet, CRI, or resource constraints. Mixing these domains wastes hours during outages.

Maintaining Kubelet Health in Production Clusters

Treating the kubelet as a set-and-forget daemon guarantees eventual failure. In production, especially for teams pursuing SOC 2 or ISO 27001 compliance, you must actively monitor and maintain the node agent itself. Enable serverTLSBootstrap to ensure all kubelet-to-API communication uses rotated certificates. Set up Prometheus scraping of the kubelet’s /metrics endpoint to track pod start latency, image pull duration, and eviction rates. These metrics form the foundation of meaningful SLIs and SLOs for node reliability.

On Ubuntu systems, pin your containerd and kubelet versions together during upgrades to avoid CRI incompatibilities. Use apt-mark hold kubelet during maintenance windows to prevent unattended upgrades from breaking node agents mid-deployment. For teams managing multiple clusters across regions, consider GitOps-driven kubelet configuration via tools like Kubespray or Cluster API to ensure consistency and auditability.

If your cluster shows intermittent NotReady flaps or slow pod scheduling despite healthy control plane metrics, the issue almost always traces back to kubelet misconfiguration or resource starvation at the node level. Audit your current settings against the parameters outlined here, validate with dry-run, and monitor the results. When you need hands-on assistance hardening node agents for compliance or performance, reach out to discuss your infrastructure.

Frequently Asked Questions

Kubelet is the node agent ensuring containers run as specified in PodSpecs. It registers nodes with the API server, reports status, and executes container lifecycle operations via the configured runtime interface.

Kubelet uses the Container Runtime Interface over gRPC to manage containers. This abstraction supports runtimes like containerd and CRI-O without requiring code changes, decoupling node management from specific container engine implementations in 2026 clusters.

The default config path is /var/lib/kubelet/config.yaml on most Linux distributions. Administrators can override this using the --config flag in the systemd unit file to specify custom parameters for node-specific tuning.

No.

Use systemctl status kubelet to verify service state. Check journalctl -u kubelet for errors indicating crash loops, CRI failures, or certificate issues preventing proper node registration and pod scheduling within the cluster control plane.

The node controller marks the node NotReady after the grace period expires. Pods remain scheduled but stop receiving traffic until kubelet recovers or the scheduler evicts them based on taint tolerations and disruption budgets.

Yes.

Kubelet enforces eviction thresholds defined in kubeletConfiguration. It removes unused images and dead containers when disk pressure exceeds highThresholdPercent, reclaiming space automatically to prevent node resource exhaustion during heavy workload deployments.

Kubeadm bootstraps clusters while kubelet manages individual nodes continuously. Kubeadm generates initial configs and certificates, whereas kubelet runs persistently as a systemd service handling actual container execution and health reporting throughout the cluster lifecycle.

Enable RotateCertificates in kubeletConfiguration and set serverTLSBootstrap true. The kubelet generates CSRs approved by the certificate controller, replacing expiring credentials without manual intervention or node restarts in production environments.

Kubelet validates resource requests against allocatable capacity before admission. When CPU, memory, or ephemeral storage limits exceed available reserves, it rejects the pod immediately rather than attempting deployment and failing later.

Yes.

Kubelet periodically updates NodeStatus objects via PATCH requests. It reports Ready, MemoryPressure, DiskPressure, and PIDPressure conditions based on local metrics, enabling controllers to make informed scheduling and eviction decisions across the cluster.

Pod Lifecycle Event Generator failures indicate runtime communication breakdowns. Common causes include unresponsive containerd sockets, excessive container counts overwhelming event processing, or filesystem permission issues preventing status updates from reaching the kubelet sync loop.

Define overrides in /etc/default/kubelet or use KubeletConfiguration files managed by GitOps tools. Avoid editing systemd units directly; instead apply structured configurations through cluster management APIs to ensure consistency and auditability across all nodes.