Linkerd’s tap command lets you peek at live HTTP traffic flowing between your Kubernetes services, but it doesn’t actually intercept or modify anything; it’s a passive observer that spins up a temporary proxy next to the target pod to sniff its traffic.

Let’s see it in action. Imagine you have a frontend service talking to a backend service. You want to see what the frontend is actually sending to the backend.

First, make sure you have Linkerd installed and your frontend and backend pods are running and part of the Linkerd mesh.

# Assuming your frontend is in the 'default' namespace and called 'frontend-abcde-12345'
# and your backend is in the 'default' namespace and called 'backend-fghij-67890'

# To tap traffic originating from the frontend pod to the backend service:
linkerd tap deploy/frontend -n default --to deploy/backend

# Or, to tap traffic destined for the backend pod from any source:
linkerd tap deploy/backend -n default

When you run linkerd tap, Linkerd injects a temporary "tap" proxy alongside the specified pod. This proxy subscribes to the Kubernetes API for events related to the target pod (or pods matching a deployment/statefulset/etc.). When traffic hits the target pod’s network interface, the tap proxy observes it before it reaches the actual application container. It then formats this information and streams it back to your terminal. The tap proxy is ephemeral; it’s created when you run the tap command and destroyed when you stop it (e.g., by pressing Ctrl+C).

The tap command is incredibly powerful for debugging. You can see the exact HTTP requests being made, including headers, bodies (if not too large and configured to be shown), status codes, and latency. This is invaluable for understanding why a service might be failing or behaving unexpectedly.

Here’s a breakdown of what you’re controlling:

  • Target: You specify what you want to observe. This can be a specific pod (pod/my-pod), a deployment (deploy/my-app), a statefulset (sts/my-db), or even a Kubernetes service (svc/my-service). When you target a deployment or statefulset, tap will observe traffic for all current pods belonging to that workload.
  • Namespace: Crucial for targeting the correct resources (-n my-namespace).
  • Direction (--to or --from): You can filter traffic by its destination or origin. --to deploy/backend means "show me traffic going to the pods managed by the backend deployment." --from deploy/frontend means "show me traffic originating from the pods managed by the frontend deployment." If you omit these, you’ll see all traffic for the targeted pod(s).
  • Output Format: By default, it’s human-readable. You can get JSON output with -o json for programmatic processing.
  • Stream Limits: For very high-traffic services, tap can overwhelm your terminal. You can limit the number of requests shown with --max-requests N.

The most surprising thing about linkerd tap is that it doesn’t require any application-level instrumentation or changes to your existing Kubernetes deployments. It works by leveraging Linkerd’s control plane and a temporary proxy injected at runtime, making it a zero-impact way to gain deep visibility into your service communication. It’s essentially a dynamic, on-demand network tap for your Kubernetes services.

When tap is active, the data is streamed through the Linkerd control plane and then to your linkerd tap CLI. This means the control plane needs to be healthy and accessible from where you’re running the command. If the control plane pods are crashing or unreachable, tap will fail to start or stream data.

Understanding the tap command means you can effectively debug inter-service communication issues without needing to SSH into pods, run tcpdump, or add complex logging. The next step in observability is often diving into Linkerd’s metrics and tracing capabilities.

Want structured learning?

Take the full Linkerd course →