Skip to main content
Kata Containers (and similar micro-VM runtimes) run each pod inside a lightweight virtual machine with its own guest kernel. The host-level eBPF collector deployed as a DaemonSet cannot observe syscalls across that VM boundary — the same constraint as ECS Fargate. So the same answer applies: the in-workload collector runs inside the guest, wrapped around your application.

How it works

The collector binary is the same dag-fargate-agent used on ECS Fargate; it detects at startup that it is running in a Kubernetes pod rather than a Fargate task. It runs as PID 1 inside your application container, installs a seccomp-BPF filter that traps only the ~20 syscalls Hilt cares about (execve, open, unlink, rename, chmod, connect, etc.), then fork+execs your original application. Every descendant process inherits the filter; everything else runs at native speed, uninstrumented. All of this happens inside the pod’s guest VM — nothing needs to cross the hypervisor boundary. You do not rebuild your application image. An initContainer (the same installer image used for Fargate) copies the agent binary into a pod-scoped emptyDir volume before your app starts; the container’s command is rewritten to launch the agent first, which then launches your original command.
This mechanism is for pods whose runtimeClassName puts them behind a guest kernel (Kata, and by extension other VM-isolated runtimes). Ordinary runc pods on the same cluster should keep using the eBPF DaemonSet — it has strictly more coverage. The two coexist: the DaemonSet simply cannot see Kata pods, and the in-workload agent fills exactly that hole.

Prerequisites

  • A Kubernetes cluster with a Kata runtime class (e.g. runtimeClassName: kata), x86_64 or arm64
  • A reachable Hilt ingest endpoint (DAG_SHIP_URL, provided during onboarding)
  • The installer image URI Hilt gives you at onboarding (the same dag-fargate-installer image used for ECS Fargate). The nodes must be able to pull it.

What gets injected into your pod spec

If something fails to attach at runtime, the agent fails open: your application always starts and runs normally, with or without telemetry.

Installation

There are two ways to get the collector into Kata pods. Both produce the same pod spec.

Automatic injection (admission webhook)

The dag-kata-injector webhook watches pod creation. Every pod whose runtimeClassName is kata or starts with kata- (kata-qemu, kata-clh, kata-fc, …) is created with the collector already wrapped around its entrypoint. Ordinary runc pods are never sent to the webhook. Pods that already exist are not changed; they pick up the collector the next time they are recreated (a rollout, a reschedule, or a scale-up).
1

Apply the manifest

Download kata-injector.yaml for your collector version (it ships next to daemonset.yaml), fill in the placeholders, and apply it:
Use the same DAG_CLUSTER_ID as your DaemonSet so Kata pods and node-level telemetry group under one cluster. No cert-manager is needed: the webhook creates its own TLS certificate on first start.
2

Roll a Kata workload

The annotation reads injected mode=full containers=…. If a pod was not injected, it says why.
Safe by default. The webhook never blocks a pod. If it is unavailable, or anything about a pod cannot be handled, the pod is created exactly as submitted. A pod created while the webhook was unavailable runs without the collector until it is next recreated; the webhook runs two replicas to keep that window closed. Other defaults:
  • Pod Security. In namespaces that enforce the Pod Security baseline or restricted level, SYS_PTRACE is not allowed, so pods there are injected in metadata mode (no capability). If your API server enforces baseline cluster-wide through its admission configuration, set DAG_INJECT_DEFAULT_MODE=metadata on the webhook.
  • Image entrypoints. Kubernetes command replaces an image’s ENTRYPOINT instead of prepending to it. For containers that don’t set command, the webhook reads the original ENTRYPOINT/CMD from the image registry (public images by default). For private registries, enable DAG_INJECT_PULL_SECRETS=true (and the optional secret-read rule in the manifest), set command explicitly, or annotate the pod:
    A container whose entrypoint cannot be determined is left unwrapped rather than started with a guessed command. The pod gets a dag.hilt.ai/inject-skipped annotation and kubectl shows a warning.

Manual injection (pod template patch)

Use this if you cannot run an admission webhook in your cluster.
1

Add the volume and initContainer

In your pod template (Deployment, StatefulSet, Job — anything that produces a pod spec):
2

Wrap your container's entrypoint

Rewrite the app container’s command so the agent starts first. If your image relies on its default ENTRYPOINT/CMD, spell them out explicitly — Kubernetes command/args replace, they never prepend.
3

Add environment and identity

There is no metadata endpoint inside the guest VM, so the pod spec hands the agent its own coordinates via the downward API:
The agent never contacts the Kubernetes API server — identity is entirely env-driven, so no serviceaccount token or RBAC is needed.
4

Roll out and verify

Apply the change and check the wrapped container’s logs: the line kata: identity loaded — host_id=<pod-uid> host_type=kata … appears on stderr before your application’s own output.
A complete, runnable reference pod is maintained at deploy/kata/pod-reference.yaml.

Configuration

Coverage

Matches the ECS Fargate collector — precise exec/file/network-lifecycle events via seccomp+ptrace in full mode, and the metadata kill-switch mode — with one Kata-specific difference: network byte counters are not available. The sampled sock_diag byte counters need INET_DIAG in the kernel serving the pod, and Kata’s default guest kernels are built without it, so on Kata the agent reports network connection lifecycle (who connected where, when) without byte volumes. If your Kata deployment ships a custom guest kernel with CONFIG_INET_DIAG, byte sampling lights up automatically. Data-flow lineage, cgroup lifecycle events, and latency probes are eBPF-collector features and are not available inside VM-isolated pods. Visibility is scoped to the wrapped container’s process subtree — one agent per wrapped container.

Identity mapping

Kata pods are as ephemeral as Fargate tasks. Expect turnover in the fleet view; the namespace and pod_name tags (and your own DAG_TAGS) give you stable grouping across pod restarts.

Verification

After deploying, confirm on the Collectors page that:
  • The pod appears with host_type = kata
  • It’s grouped under the correct DAG_CLUSTER_ID
  • The pod_name, namespace, and runtime_class tags are present
  • Exec and network events are arriving

Upgrade

Update the installer image tag (DAG_INJECT_INSTALLER_IMAGE on the webhook, or the initContainer image in a patched template) and roll the workload. The agent binary is copied fresh from the initContainer on every pod start, so a new pod always picks up the latest agent.

Uninstall

Automatic: kubectl delete -f kata-injector.yaml (and the dag-kata-injector-tls Secret), then roll your Kata workloads. New pods are created without the collector. Manual: Remove the injected pieces (initContainer, emptyDir volume, command rewrite, SYS_PTRACE capability, and DAG_* environment variables) from the pod template and roll the workload.
Last modified on October 8, 2026