Skip to content

Troubleshooting Toolkit — tcpdump, nsenter, Hubble, Connectivity Tests

Vì sao chủ đề này quan trọng

Bốn file trước dựng mental model: IP plan, dataplane, packet path, Service, NetworkPolicy. File này biến mental model thành hành động: khi sự cố xảy ra lúc 3 giờ sáng, bạn cần biết gõ lệnh gì, ở đâu, để nhìn thấy gói tin thật và xác nhận giả thuyết — thay vì restart bừa và hy vọng.

Đặc thù của debug mạng GKE: phần lớn “sự thật” nằm ở những nơi kubectl không với tới — bên trong network namespace của Pod, trong bảng conntrack của node, trong eBPF map của anetd. Bộ công cụ ở đây cho phép bạn “chui vào” những nơi đó một cách có kỷ luật. Nguyên tắc xuyên suốt: quan sát trước, kết luận sau; đặt điểm quan sát đúng chặng (file 3) rồi mới chọn công cụ.

Cảnh báo vận hành: nhiều thao tác dưới đây yêu cầu quyền trên node (SSH/privileged Pod) và can thiệp ở cấp kernel. Chỉ thực hiện trên node có thể chấp nhận rủi ro, ưu tiên debug node đã cordon hoặc node trong môi trường staging khi có thể. Không chạy lệnh ghi (sửa iptables/conntrack) trên node production trừ khi thực sự hiểu hệ quả.

Công cụ 1: tcpdump bên trong network namespace của Pod

Vấn đề: Pod thường không có tcpdump, và ngay cả khi có, bạn muốn bắt gói ở đúng giao diện. Giải pháp là vào network namespace của Pod từ host và bắt gói ở đó.

Cách vào netns của Pod từ node

bash
# 1. Tìm container ID của Pod trên node (qua crictl)
CID=$(crictl ps --name <container-name> -q | head -n1)

# 2. Lấy PID của tiến trình container
PID=$(crictl inspect $CID | grep -m1 '"pid"' | grep -o '[0-9]\+')

# 3. Bắt gói trong netns của Pod, trên eth0 của Pod
sudo nsenter -t $PID -n tcpdump -ni eth0 -w /tmp/pod.pcap host <dest-ip>

Vì sao đây là điểm quan sát quý: tại eth0 của Pod, bạn thấy gói trước khi mọi NAT của host xảy ra — source là Pod IP thật, đích là thứ Pod thực sự gửi tới. So sánh với gói bắt được ở eth0 của node (sau SNAT/DNAT) cho biết chính xác NAT đã làm gì.

Mẫu so sánh hai điểm bắt

Để định vị nơi gói chết, bắt đồng thời ở hai điểm:

  • Trong netns Pod (nsenter -t $PID -n tcpdump -ni eth0).
  • Trên eth0 của node (tcpdump -ni eth0).

Nếu thấy gói ở netns Pod nhưng không thấy ở node → gói chết giữa veth và NIC (dataplane host: eBPF/iptables, hoặc routing). Nếu thấy ở cả hai nhưng không có reply → vấn đề ở phía VPC/đích/firewall. Đây là kỹ thuật khoanh vùng mạnh nhất.

Công cụ 2: nsenter cho debug cấp node và netns

nsenter cho phép chạy lệnh trong namespace của tiến trình khác. Ngoài -n (network namespace), các pattern hữu ích:

bash
# Xem bảng route trong netns của Pod
sudo nsenter -t $PID -n ip route

# Xem ARP/neighbor của Pod
sudo nsenter -t $PID -n ip neigh

# Xem địa chỉ và giao diện trong Pod
sudo nsenter -t $PID -n ip addr

# Thử kết nối từ chính netns của Pod (nếu có công cụ)
sudo nsenter -t $PID -n curl -sv http://<service>:<port>

Giá trị: tái hiện chính xác “Pod nhìn mạng như thế nào” mà không phụ thuộc image Pod có công cụ hay không — bạn dùng công cụ của host nhưng trong netns của Pod.

Truy cập node để chạy nsenter

