用 tcpdump 對指定 k8s pod 抓包


環境要求

  • 執行命令的主機可以使用 kubectl 命令。

  • 執行命令的主機可以通過 ssh (使用當前用戶名)訪問容器所在的主機,或者執行命令的主機本身就是容器所在的主機。

  • 容器所在的主機可以使用 tcpdumpdocker/crictl 命令,並且當前用戶有權限執行這些命令。

創建腳本 sniff

#!/usr/bin/env bash

set -euxo pipefail

NAMESPACE=${1}; shift
POD=${1}; shift

eval "$(kubectl get pod \
    --namespace "${NAMESPACE}" \
    "${POD}" \
    --output=jsonpath="{.status.containerStatuses[0].containerID}{\"\\000\"}{.status.hostIP}" \
    | xargs -0 bash -c 'printf "${@}"' -- 'CONTAINER_ID=%q\nHOST_IP=%q')"


if [[ ${CONTAINER_ID} == 'docker://'* ]]; then
    CONTAINER_ENGINE=docker
    CONTAINER_ID=${CONTAINER_ID#'docker://'}
elif [[ ${CONTAINER_ID} == 'containerd://'* ]]; then
    CONTAINER_ENGINE=containerd
    CONTAINER_ID=${CONTAINER_ID#'containerd://'}
fi

if [[ -z $(ip address | sed -n "s/inet ${HOST_IP}\//found/p") ]]; then
    SHELL_COMMAND='eval ssh "${HOST_IP}" bash -euxo pipefail -'
else
    SHELL_COMMAND='source /dev/stdin'
fi

${SHELL_COMMAND} <<EOF
PATH=\${PATH}:/usr/local/bin

if [[ ${CONTAINER_ENGINE@Q} == docker ]]; then
    PID=\$(docker inspect --format '{{.State.Pid}}' ${CONTAINER_ID@Q})
elif [[ ${CONTAINER_ENGINE@Q} == containerd ]]; then
    PID=\$(crictl inspect --output go-template --template '{{.info.pid}}' ${CONTAINER_ID@Q})
fi
IF_NO=\$(<"/proc/\${PID}/root/sys/class/net/eth0/iflink")
IF=\$(ip link | sed -n "s/^\${IF_NO}: \([^@]\+\).*$/\1/p")

tcpdump -i "\${IF}" ${@@Q}
EOF

使用

./sniff <NAMESPACE> <POD> [TCPDUMP ARG]...
# 例子:./sniff kubernetes-dashboard kubernetes-dashboard-7c4b498cb4-slkk8 -U -w -

原理

  • 容器網絡通常由 veth-pair 實現,和 socketpair 一樣有兩個網絡接口,兩個 veth 接口分別設置在主機 network namespace 側和容器 network namespace 側,兩個 veth 接口對應一個唯一“編號”,只要得到容器內(network namespace)其中一個 veth 的“編號”,就可以根據“編號”在主機側找到另一個的 veth 接口。然后在主機側用 tcpdump 抓取這個 veth 接口的包就行了。

  • 如果知道容器在主機上的 pid,容器內 veth 的接口“編號”可以在主機上執行命令 cat /proc/<PID>/root/sys/class/net/eth0/iflink 得到。

  • 如果知道容器的 ID,容器在主機上的 pid 可以在主機上執行命令 docker inspectcrictl inspect 得到。

  • kubectl get pod 可以得到 Pod 容器的 ID,以及容器所在的主機 IP。

注意:一個 pod 可能包含多個容器,這些容器共享共同一個 network namespace,在 veth 上抓包會抓取 pod 內所有容器的流量


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM