Podtrace

repository·main·Indexed 41 days ago

https://github.com/gma1k/podtrace

An eBPF-powered observability tool for Kubernetes providing on-demand, full-stack diagnostics from the kernel to the application layer without code instrumentation. It features a CLI for ad-hoc debugging and a Kubernetes operator for declarative tracing via PodTrace, PodTraceSession, and PodTraceSchedule Custom Resources.

Tokens
104.4K
Snippets
264
Records
400
Agent score
51%

What's inside Podtrace

  1. Overview of Podtrace

    main

    Podtrace is a lightweight, eBPF-driven diagnostic tool designed for Kubernetes applications. It provides full-stack observability by attaching eBPF programs directly to containers to observe real-time behavior without requiring prior configuration or application instrumentation.

    Key capabilities include:

    • Observability Scope: Correlates kernel events with application-layer behavior (network flows, TCP/UDP performance, file system activity, memory behavior, latency patterns, system calls, and high-level events like HTTP, DNS, and database queries).
    • Use Cases: Debugging service slowness, identifying latency origins, monitoring network/IO resource usage, tracing request flows, and performing production incident response.
    • Security: Because it runs privileged and loads eBPF into the kernel, release artifacts ship with SLSA v1.0 Build L2 provenance for verification.
  2. Overview of Podtrace features

    main

    Podtrace is a comprehensive observability tool providing deep insights across multiple layers:

    Network Tracing

    • TCP/UDP: Monitors connection latency, errors, RTT, state transitions, retransmissions, and bandwidth.
    • L7 Tracing: Captures HTTP (1.x, 2, 3/QUIC), DNS, TLS handshakes, and gRPC methods. Supports HTTP-over-TLS via uprobes for various libraries (OpenSSL, Go, Node.js, etc.).
    • Database/Cache: Traces PostgreSQL, MySQL, Redis (via hiredis), Memcached, and Kafka.

    System & Resource Monitoring

    • File System: Tracks I/O latency, throughput, and path tracking.
    • Memory: Monitors page faults and OOM kills.
    • CPU/Scheduling: Tracks thread blocking, CPU usage per process, and lock contention (futex/pthread).
    • Syscalls: Monitors process lifecycle and file descriptor leaks.

    Advanced Capabilities

    • Distributed Tracing: Extracts trace context from HTTP/gRPC and supports exporters like OTLP, Jaeger, Splunk HEC, Datadog, and Zipkin.
    • Performance Profiling: Integrates with pprof and perf to correlate BPF stack traces with slow events.
    • Multi-Pod Tracing: Supports targeting multiple pods via label selectors or namespaces.
    • PII Redaction: Configurable regex rules to scrub sensitive data before dispatch.
  3. Schedule recurring diagnoses with PodTraceSchedule CR

    main

    Use the PodTraceSchedule CR to automate nightly sweeps or on-call probes. It fires a fresh PodTraceSession on every cron tick, manages child sessions via owner references, and prunes history based on successfulSessionsHistoryLimit.

    Manual Trigger: You can manually trigger a scheduled session from the CLI.

    apiVersion: podtrace.io/v1alpha1
    kind: PodTraceSchedule
    metadata: { name: nightly-diagnose, namespace: my-app }
    spec:
      schedule: "0 2 * * *"
      concurrencyPolicy: Forbid
      successfulSessionsHistoryLimit: 7
      sessionTemplate:
        spec:
          selector: { matchLabels: { app: api } }
          duration: 5m
          filters: [dns, net]
          exporterRef: { name: prod-otlp }

    Manual trigger

    kubectl podtrace schedule trigger nightly-diagnose -n my-app

  4. Use ApplicationTrace for application-level continuous tracing

    main

    The ApplicationTrace Custom Resource (CR) is a high-level abstraction used to trace an entire application by defining it as a set of workloads via label selectors.

    When you create an ApplicationTrace, the operator automatically creates and owns a single PodTrace object. This PodTrace uses the union of all selectors provided in the ApplicationTrace to trace all matching pods at once. Because the operator owns the child PodTrace, deleting the ApplicationTrace will automatically garbage-collect the generated PodTrace via a cascade delete.

    Use ApplicationTrace instead of a plain PodTrace when you want:

    • To manage an application as a single logical entity.
    • To aggregate status across multiple workloads.
    • To use a single object to represent a collection of related services.
    apiVersion: podtrace.io/v1alpha1
    kind: ApplicationTrace
    metadata:
      name: checkout
      namespace: my-app
    spec:
      appSelector:
        matchSelectors:
          - matchLabels: { app.kubernetes.io/name: checkout, tier: frontend }
          - matchLabels: { app.kubernetes.io/name: checkout, tier: cart }
      exporterRef:
        name: prod-otlp
  5. How the CLI interacts with the kernel

    main

    The kubectl podtrace command behaves differently depending on your environment:

    • Real Clusters (EKS, GKE, etc.): The CLI spawns a short-lived privileged pod on the target node to run eBPF. This requires a one-time PodSecurity label on the namespace.
    • Local/Development (kind, minikube, docker-desktop): Since the workstation is effectively the node host, spawning a pod is unnecessary. Use the --local flag to load eBPF directly onto your workstation's kernel. This requires CAP_BPF or CAP_SYS_ADMIN capabilities on the binary.
    # Use --local for kind/minikube/docker-desktop
    kubectl podtrace --local -n my-app api-pod
  6. How Podtrace captures DNS traffic

    main

    Podtrace uses a dual-path approach to capture DNS activity, ensuring visibility even for workloads that do not use standard system libraries (like statically-linked Go binaries).

    1. Packet capture (cgroup_skb): This is the primary method. Podtrace attaches a cgroup_skb program to the pod's cgroup and parses DNS directly from UDP packets on port 53. This method is libc-independent and works for:
      • glibc, musl
      • Statically-linked Go (netgo resolver)
      • Distroless/scratch containers
      • Both IPv4 and IPv6
    2. libc getaddrinfo uprobe: A complementary source used to capture the "intent" of DNS lookups for applications using glibc.

    Because queries are emitted as soon as they are seen on egress (DNS_QUERY), Podtrace can capture the looked-up name even if a response is never received (e.g., in sparse or idle pods).

  7. Understand the Podtrace Binary Event Schema

    main
    Podtrace uses a binary wire format for events emitted by the BPF ring buffer. These events are consumed by the Go parser. The schema has evolved through several versions (V1 to V6), and the parser determines the version by checking the size of the incoming data record against known struct sizes. All multi-byte fields are encoded in little-endian format.
  8. Understand Podtrace issue identifiers

    main

    Continuous inspections and diagnostic detectors report issues. An issue's id is treated as a contractual address, similar to a metric name.

    • Stability: Adding an id is a minor change. Renaming or removing an id is a breaking change (must be documented in CHANGELOG.md under ### Breaking).
    • Why: The id is used as a label value in podtrace_issue_active{id=...}, in alerts, and in PodTraceSchedule triggers. Renaming an ID will silently break existing rules.

    Non-contractual elements:

    • Issue messages (human-readable text).
    • Which rule produces a specific ID.
    • Thresholds and For durations (tuning parameters).
    • Whether a specific rule exists for a failure mode.
  9. Security requirements for Podtrace

    main

    Because Podtrace interacts with the Linux kernel via eBPF, it has specific security requirements:

    • Privileges: Requires elevated privileges, specifically CAP_SYS_ADMIN or root access.
    • Input Validation: The tool validates all inputs including pod names, PIDs, and container IDs.
    • Sanitization: Process names are sanitized to prevent injection attacks.
    • Metrics Security: The Prometheus metrics endpoint includes rate limiting and security headers on HTTP responses.
  10. Understand DNS tracking limitations in container images

    main

    Podtrace tracks DNS name resolution by attaching a uprobe to the getaddrinfo function in the workload container's libc.

    Limitation: If your application is a statically-linked binary (common in Go) or runs on a distroless or scratch base image, there is no libc available to probe. In these cases, podtrace will emit a warning: DNS tracking disabled: no libc found in the target container...

    Impact: This is non-fatal. All other tracing capabilities (network, filesystem, CPU, memory, syscalls) will continue to function normally. To enable DNS tracking, you must use a workload image that ships a dynamic glibc or musl libc.

  11. Understand podtrace's scope and non-goals

    main

    To help with architectural planning, note the following boundaries of the podtrace project:

    • Linux-bound: The tracing core is built on eBPF, meaning it is strictly bound to the Linux kernel.
    • Observability only: Podtrace is an observation tool. It is not a policy engine, admission controller, or service mesh. It does not admit, mutate, or route workloads.
    • Controlled upgrades: There is no agent self-update mechanism. Agent versions are managed by the operator/cluster owner via standard deployment procedures.
  12. Target pods for tracing

    main

    Podtrace allows you to target one or many pods using several selection modes. It supports dynamic updates, meaning if pods matching your criteria are added or removed while Podtrace is running, the target cgroup filters are updated automatically.

    Available selection methods:

    • Single pod (legacy): Provide a single positional pod name.
    • Explicit pod list: Use the --pods flag with a comma-separated list of pod names or namespace/pod pairs.
    • Namespace-wide: Use --all-in-namespace to target every pod in a specific namespace.
    • Label selector: Use --pod-selector to target pods matching specific labels within a namespace.
    • Cross-namespace selector: Use --namespaces to specify multiple namespaces and --pod-selector to filter pods across all of them.
    # Example: Explicit pod list using namespace/pod syntax
    ./bin/podtrace --pods podtrace-test/alpine-test,podtrace-cross/nginx-cross --diagnose 30s
    
    # Example: Label selector across multiple namespaces
    ./bin/podtrace --namespaces podtrace-test,podtrace-cross --pod-selector app=podtrace-e2e --diagnose 60s