Trên GKE, có vài cách lên node:

  • kubectl debug node/<node> -it --image=<toolbox> tạo một Pod debug gắn vào host namespace của node (kubectl debug node).
  • SSH vào node (nếu được phép) qua gcloud compute ssh.
  • Dùng một privileged debug Pod (hostNetwork: true, hostPID: true) trong môi trường cho phép.

kubectl debug node thường là cách sạch nhất vì không cần SSH và tự dọn dẹp.

Công cụ 3: ip route, arp, iptables — kiểm tra trạng thái dataplane

Trên node (host namespace)

bash
# Bảng route của node (thấy default route, route tới Pod CIDR cục bộ)
ip route

# Neighbor/ARP table
ip neigh

# (Cluster iptables mode) độ lớn bảng nat của Service
sudo iptables -t nat -L KUBE-SERVICES -n | head
sudo iptables-save -t nat | grep -c KUBE-SEP

# Xem rule DNAT của một ClusterIP cụ thể
sudo iptables-save -t nat | grep <clusterIP>

Trên cluster Dataplane V2, bạn sẽ không thấy chuỗi KUBE-SVC/KUBE-SEP cho Service (vì eBPF đảm nhiệm) — đây cũng là một cách xác nhận dataplane đang dùng. Khi đó dùng công cụ Cilium/Hubble thay cho iptables.

Công cụ 4: conntrack — bảng kết nối và giới hạn

conntrack là bảng theo dõi kết nối của netfilter, nền tảng cho mọi NAT có trạng thái (DNAT của Service, SNAT của masquerade). Khi conntrack đầy, kết nối mới bị drop — biểu hiện là “drop ngẫu nhiên dưới tải cao”, một trong những sự cố mạng khó chịu nhất vì không có lỗi rõ ràng.

bash
# Số entry hiện tại và giới hạn tối đa
sudo conntrack -C                       # count hiện tại
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# Liệt kê kết nối tới một đích
sudo conntrack -L -d <dest-ip>

# Theo dõi sự kiện conntrack thời gian thực (new/destroy)
sudo conntrack -E

Dấu hiệu conntrack là thủ phạm

  • nf_conntrack_count tiệm cận nf_conntrack_max.
  • Log kernel nf_conntrack: table full, dropping packet.
  • Drop tăng đột biến khi connection rate cao (workload tạo nhiều kết nối ngắn).

Hướng xử lý

  • Giảm connection churn ở ứng dụng: dùng connection pooling, keep-alive (giảm số 5-tuple mới).
  • Rà soát timeout: kết nối TIME_WAIT/UDP giữ entry lâu làm phình bảng.
  • Cân nhắc workload tạo kết nối ngắn hàng loạt (ví dụ một số pattern gọi external API) — đây thường là gốc rễ thật, không phải “tăng max”.

Lưu ý: tăng nf_conntrack_max chỉ là giảm đau tạm thời; gốc rễ thường là connection churn của ứng dụng.

Công cụ 5: Hubble — observability của Dataplane V2

Hubble là lớp observability của Cilium, có sẵn trên cluster Dataplane V2, cho phép quan sát flow ở cấp identity thay vì chỉ gói thô (network observability/Hubble). Đây là công cụ mạnh nhất để trả lời “vì sao gói này bị drop”.

bash
# Quan sát flow thời gian thực (cần Hubble được bật/relay)
hubble observe --follow

# Lọc flow bị drop
hubble observe --verdict DROPPED

# Lọc theo namespace/pod
hubble observe --namespace payments --pod checkout

# Xem flow bị NetworkPolicy chặn
hubble observe --verdict DROPPED --type policy-verdict

Vì Hubble hiểu identity và policy, nó cho biết flow bị chặn vì policy nào, điều mà tcpdump (chỉ thấy gói biến mất) không nói được. Kết hợp với network policy logging (file 5), đây là cặp công cụ chính cho debug NetworkPolicy.

Công cụ 6: GCP Connectivity Tests — kiểm tra đường đi ở tầng VPC

Khi nghi ngờ vấn đề ở tầng VPC (firewall, route, peering) chứ không phải trong node, Connectivity Tests của Network Intelligence Center mô phỏng đường đi của gói qua cấu hình VPC và chỉ ra nơi bị chặn (Connectivity Tests).

