KubernetesXLVI · Packet Capture in KubernetesPacket capture
tcpdump in Kubernetes — the flags that matter
What you'll learn
- Construct BPF filters for Pod CIDR, Service IP, and port-range capture
- Use snap length, ring buffers, and time-stamping to control pcap size
- Decode VXLAN and IPIP overlays with tcpdump
- Read a pcap file safely after capture
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
tcpdump on a Linux VM is straightforward. tcpdump on a
Kubernetes node is the same tool with three additional
wrinkles: BPF expressions that match Pod CIDRs and Service
IPs, overlay decoders that surface the inner packet, and
file rotation that does not fill the host filesystem. This
lesson walks the flags that matter.
The minimum tcpdump command for Kubernetes
tcpdump -ni eth0 -s 0 -w /tmp/cap.pcap -W 5 -C 100 \
-e -tttt 'net 10.244.0.0/16'
| Flag | Why it matters |
|---|---|
-n | Disable DNS resolution. Without it, every packet triggers a reverse lookup that pollutes the capture and the host’s resolver. |
-i eth0 | The interface. On a node this is the physical NIC; the Pod traffic is on cni0 or a veth. |
-s 0 | Full snap length. Default 65535 is fine; the legacy default of 68 truncated packets. |
-w /tmp/cap.pcap | Write to file. Capturing to stdout is fine for a quick look but does not survive process death. |
-W 5 -C 100 | Rotate files: 5 files of 100 MB each, replacing the oldest. |
-e | Include link-layer header. Required for VLAN tags and overlay decoders. |
-tttt | Human-readable timestamps. |
net 10.244.0.0/16 | BPF filter. Matches the Pod CIDR. |
The cluster’s Pod CIDR is configured at kubeadm init time
or by the CNI. The standard defaults are 10.244.0.0/16
(Flannel, Calico default), 10.0.0.0/8 (some EKS), or
192.168.0.0/16. The cluster operator should know the
CIDR; the kubectl cluster-info dump output includes it.
kubectl cluster-info dump | grep -i cidr
BPF expressions for Kubernetes
BPF (Berkeley Packet Filter) is the in-kernel filter language tcpdump compiles your expression into. The expressions that matter for Kubernetes:
# A specific Pod IP
host 10.244.1.5
# A specific Service IP (ClusterIP)
host 10.96.45.200
# The Pod CIDR (all Pods)
net 10.244.0.0/16
# The Service CIDR (typically 10.96.0.0/12)
net 10.96.0.0/12
# A specific port
port 8080
# Combinations
'tcp and port 8080 and net 10.244.0.0/16'
'(src host 10.244.1.5 or src host 10.244.1.6) and dst port 443'
'tcp[tcpflags] & (tcp-syn) != 0 and not src host 10.244.1.5'
The last expression — tcp[tcpflags] — is a tcpdump
extension that examines TCP flags directly. It catches
SYNs, which is what you want when the symptom is “the
connection is not establishing.”
# Show only TCP SYNs (connection attempts)
tcpdump -ni eth0 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'
Overlay decoding
A cluster with a VXLAN overlay hides Pod IPs from the wire.
tcpdump decodes VXLAN if it sees UDP/4789 and the packet
is large enough:
tcpdump -ni eth0 -e -vv 'udp port 4789'
13:42:01.123456 node-1 > node-2: VXLAN, flags [I] (0x08), vni 1
IP 10.244.1.5.42184 > 10.244.2.6.8080: Flags [S], seq 100, win 64240
The first line is the outer header (UDP/4789, VXLAN VNI). The second is the inner IP packet. The Pod IPs are visible.
For IPIP (another common overlay), the tunnel device is
typically tunl0:
tcpdump -ni tunl0 host 10.244.1.5
For Geneve (used by some Calico configurations), UDP/6081:
tcpdump -ni eth0 -e -vv 'udp port 6081'
Snap length and ring buffers
tcpdump writes every packet to disk by default. On a busy
node, a 1-minute capture can be hundreds of MB. The
production-grade capture uses:
-s 0— full snap length (no truncation).-W 5 -C 100— 5 files of 100 MB each, ring-buffered.-c 1000— stop after N packets (good for “I want to see the next 1000 SYNs”).
The ring-buffer pattern is the production default: a bounded pcap that survives a crash, rotates without filling the disk, and can be deleted in one command after the investigation.
# Capture the next 60 seconds, rotating every 100 MB
timeout 60 tcpdump -ni eth0 -s 0 -w /tmp/cap.pcap \
-W 10 -C 100 'tcp and port 8080'
The -W flag is the file count; the -C flag is the file
size in MB. With 10 files of 100 MB, the worst case is 1 GB
on the host. Plan accordingly.
Reading the pcap after capture
Reading the pcap on the same host re-runs the kernel’s packet path and pollutes the capture with the reader’s packets. The production pattern:
- Capture on the node.
- Copy the pcap to an analyst workstation with
scporkubectl cp(from a debug Pod). - Read on the workstation with
tcpdump -r cap.pcaportshark -r cap.pcap.
# Read the pcap on an analyst workstation
tcpdump -nr /tmp/cap.pcap 'tcp and port 8080'
# Or with tshark for protocol-aware decoding
tshark -r /tmp/cap.pcap -Y 'tcp.port == 8080' \
-T fields -e ip.src -e ip.dst -e tcp.srcport -e tcp.dstport
The -r flag reads from a file. Do not re-capture on the
host.
Time-stamping and clock skew
A cluster’s nodes run NTP, but a capture that spans nodes
needs the timestamps to be comparable. Use -j adapter or
-tttt for human-readable time, and confirm the host clock
is sane:
# Check the host clock
date -u; ntpq -p
# Capture with nanosecond precision
tcpdump -ni eth0 --time-stamp-type=adapter -tttt
A 100 ms clock skew between two nodes turns a “packet arrived at node-2 50 ms after node-1 sent it” observation into garbage. The capture must be on NTP-synced hosts.
Quiz
Knowledge check · 4 questions
Q1. Which tcpdump flag combination is the standard production-safe pattern for capturing on a Kubernetes node?
Q2. A tcpdump capture on a node's eth0 will always show Pod IP addresses in the IP header.
Q3. An application reports intermittent 504s to a Service. You need to capture the TCP retransmissions to confirm the underlay is dropping packets. Construct the capture command and explain the analysis.
Pod app-a in ns-a calls Service svc-b in ns-b. The Service has 3 endpoints across 3 nodes. 504s occur ~1% of the time, only during business hours. The cluster uses Calico VXLAN. The application team suspects the underlay.
Q4. Explain what the BPF expression `tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0` does, and why it is useful for Kubernetes capture.
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Always use
-nto disable DNS resolution. A capture that triggers reverse lookups pollutes the host resolver and the capture itself. - Always use
-s 0for full snap length. The legacy default truncates packets and hides application data. - Always use a ring buffer (
-W N -C M). A capture that fills the host disk is a self-inflicted outage. - Always use a BPF filter. Capturing every packet on
eth0writes the entire node’s traffic to disk. Filter on the Pod CIDR, the Service CIDR, or a specific port. - Copy the pcap off the host before reading. Reading on
the host with
-i eth0while another process is capturing pollutes both captures. - Confirm the overlay before drawing conclusions.
Calico VXLAN uses UDP/4789, IPIP uses
tunl0, Cilium VXLAN uses UDP/8472, BGP-routed clusters have no encapsulation.