Ecstaticloud
Initializing0%
Ecstaticloud Logo
Back to Insights
DevOpsSeptember 5, 2026

Building Self-Healing Kubernetes Clusters with eBPF Tracing and Agentic AI

Learn how combining low-overhead eBPF kernel observability with autonomous AI agents can instantly diagnose and resolve transient Kubernetes runtime failures. Discover practical architecture patterns for automating root-cause analysis and remediation without human intervention.

Kubernetes clusters at scale operate in a state of continuous, micro-level degradation. While Kubernetes excels at handling binary failure modes—such as a container crashing with a non-zero exit code or failing a liveness probe—it struggles with transient, insidious runtime failures. Silent packet drops in the CNI plugin, ephemeral port exhaustion, localized cgroup memory throttling, and subtle kernel deadlocks frequently evade standard Prometheus scraping intervals and traditional alerting rules.

By the time a human engineer is paged, reads the Grafana dashboard, retrieves logs via kubectl, and correlates them with kernel metrics, minutes or hours of service degradation have elapsed.

To achieve true self-healing infrastructure, we must bridge two cutting-edge paradigms: eBPF (Extended Berkeley Packet Filter) for microsecond-level, non-intrusive kernel visibility, and Agentic AI for real-time, non-deterministic root-cause analysis and dynamic remediation.


Architectural Overview: The Autonomous Feedback Loop

A self-healing system requires four functional layers: continuous zero-overhead observation, real-time event streaming, contextual reasoning, and safe execution.

+-----------------------------------------------------------------------------------+
|                                KERNEL SPACE                                       |
|  +--------------------+   +--------------------+   +---------------------------+  |
|  | kprobe/tcp_drop    |   | tracepoint/sched   |   | kprobe/cgroup_mkdir       |  |
|  +---------+----------+   +---------+----------+   +-------------+-------------+  |
+------------|------------------------|----------------------------|----------------+
             | Ring Buffer            | Ring Buffer                | Ring Buffer
+------------v------------------------v----------------------------v----------------+
|                                USER SPACE (DaemonSet)                             |
|  +-----------------------------------------------------------------------------+  |
|  |                        eBPF Telemetry Collector                             |  |
|  |             (Enriches Kernel Events with K8s Pod/Namespace Meta)           |  |
|  +--------------------------------------+--------------------------------------+  |
+-----------------------------------------|-----------------------------------------+
                                          | gRPC / Protobuf
                                          v
+-----------------------------------------------------------------------------------+
|                           STREAM & CONTEXT ENGINE                                 |
|  +-----------------------------------------------------------------------------+  |
|  | Vector / Kafka Aggregator -> Anomaly Detector (e.g., Z-score spike on drops) |  |
|  +--------------------------------------+--------------------------------------+  |
+-----------------------------------------|-----------------------------------------+
                                          | JSON Payload Alert
                                          v
+-----------------------------------------------------------------------------------+
|                            AGENTIC REASONING ENGINE                               |
|  +-----------------------------------------------------------------------------+  |
|  | Autonomous Agent (ReAct Loop)                                               |  |
|  |  ├── Tools: [K8s API, eBPF SockDump, Cgroup Inspect, Prometheus Vector]     |  |
|  |  └── Memory: Historical Incidents + Topology Graph                          |  |
|  +--------------------------------------+--------------------------------------+  |
+-----------------------------------------|-----------------------------------------+
                                          | Remediation Plan (YAML CRD)
                                          v
+-----------------------------------------------------------------------------------+
|                             ACTUATION ENGINE                                      |
|  +-----------------------------------------------------------------------------+  |
|  | Remediation Operator (Validates RBAC, Blast-Radius Limits, Applies Action)    |  |
|  +-----------------------------------------------------------------------------+  |
+-----------------------------------------------------------------------------------+
  1. Kernel-Space Observation (eBPF): Probes run directly in the Linux kernel, capturing socket drops, TCP retransmissions, file descriptor bottlenecks, and memory allocation stalls at the source without altering container images or injecting sidecars.
  2. Context Enrichment: A user-space DaemonSet reads kernel events via perf/ring buffers and maps Linux thread groups (tgid/pid) and network namespaces directly to Kubernetes metadata (pod_name, namespace, container_id).
  3. Agentic Reasoning Loop: Instead of executing hardcoded conditional scripts (if X then Y), an autonomous AI agent consumes the telemetry, interacts with the cluster using targeted inspection tools, formulates a hypothesis, and generates a scoped mitigation plan.
  4. Deterministic Actuation Operator: A dedicated Kubernetes Controller validates the agent’s proposed remediation plan against strict policy guardrails (RBAC, rate-limiting, blast-radius constraints) before applying mutations to the cluster.