bash
gcloud network-management connectivity-tests create pod-to-onprem \
  --source-ip-address=<pod-ip> \
  --destination-ip-address=<onprem-ip> \
  --destination-port=5432 \
  --protocol=TCP \
  --source-network=projects/<proj>/global/networks/prod-vpc

Connectivity Tests phân tích cấu hình (config-based), không gửi gói thật, nên hữu ích để xác nhận firewall/route cho phép đường đi — bổ trợ cho tcpdump (kiểm tra thực tế gói). Dùng nó để loại trừ nhanh “có phải firewall VPC chặn không” trước khi mất công bắt gói.

Công cụ 7: eBPF tracing với bpftrace (ca khó)

Khi các công cụ trên chưa đủ — ví dụ nghi ngờ drop xảy ra ở một điểm cụ thể trong kernel — bpftrace cho phép gắn probe vào kernel để quan sát. Đây là công cụ cho ca khó và phải dùng thận trọng.

bash
# Đếm các lý do kernel drop gói (kfree_skb với reason, kernel mới)
sudo bpftrace -e 'tracepoint:skb:kfree_skb { @[args->reason] = count(); }'

# Theo dõi gói bị drop kèm stack (định vị nơi drop)
sudo bpftrace -e 'kprobe:kfree_skb { @[kstack] = count(); }'

Lưu ý quan trọng trên Dataplane V2: cluster không hỗ trợ nạp chương trình eBPF tùy biến và có thể xung đột với agent eBPF bên thứ ba (file 2). bpftrace để quan sát (read-only tracing) thường khác với việc nạp eBPF datapath, nhưng vẫn phải hết sức cẩn trọng và ưu tiên môi trường staging/node cordon. Đây là công cụ cuối cùng, không phải đầu tiên.

Công cụ 8: ss và socket statistics — trạng thái kết nối thực

tcpdump cho thấy gói trên dây; ss cho thấy trạng thái socket trong kernel — bổ trợ nhau. Trong netns của Pod (qua nsenter) hoặc trên node:

bash
# Liệt kê socket TCP kèm trạng thái và hàng đợi
sudo nsenter -t $PID -n ss -tanp

# Đếm socket theo trạng thái (TIME_WAIT, ESTABLISHED, SYN-SENT...)
sudo nsenter -t $PID -n ss -tan state time-wait | wc -l

# Xem hàng đợi nhận/gửi để phát hiện nghẽn ứng dụng
sudo nsenter -t $PID -n ss -tin

Giá trị: số TIME_WAIT cao gợi ý connection churn lớn (liên quan conntrack/Cloud NAT — file 3, 4); SYN-SENT treo gợi ý gói SYN không tới đích hoặc reply bị chặn; Recv-Q/Send-Q đầy gợi ý app không đọc/ghi kịp (vấn đề ứng dụng, không phải mạng).

Công cụ 9: mtr và Path MTU — chẩn đoán đường dài và treo payload lớn

Khi kết nối tới on-prem/internet bị mất gói rải rác hoặc treo khi truyền dữ liệu lớn:

bash
# Trace có thống kê mất gói theo từng hop
sudo nsenter -t $PID -n mtr -rwzbc 100 <dest-ip>

# Kiểm tra Path MTU bằng ping với cờ không phân mảnh
sudo nsenter -t $PID -n ping -M do -s 1472 <dest-ip>

Nếu ping -M do với payload lớn thất bại nhưng payload nhỏ thành công, đó là dấu hiệu MTU mismatch / Path MTU Discovery bị chặn (file 3) — hướng xử lý là MSS clamping hoặc chỉnh MTU, không phải sửa app.

Công cụ 10: VPC Flow Logs — bằng chứng ở tầng VPC

Khác với Connectivity Tests (phân tích cấu hình), VPC Flow Logs ghi lại mẫu lưu lượng thực đi qua VPC, gồm src/dst, port, số byte và hành động (VPC Flow Logs). Hữu ích để xác nhận traffic có thực sự rời/đến node như kỳ vọng và có bị firewall từ chối không. Lưu ý: Flow Logs lấy mẫu (sampling) và mặc định không thấy traffic same-node giữa các Pod trừ khi bật intranode visibility (file 3). Kết hợp Flow Logs (đã xảy ra gì ở VPC) với Connectivity Tests (cấu hình cho phép gì) cho bức tranh tầng VPC đầy đủ.

