Kubernetes 中使用插件 sniff 進行網絡抓包

背景

在 Kubernetes 的實際使用中,咱們常常須要配合業務調查問題,對於微服務來講,這個問題更多的是查看 API 的調用狀況,這些API或者採用 RPC 協議或者是採用 HTTP 的協議。這兩種協議都是基於 TCP 的協議,因此通常咱們會到容器中使用 tcpdump 工具來抓包,而後就地或者拿出來放到 wireshark 圖形化軟件裏面分析。java

這種狀況下,須要咱們的基礎鏡像提早把 tcpdump 等排查工具打包進去,不然線上安裝 debug 軟件,一者違反安全規則,另外若是須要支持的 Pod 過多,安裝 debug 工具自己就有不小的工做量。git

krew

在 Kubernetes 中,有一個插件命令叫作 krew,能夠經過這個命令來安裝一個叫作 sniff 的插件工具來完成這個工做。下面咱們先看看如何安裝這個 krew 插件。github

krew 的項目地址在:https://github.com/kubernetes-sigs/krew 。若是有興趣能夠自行瀏覽,咱們這裏介紹下在 Centos 等 Linux 下面如何安裝。api

首先,須要確認系統安裝了 git 。安全

其次,複製下面的命令到終端軟件中,這段命令會去下載和安裝這個 krew 插件。bash

$(
  set -x; cd "$(mktemp -d)" &&
  curl -fsSLO "https://storage.googleapis.com/krew/v0.2.1/krew.{tar.gz,yaml}" &&
  tar zxvf krew.tar.gz &&
  ./krew-"$(uname | tr '[:upper:]' '[:lower:]')_amd64" install \
    --manifest=krew.yaml --archive=krew.tar.gz
)

安裝好的 krew 命令在目錄 ~/.krew/bin 下面,因此咱們能夠把這個路徑加到終端的配置文件中。通常是 ~/.bashrc 或者是 ~/.zshrc服務器

例如,使用以下的命令將 krew 命令的所在路徑寫入到 $PATH 中。curl

$ echo 'export PATH=$PATH:$HOME/.krew/bin' >> ~/.bashrc

須要注意的是,上面設置的這個路徑同時也是經過 krew 安裝的其餘的插件命令所在的目錄,因此一次設置後面其餘的命令均可以直接使用了。tcp

安裝完 krew 以後,咱們須要經過 kubectl krew update 命令來更新支持的插件命令列表,下載下來的 Plugin 配置文件都存放在 ~/.krew/index/plugins 下面。微服務

$ kubectl krew update
Updated the local copy of plugin index.

sniff

咱們可使用命令 kubectl krew install sniff 來安裝這個插件命令,安裝好的命令位於 ~/.kube/store/sniff 下面。

$ kubectl krew install sniff
Updated the local copy of plugin index.
Installing plugin: sniff
CAVEATS:
\
 |  This plugin needs the following programs:
 |  * wireshark (optional, used for live capture)
/
Installed plugin: sniff

咱們能夠看下 sniff 命令的所在目錄下的文件。

$ ls -ahl ~/.krew/store/sniff/71102253eded8900c8f7b0d0624c65b3c77ecd6bcd28fabc9a200daac502282a/
total 36M
drwx------ 2 root root 4.0K Jun 11 17:58 .
drwxr-xr-x 3 root root 4.0K Jun 11 17:58 ..
-rwxr-xr-x 1 root root  33M Jun 11 17:58 kubectl-sniff
-rwxr-xr-x 1 root root 2.6M Jun 11 17:58 static-tcpdump

這裏面其實下載了兩個文件,其中一個是 sniff,另一個是 tcpdump,稍後咱們會看到這個 tcpdump 的用途。

Pod 抓包

咱們首先找個 Pod 來研究下 sniff 的具體抓包操做方法。

NAME                         READY   STATUS    RESTARTS   AGE
echo-go-bdf4bd7ff-v6hml      1/1     Running   0          8h
echo-java-55c5dcbbc9-7dh5c   1/1     Running   1          30h

咱們拿第一個 Pod 出來測試下抓包。

$ kubectl sniff echo-go-bdf4bd7ff-v6hml -n devops
<1> INFO[0000] sniffing method: upload static tcpdump
<2> INFO[0000] using tcpdump path at: '/root/.krew/store/sniff/71102253eded8900c8f7b0d0624c65b3c77ecd6bcd28fabc9a200daac502282a/static-tcpdump'
<3> INFO[0000] no container specified, taking first container we found in pod.
<4> INFO[0000] selected container: 'echo-go'
<5> INFO[0000] sniffing on pod: 'echo-go-bdf4bd7ff-v6hml' [namespace: 'devops', container: 'echo-go', filter: '', interface: 'any']
<6> INFO[0000] uploading static tcpdump binary from: '/root/.krew/store/sniff/71102253eded8900c8f7b0d0624c65b3c77ecd6bcd28fabc9a200daac502282a/static-tcpdump' to: '/tmp/static-tcpdump'
<7> INFO[0000] uploading file: '/root/.krew/store/sniff/71102253eded8900c8f7b0d0624c65b3c77ecd6bcd28fabc9a200daac502282a/static-tcpdump' to '/tmp/static-tcpdump' on container: 'echo-go'
<8> INFO[0000] executing command: '[/bin/sh -c ls -alt /tmp/static-tcpdump]' on container: 'echo-go', pod: 'echo-go-bdf4bd7ff-v6hml', namespace: 'devops'
<9> INFO[0000] command: '[/bin/sh -c ls -alt /tmp/static-tcpdump]' executing successfully exitCode: '0', stdErr :''
<10> INFO[0000] file found: '-rwxr-xr-x 1 root root 2642872 Jan  1  1970 /tmp/static-tcpdump'
<11> INFO[0000] file was already found on remote pod
<12> INFO[0000] tcpdump uploaded successfully
<13> INFO[0000] spawning wireshark!
<14> INFO[0000] starting sniffer cleanup
<15> INFO[0000] sniffer cleanup completed successfully
<16> Error: exec: "wireshark": executable file not found in $PATH

爲了方便敘述,咱們把每一行輸出都標上了數字。這些數字不在實際輸出的結果中。 從第 <1> - <7> 行咱們能夠看出,sniff 命令把咱們剛剛看到的 static-tcpdump 上傳到 Pod 中,咱們能夠到 Pod 裏面在 /tmp 目錄下發現這個 static-tcpdump 文件。而後試圖啓動 wireshark 進程,可是因爲咱們服務器通常不安裝 wireshark 因此啓動失敗了。

這種狀況下,咱們可使用一個新的選項 -o 來將抓包的內容輸出到文件中。

$ kubectl sniff echo-go-bdf4bd7ff-v6hml -n devops -o test.pcap
kubectl sniff echo-go-bdf4bd7ff-v6hml -n devops -o pcap
INFO[0000] sniffing method: upload static tcpdump
INFO[0000] using tcpdump path at: '/root/.krew/store/sniff/71102253eded8900c8f7b0d0624c65b3c77ecd6bcd28fabc9a200daac502282a/static-tcpdump'
INFO[0000] no container specified, taking first container we found in pod.
INFO[0000] selected container: 'echo-go'
INFO[0000] sniffing on pod: 'echo-go-bdf4bd7ff-v6hml' [namespace: 'devops', container: 'echo-go', filter: '', interface: 'any']
INFO[0000] uploading static tcpdump binary from: '/root/.krew/store/sniff/71102253eded8900c8f7b0d0624c65b3c77ecd6bcd28fabc9a200daac502282a/static-tcpdump' to: '/tmp/static-tcpdump'
INFO[0000] uploading file: '/root/.krew/store/sniff/71102253eded8900c8f7b0d0624c65b3c77ecd6bcd28fabc9a200daac502282a/static-tcpdump' to '/tmp/static-tcpdump' on container: 'echo-go'
INFO[0000] executing command: '[/bin/sh -c ls -alt /tmp/static-tcpdump]' on container: 'echo-go', pod: 'echo-go-bdf4bd7ff-v6hml', namespace: 'devops'
INFO[0000] command: '[/bin/sh -c ls -alt /tmp/static-tcpdump]' executing successfully exitCode: '0', stdErr :''
INFO[0000] file found: '-rwxr-xr-x 1 root root 2642872 Jan  1  1970 /tmp/static-tcpdump
'
INFO[0000] file was already found on remote pod
INFO[0000] tcpdump uploaded successfully
INFO[0000] output file option specified, storing output in: 'pcap'
INFO[0000] start sniffing on remote container
INFO[0000] executing command: '[/tmp/static-tcpdump -i any -U -w - ]' on container: 'echo-go', pod: 'echo-go-bdf4bd7ff-v6hml', namespace: 'devops'

這種狀況下,咱們看到容器中的 /tmp/static-tcpdump 命令已經啓動了,並把輸出導向到 stdout,而後咱們在 sniff 命令中把它寫入到 test.pcap 文件中。

最後,咱們就能夠用本地的 wireshark 圖形化工具打開這個 test.pcap 文件進行分析了。

相關文章
相關標籤/搜索