Phase 1: Deep Observability with eBPF

Standard metrics scrapers (like Prometheus) aggregate data at $10\text{s}$ to $60\text{s}$ intervals. Transient anomalies—such as a 200ms TCP connection reset storm—disappear inside these rolling averages. eBPF provides event-driven, microsecond-accurate telemetry directly from kernel probe points.

Tracking Transient TCP Drops in C

The following eBPF C program attaches to the kernel’s tcp_drop function (kprobe/tcp_drop). It captures packet drops, extracts the source/destination IPs and ports, and reads the socket state—giving us visibility into dropped SYN/ACK packets or queue overflows before user-space applications even log an HTTP 500 error.

// +build ignore
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

struct drop_event_t {
    u32 saddr;
    u32 daddr;
    u16 sport;
    u16 dport;
    u32 netns;
    u32 pid;
    u8 state;
};

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);
} events SEC(".maps");

SEC("kprobe/tcp_drop")
int BPF_KPROBE(tcp_drop, struct sock *sk, struct sk_buff *skb) {
    if (!sk)
        return 0;

    // Filter non-IPv4 for brevity
    u16 family = BPF_CORE_READ(sk, __sk_common.skc_family);
    if (family != AF_INET)
        return 0;

    struct drop_event_t *event = bpf_ringbuf_reserve(&events, sizeof(*event), 0);
    if (!event)
        return 0;

    event->saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr);
    event->daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr);
    event->sport = BPF_CORE_READ(sk, __sk_common.skc_num);
    
    u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport);
    event->dport = bpf_ntohs(dport);
    
    event->state = BPF_CORE_READ(sk, __sk_common.skc_state);
    event->pid = bpf_get_current_pid_tgid() >> 32;

    // Retrieve network namespace inode for K8s pod association
    struct net *net = BPF_CORE_READ(sk, __sk_common.skc_net.net);
    event->netns = BPF_CORE_READ(net, ns.inum);

    bpf_ringbuf_submit(event, 0);
    return 0;
}

char _license[] SEC("license") = "GPL";

Enriching Telemetry in User Space (Go)

The Go DaemonSet reads the ring buffer, translates raw network namespace inodes into Pod names by querying /proc or the local Container Runtime Interface (CRI), and streams rich JSON events to the ingestion pipeline.

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/cilium/ebpf/ringbuf"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

type DropEvent struct {
	SAddr u32
	DAddr u32
	SPort u16
	DPort u16
	NetNS u32
	PID   u32
	State u8
}

func main() {
	// Initialize Cilium eBPF objects loaded from compiled ELF...
	// (Boilerplate omitted for brevity)

	rd, err := ringbuf.NewReader(objs.Events)
	if err != nil {
		log.Fatalf("creating ringbuf reader: %s", err)
	}
	defer rd.Close()

	for {
		record, err := rd.Read()
		if err != nil {
			if err == ringbuf.ErrClosed {
				return
			}
			continue
		}

		var event DropEvent
		if err := binary.Read(bytes.NewReader(record.RawSample), binary.LittleEndian, &event); err != nil {
			continue
		}

		// Enriched lookup: resolve NetNS ID to Pod Spec
		podInfo := ResolvePodByNetNS(event.NetNS)

		fmt.Printf("[eBPF TCP_DROP] Pod: %s/%s | LocalPort: %d -> RemotePort: %d | Kernel State: %d\n",
			podInfo.Namespace, podInfo.Name, event.SPort, event.DPort, event.State)
	}
}

Phase 2: Building the Agentic AI Reasoning Engine

Static runbooks fail when multi-variable anomalies occur. For instance, a TCP Drop combined with a cgroup memory throttle in a dependent service requires holistic investigation, not a simple kubectl delete pod script.

We employ a ReAct (Reason + Act) pattern. The AI Agent receives an anomaly trigger, decides which diagnostic tools to invoke, analyzes output recursively, formulates a root cause, and proposes a structured remediation plan.

Defining Autonomous Diagnostic Tools