Quy trình debug chuẩn (kết hợp công cụ)

  1. Khoanh path (file 3): từ triệu chứng xác định đang ở path nào (same-node, cross-node, Service, egress, ingress).
  2. Loại trừ tầng VPC: chạy Connectivity Tests để xác nhận firewall/route cho phép đường đi.
  3. Xác nhận policy (nếu nghi bị chặn): Hubble --verdict DROPPED + network policy logging.
  4. Bắt gói đúng chặng: nsenter vào netns Pod + tcpdump; so sánh với tcpdump trên node để định vị NAT/drop.
  5. Kiểm tra tài nguyên hữu hạn: conntrack count/max; endpoint map (Dataplane V2).
  6. Ca khó: bpftrace để tìm điểm drop trong kernel.
  7. Chỉ thay đổi sau khi định vị: không “sửa mù”.

Real-world scenarios

Scenario A: Drop ngẫu nhiên dưới tải — conntrack đầy

Dịch vụ gọi external API timeout ngẫu nhiên lúc cao điểm. conntrack -C cho thấy count gần max; log kernel có table full. Gốc rễ: ứng dụng mở kết nối mới cho mỗi request (không pool). Sửa: bật connection pooling + keep-alive; conntrack ổn định trở lại.

Scenario B: Kết nối bị chặn không rõ lý do — Hubble chỉ ra policy

A không gọi được B, tcpdump thấy gói rời A nhưng không có reply. Hubble --verdict DROPPED --type policy-verdict cho thấy một egress policy chặn A. Sửa policy. Thời gian từ vài giờ xuống vài phút nhờ đúng công cụ.

Scenario C: Egress on-prem bị chặn — tcpdump + Connectivity Tests

Pod gọi DB on-prem bị từ chối. tcpdump ở on-prem thấy source là node IP (không phải Pod IP). Connectivity Tests xác nhận route/firewall VPC ổn. Gốc rễ: ip-masq-agent SNAT (file 3). Sửa: thêm dải on-prem vào nonMasqueradeCIDRs.

Scenario D: 502 qua Ingress — bắt gói ở Pod để xác nhận health check

Ingress trả 502 ngắt quãng. nsenter + tcpdump trên Pod backend cho thấy health check của Google đến nhưng readiness chưa pass đúng lúc. Sửa: căn chỉnh readiness probe và health check NEG (file 3).

Common mistakes / anti-patterns

  1. Bắt gói sai chặng. Bắt ở node khi vấn đề ở veth Pod (hoặc ngược lại) → bỏ lỡ sự thật.
  2. Quên rằng NAT làm địa chỉ đổi giữa các chặng. Không biết “lúc này gói mang IP gì” → đọc nhầm.
  3. Tăng nf_conntrack_max thay vì sửa connection churn. Giảm đau, không trị bệnh.
  4. Tìm chuỗi KUBE-SVC trên cluster Dataplane V2. Không có — phải dùng Hubble/cilium.
  5. Dùng bpftrace/nạp eBPF bừa trên node production Dataplane V2. Rủi ro xung đột với anetd.
  6. Bỏ qua Connectivity Tests, lao vào tcpdump ngay. Mất thời gian khi vấn đề chỉ là một firewall rule.
  7. Chạy lệnh ghi (sửa iptables/conntrack) trên node production khi chưa hiểu hệ quả.

GCP-native implementation guidance

Pod debug nhanh trong netns của Pod đích

bash
# Tạo ephemeral container chia sẻ netns với Pod đang chạy
kubectl debug -it <pod> --image=nicolaka/netshoot --target=<container>
# Trong shell: tcpdump, dig, curl, ss... chạy trong đúng netns của Pod

Debug ở cấp node

bash
kubectl debug node/<node> -it --image=nicolaka/netshoot
# Sau đó dùng nsenter, ip route, conntrack, iptables... ở host namespace

Bật Hubble relay/UI (nếu chưa)

bash
# Kiểm tra thành phần Cilium/anetd và trạng thái Hubble
kubectl -n kube-system get pods -l k8s-app=cilium
kubectl -n kube-system get pods -l k8s-app=hubble-relay

Kết nối với Architecture Framework

  • Operational excellence: có quy trình và công cụ debug chuẩn hóa giảm MTTR, đúng tinh thần vận hành xuất sắc (Operational excellence).
  • Reliability: phát hiện sớm tài nguyên hữu hạn (conntrack, endpoint map) trước khi chúng gây drop diện rộng (Reliability pillar).

References

Phụ lục: bộ công cụ tối thiểu nên có sẵn

Image debug

Chuẩn bị sẵn một image debug (ví dụ netshoot) chứa tcpdump, dig, curl, ss, iproute2, conntrack-tools, mtr. Khai báo cách dùng kubectl debug trong runbook để mọi người trong team dùng nhất quán, thay vì mỗi người tự cài công cụ khác nhau.

Runbook ánh xạ triệu chứng → công cụ

Triệu chứngCông cụ đầu tiênCông cụ xác nhận
Kết nối bị chặn nghi do policyHubble --verdict DROPPEDnetwork policy logging
Drop ngẫu nhiên dưới tảiconntrack -C / maxlog kernel table full
Egress SNAT saitcpdump ở đích (xem source IP)kiểm tra ip-masq-agent ConfigMap
Nghi firewall/route VPCConnectivity Teststcpdump ở node
502 qua LB/Ingresstcpdump ở Pod backendhealth check NEG / readiness
Service không tới backendEndpointSlice Readyiptables/Hubble theo dataplane

Vì sao chuẩn hóa quan trọng hơn “mẹo hay”

Debug mạng dễ trở thành “nghệ thuật cá nhân” của một vài kỹ sư kỳ cựu. Điều đó nguy hiểm: khi họ vắng mặt, MTTR tăng vọt. Giá trị thật của file này không nằm ở từng lệnh riêng lẻ mà ở quy trình chuẩn: khoanh path → loại trừ VPC → xác nhận policy → bắt gói đúng chặng → kiểm tra tài nguyên hữu hạn. Khi quy trình này được viết thành runbook và luyện qua game day, cả team debug được, không chỉ một người.

Luyện tập qua game day

  • Cố tình tạo một NetworkPolicy chặn nhầm, để team dùng Hubble tìm ra.
  • Mô phỏng conntrack đầy bằng workload connection-churn cao, luyện chẩn đoán.
  • Tạo một firewall rule chặn health check, luyện dùng Connectivity Tests + tcpdump.
  • Đặt mục tiêu MTTR cho từng kịch bản và đo cải thiện theo quý.

Ghi nhớ cốt lõi

  • Bắt gói đúng chặng (netns Pod vs node) quan trọng hơn bắt nhiều gói.
  • Luôn biết “lúc này gói mang IP gì” — NAT đổi địa chỉ giữa các chặng.
  • Hubble + policy logging trả lời “vì sao bị drop”; tcpdump trả lời “gói có tới không”.
  • Connectivity Tests loại trừ tầng VPC nhanh trước khi bắt gói.
  • conntrack/endpoint map là tài nguyên hữu hạn — theo dõi và cảnh báo sớm.
  • Trên Dataplane V2, tránh nạp eBPF tùy biến; bpftrace chỉ cho ca khó, ưu tiên staging.

Lời khuyên cuối: ghi lại mọi lần debug thành tri thức chung

Mỗi sự cố mạng được giải quyết là một cơ hội làm giàu runbook. Sau mỗi lần điều tra, hãy ghi lại: triệu chứng ban đầu, path nghi ngờ, công cụ đã dùng, manh mối quyết định, và gốc rễ thật. Theo thời gian, bộ ghi chép này biến thành một “cây quyết định” giúp người sau khoanh vùng nhanh hơn nhiều. Giá trị lớn nhất không phải là giải được một sự cố cụ thể, mà là biến năng lực debug từ kỹ năng cá nhân thành tài sản của cả team — đó cũng chính là tinh thần của một production handbook. Một mạng GKE được vận hành tốt không phải là mạng không bao giờ có sự cố, mà là mạng nơi mọi sự cố đều để lại bài học có thể tái sử dụng.