The agent is provided with scoped execution primitives (tools). It cannot execute arbitrary shell commands directly on the host; instead, it calls micro-tools wrapped in strict validation logic.

import json
from typing import Dict, Any
from langchain.tools import tool
from kubernetes import client, config

config.load_incluster_config()
v1 = client.CoreV1Api()
apps_v1 = client.AppsV1Api()

@tool
def inspect_pod_kernel_events(pod_name: str, namespace: str) -> str:
    """Queries recent eBPF kernel telemetry specific to the target Pod's network namespace."""
    # Fetch from local vector database or eBPF log store
    telemetry_data = {
        "pod": pod_name,
        "recent_tcp_drops": 142,
        "conntrack_table_full": True,
        "cgroup_memory_throttling_events": 12,
        "last_kernel_error": "nf_conntrack: table full; dropping packet"
    }
    return json.dumps(telemetry_data)

@tool
def get_pod_resource_limits(pod_name: str, namespace: str) -> str:
    """Fetches current CPU/Memory resource requests and limits for a given Pod."""
    pod = v1.read_namespaced_pod(name=pod_name, namespace=namespace)
    containers = pod.spec.containers
    result = []
    for c in containers:
        result.append({
            "container_name": c.name,
            "resources": c.resources.to_dict()
        })
    return json.dumps(result)

@tool
def propose_remediation_patch(
    target_kind: str, 
    target_name: str, 
    namespace: str, 
    patch_type: str, 
    patch_payload: Dict[str, Any],
    reasoning: str
) -> str:
    """Submits a formal RemediationPlan Custom Resource for validation and execution."""
    custom_api = client.CustomObjectsApi()
    
    crd_manifest = {
        "apiVersion": "healing.ecstaticloud.io/v1alpha1",
        "kind": "RemediationPlan",
        "metadata": {"generateName": "auto-heal-"},
        "spec": {
            "targetRef": {
                "kind": target_kind,
                "name": target_name,
                "namespace": namespace
            },
            "action": patch_type,
            "patch": patch_payload,
            "justification": reasoning,
            "status": "PendingValidation"
        }
    }
    
    res = custom_api.create_namespaced_custom_object(
        group="healing.ecstaticloud.io",
        version="v1alpha1",
        namespace=namespace,
        plural="remediationplans",
        body=crd_manifest
    )
    return f"RemediationPlan created successfully: {res['metadata']['name']}"

The ReAct Execution Loop

The Agent processes incoming eBPF telemetry alerts via an autonomous ReAct loop:

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

SYSTEM_PROMPT = """ You are an expert Site Reliability Engineer and Autonomous Kubernetes Operator.
You respond to microsecond eBPF kernel anomaly detections.
Your goal is to diagnose transient infrastructure failures using available tools and propose minimal, precise remediations.

RULES:
1. Always verify resource configurations and kernel events before proposing changes.
2. Never execute destructive actions (e.g., deleting PVs or namespaces).
3. Generate a structured RemediationPlan CRD using `propose_remediation_patch` as your final output.
"""

prompt = ChatPromptTemplate.from_messages([
    ("system", SYSTEM_PROMPT),
    MessagesPlaceholder(variable_name="chat_history"),
    ("human", "{input}"),
    MessagesPlaceholder(variable_name="agent_scratchpad"),
])

tools = [inspect_pod_kernel_events, get_pod_resource_limits, propose_remediation_patch]
llm = ChatOpenAI(model="gpt-4o", temperature=0)

agent = create_openai_functions_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# Example Event Payload from eBPF Aggregator
alert_payload = """
ANOMALY DETECTED:
Namespace: production
Pod: payment-gateway-7899b45f-x2z9l
Metric Spike: High TCP Drops + System Call Latency
eBPF Probes: kprobe/tcp_drop spiking, sys_enter_epoll_wait delayed > 500ms
"""

agent_executor.invoke({"input": alert_payload, "chat_history": []})

Phase 3: Safe Actuation via Deterministic Kubernetes Controller

Allowing an AI agent directly to apply destructive API commands (PATCH, DELETE) without a structural deterministic guardrail introduces systemic risk.

To prevent run-away AI agents from corrupting state, the AI only creates Custom Resources (RemediationPlan). A deterministic Kubernetes Operator acts as a safety barrier, validating the plan against rigid policy rules before calling the Kubernetes API.

The RemediationPlan Custom Resource Definition (CRD)

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: remediationplans.healing.ecstaticloud.io
spec:
  group: healing.ecstaticloud.io
  versions:
    - name: v1alpha1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                targetRef:
                  type: object
                  properties:
                    kind: { type: string }
                    name: { type: string }
                    namespace: { type: string }
                action:
                  type: string
                  enum: ["ScaleDeployment", "Patchsysctl", "IncreaseResourceLimits", "RestartStatefulSet"]
                patch:
                  type: object
                  x-kubernetes-preserve-unknown-fields: true
                justification: { type: string }
            status:
              type: object
              properties:
                state: { type: string }
                reason: { type: string }
  scope: Namespaced
  names:
    plural: remediationplans
    singular: remediationplan
    kind: RemediationPlan

Safety Validation inside the Controller (Reconciler Loop)

Written in Go using controller-runtime, the controller verifies policies (e.g., maximum limits, rate limits per hour) before executing the mutation.

func (r *RemediationPlanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	log := log.FromContext(ctx)

	var plan healingv1alpha1.RemediationPlan
	if err := r.Get(ctx, req.NamespacedName, &plan); err != nil {
		return ctrl.Result{}, client.IgnoreNotFound(err)
	}

	if plan.Status.State != "PendingValidation" {
		return ctrl.Result{}, nil
	}

	// GUARDRAIL CHECK 1: Rate Limiting
	if r.ExceedsRemediationThreshold(plan.Spec.TargetRef.Namespace) {
		plan.Status.State = "Rejected"
		plan.Status.Reason = "Rate limit exceeded: Too many automated remediations in namespace over past 1 hour."
		r.Status().Update(ctx, &plan)
		return ctrl.Result{}, nil
	}

	// GUARDRAIL CHECK 2: Blast-Radius Policy Enforcer
	switch plan.Spec.Action {
	case "IncreaseResourceLimits":
		// Prevent LLM from requesting unbounded memory spikes
		if err := r.validateResourceCap(plan.Spec.Patch); err != nil {
			plan.Status.State = "Rejected"
			plan.Status.Reason = fmt.Sprintf("Safety violation: %v", err)
			r.Status().Update(ctx, &plan)
			return ctrl.Result{}, nil
		}
	}

	// APPLY REMEDIATION
	log.Info("RemediationPlan passed policy validation. Executing...", "Plan", plan.Name)
	if err := r.ApplyPatch(ctx, plan.Spec); err != nil {
		plan.Status.State = "Failed"
		plan.Status.Reason = err.Error()
	} else {
		plan.Status.State = "Executed"
	}

	r.Status().Update(ctx, &plan)
	return ctrl.Result{}, nil
}

End-to-End Walkthrough: Resolving an Intermittent Ephemeral Port Exhaustion Failure

Let's walk through a real-world scenario to demonstrate the power of this system.

1. Root Cause Scenario

A microservice order-processor communicates with an external payment gateway via HTTP REST. Under high load, order-processor experiences intermittent $502\text{ Bad Gateway}$ errors.

  • Prometheus perspective: Pod CPU is at 45%, Memory is at 60%. HTTP 5xx errors are rising. No standard metrics indicate why sockets are failing.
  • eBPF perspective: eBPF probe kprobe/tcp_v4_connect detects thousands of connections rapidly entering TCP_SYN_SENT state and failing with error code -99 (EADDRNOTAVAIL). The socket layer is failing to allocate ephemeral local ports (net.ipv4.ip_local_port_range).

2. Event Ingestion & Processing

The eBPF collector immediately streams the kernel drop signal:

{
  "timestamp": "2026-03-31T09:14:22.00192Z",
  "event": "TCP_CONNECT_FAILED",
  "error_code": "EADDRNOTAVAIL",
  "pod": "order-processor-65778b74f4-m89xk",
  "namespace": "production",
  "netns_inode": 4026533102,
  "metrics": {
    "active_sockets_in_time_wait": 28410,
    "ip_local_port_range": "32768-60999"
  }
}

3. Agentic Diagnosis & Multi-Step Reasoning

The Agentic Engine receives this payload and initiates its ReAct chain:

  1. Observation: High rate of EADDRNOTAVAIL during tcp_v4_connect. active_sockets_in_time_wait is holding ~28k connections.
  2. Tool Execution (inspect_pod_kernel_events): Agent checks socket states inside the Pod's network namespace and identifies thousands of sockets trapped in TIME_WAIT due to standard HTTP keep-alives being disabled or rapidly closed by high concurrency.
  3. Hypothesis: Local ephemeral port space is completely saturated due to short-lived non-reused TCP connections sitting in TIME_WAIT for 60 seconds (default tcp_fin_timeout).
  4. Formulated Fix:
    • Enable TCP socket reuse (net.ipv4.tcp_tw_reuse = 1).
    • Expand local port range (net.ipv4.ip_local_port_range = 1024 65535).
  5. Action: Construct a RemediationPlan updating the deployment's pod spec init-container or CNI sysctl security context settings.
apiVersion: healing.ecstaticloud.io/v1alpha1
kind: RemediationPlan
metadata:
  name: auto-heal-port-exhaustion-89a7
  namespace: production
spec:
  targetRef:
    kind: Deployment
    name: order-processor
    namespace: production
  action: Patchsysctl
  patch:
    spec:
      template:
        spec:
          securityContext:
            sysctls:
              - name: net.ipv4.tcp_tw_reuse
                value: "1"
              - name: net.ipv4.ip_local_port_range
                value: "1024 65535"
  justification: "eBPF telemetry flagged EADDRNOTAVAIL socket errors. Local ephemeral ports exhausted due to high TIME_WAIT connections. Tuning sysctl parameters for socket reuse."

4. Controller Actuation & Verification

  1. The Remediation Operator receives the RemediationPlan.
  2. It verifies that net.ipv4.tcp_tw_reuse is on the pre-approved white-list of safe sysctl modifications.
  3. The Operator applies a rolling patch to the order-processor deployment.
  4. eBPF probes confirm that within $15\text{s}$, EADDRNOTAVAIL instances drop to 0.
  5. The incident is resolved automatically with a complete audit trail attached to the CRD status object.

Safety Guardrails and Production Best Practices

Deploying autonomous agents into production environments requires robust control mechanisms. Implementing the following boundaries prevents unexpected automated behaviors:

+-------------------------------------------------------------------------+
|                          SAFETY ARCHITECTURE                            |
|                                                                         |
|  +------------------------+      +-----------------------------------+  |
|  |   Blast Radius Caps    |      |    Multi-Agent Consensus          |  |
|  |  - Max 10% pod rollouts|      |   - Critical actions require      |  |
|  |  - Scope: Single NS    |      |     2/3 agent verification        |  |
|  +-----------+------------+      +-----------------+-----------------+  |
|              |                                     |                    |
|              +------------------+------------------+                    |
|                                 |                                       |
|                                 v                                       |
|                  +------------------------------+                       |
|                  |   Strict CRD Validation      |                       |
|                  |  - Schema checks             |                       |
|                  |  - Sysctl whitelist          |                       |
|                  +--------------+---------------+                       |
|                                 |                                       |
|                                 v                                       |
|                  +------------------------------+                       |
|                  |    Immutable Audit Trail     |                       |
|                  |  - CRD state recorded in Git |                       |
|                  |  - Complete log of actions   |                       |
|                  +------------------------------+                       |
+-------------------------------------------------------------------------+
  • Blast-Radius Budgeting: Limit automated updates to a maximum percentage of a cluster (e.g., maximum 1 Deployment mutation per namespace per hour).
  • Deterministic Guardrails via OPA/Gatekeeper: Run Open Policy Agent (OPA) constraints alongside your Remediation Operator to structurally reject invalid patches regardless of AI output.
  • Multi-Agent Consensus for High-Severity Actions: For cluster-wide mutations (e.g., adjusting node-level network settings), require consensus between two independent Agent instances (e.g., a "Diagnostic Agent" and an "Auditor Agent").
  • GitOps State Syncing: When the Remediation Operator successfully patches a resource in memory, it should simultaneously submit a Pull Request back to your Git repository (Flux / ArgoCD) to prevent GitOps drift from overwriting auto-healed changes.

Conclusion: The Era of Zero-MTTR Kubernetes

Combining eBPF's low-overhead observation with Agentic AI's multi-step reasoning transforms Kubernetes operations from reactive firefighting to real-time, self-healing orchestration. By isolating the AI’s non-deterministic reasoning layer behind a deterministic, CRD-driven Kubernetes Controller, platforms can safely resolve transient, deep-kernel performance bottlenecks—reducing Mean Time To Resolution (MTTR) from hours to milliseconds.