如何使用 K8spacket 和 Grafana 對(duì) K8s 的 TCP 數(shù)據(jù)包流量進(jìn)行可視化

前言
如何知道 K8S 集群內(nèi) Pod 之間建立了哪些 TCP 連接?集群之間存在哪些調(diào)用關(guān)系?
使用 k8spacket 和Grafana,你可以可視化集群中的 TCP 流量。了解工作負(fù)載如何相互通信,以及建立了多少連接,交換了多少字節(jié),這些連接處于活動(dòng)狀態(tài)的時(shí)間。
介紹
k8spacket是用 Golang 編寫的工具,它使用gopacket第三方庫來嗅探工作負(fù)載(傳入和傳出)上的 TCP 數(shù)據(jù)包。它在運(yùn)行的容器網(wǎng)絡(luò)接口上創(chuàng)建 TCP 偵聽器。當(dāng) Kubernetes 創(chuàng)建一個(gè)新容器時(shí),CNI 插件負(fù)責(zé)提供與其他容器進(jìn)行通信的可能性。最常見的方法是用linux namespace隔離網(wǎng)絡(luò)并用veth pair連接隔離的 namespace 與網(wǎng)橋。除了bridge 類型,CNI 插件還可以使用其他類型(vlan, ipvlan,macvlan),但都為容器創(chuàng)建了一個(gè)網(wǎng)絡(luò)接口,它是k8spacket嗅探器的主要句柄。
k8spacket有助于了解 Kubernetes 集群中的 TCP 數(shù)據(jù)包流量:
- 顯示集群中工作負(fù)載之間的流量
- 通知流量在集群外路由到哪里
- 顯示有關(guān)連接關(guān)閉套接字的信息
- 顯示工作負(fù)載發(fā)送/接收的字節(jié)數(shù)
- 計(jì)算建立連接的時(shí)間
- 顯示整個(gè)集群中工作負(fù)載之間的網(wǎng)絡(luò)連接拓?fù)?br>
k8spacket是一個(gè) Kubernetes API 客戶端,可以將嗅探到的工作負(fù)載解析為可視化上可見的集群資源名稱(Pods和Services)。它作為DaemonSet Pod啟動(dòng),使用 hostNetwork,并監(jiān)聽節(jié)點(diǎn)上的網(wǎng)絡(luò)接口。
k8spacket 收集 TCP 流、處理數(shù)據(jù),使用 Node Graph API Grafana 數(shù)據(jù)源插件(詳情請(qǐng)查看 Node Graph API 插件),通過 API 展示在Grafana面板。
要安裝k8spacket,需要同時(shí)安裝 Grafana。下面將在Kind安裝的 k8s 集群上做演示。
安裝 k8spacket
使用 Helm 安裝:
helm repo add k8spacket https://k8spacket.github.io/k8spacket-helm-chart
helm install k8spacket --namespace k8spacket k8spacket/k8spacket --create-namespace
默認(rèn)安裝會(huì)使用下面的命令獲取所有需要監(jiān)聽的網(wǎng)絡(luò)接口:
ip address | grep @ | sed -E 's/.* (\w+)@.*/\1/' | tr '\n' ',' | sed 's/.$//'
其中可能包含一些狀態(tài)為Down的接口,此時(shí)啟動(dòng)k8spacket會(huì)報(bào)錯(cuò):
2022/08/15 00:17:34 error opening pcap handle: tunl0: That device is not up
報(bào)錯(cuò)中提示網(wǎng)絡(luò)接口tunl0狀態(tài)不是up。
所以需要自定義修改values.yaml中的參數(shù)。將charts包拉取到本地,解壓之后再修改:
mkdir k8spacket
helm fecth k8spacket/k8spacket
tar -zxf k8spacket-0.1.0.tgz
cd k8spacket
修改 values.yaml 中的內(nèi)容,過濾掉tunl0:
k8sPacket:
tcp:
listener:
interfaces:
## 實(shí)現(xiàn)容器網(wǎng)絡(luò)接口的命令
command: "ip address | grep @ | grep -v tunl0 | sed -E 's/.* (\\w+)@.*/\\1/' | tr '\\n' ',' | sed 's/.$//'"
## 多久刷新一次要監(jiān)聽的網(wǎng)絡(luò)接口列表
refreshPeriod: "10s"
## 每 (periodDuration) 秒,刷新在過去 (closeOlderThanDuration) 秒內(nèi)沒有看到活動(dòng)的連接。
flushing:
periodDuration: "10s"
closeOlderThanDuration: "20s"
- refreshPeriod參數(shù)表示多久刷新一次要監(jiān)聽的網(wǎng)絡(luò)接口列表,增加新的網(wǎng)絡(luò)接口監(jiān)聽,移除舊網(wǎng)絡(luò)接口監(jiān)聽。
- 每 periodDuration秒,刷新在過去 closeOlderThanDuration秒內(nèi)沒有看到活動(dòng)的連接。
安裝成功,包含以下Daemonset Pods 和 Service:
# k get pod -n k8spacket -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
k8spacket-9m4cz 1/1 Running 0 10m 192.168.16.4 k8s118-control-plane <none> <none>
k8spacket-b4q9k 1/1 Running 0 10m 192.168.16.6 k8s118-control-plane3 <none> <none>
k8spacket-b5nnp 1/1 Running 0 10m 192.168.16.7 k8s118-control-plane2 <none> <none>
k8spacket-c25jh 1/1 Running 0 10m 192.168.16.2 k8s118-worker <none> <none>
k8spacket-cqqxh 1/1 Running 0 10m 192.168.16.5 k8s118-worker2 <none> <none>
k8spacket-h9hjc 1/1 Running 0 10m 192.168.16.3 k8s118-worker3 <none> <none>
# k get svc -n k8spacket -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
k8spacket ClusterIP 11.0.227.158 <none> 8080/TCP 31m app.kubernetes.io/instance=k8spacket,app.kubernetes.io/name=k8spacket
k8spacket Pod 提供了 /metrics 接口暴露指標(biāo):
curl 192.168.16.4:8080/metrics
安裝 dashboards
下載k8spacket項(xiàng)目,并將dashboards目錄下的面板 configmaps 創(chuàng)建到 K8S 中:
wget https://github.com/k8spacket/k8spacket/archive/refs/heads/master.zip
unzip master.zip
cd k8spacket-master
kubectl apply --recursive -f ./dashboards
創(chuàng)建了 k8spacket-logs-dashboard、k8spacket-metrics-dashboard、k8spacket-node-graph-dashboard三個(gè)面板。
其中的metrics面板公開了 Prometheus 指標(biāo),這里不做演示。只關(guān)心node-graph面板。
安裝 grafana
使用 Helm 安裝 grafana,helm-charts 包地址如下:
- https://github.com/grafana/helm-charts
同樣的拉取到本地:
helm repo add grafana https://grafana.github.io/helm-charts
helm fetch grafana/grafana
tar -zxf grafana-6.32.13.tgz
cd grafana/
- charts包版本為:6.32.13
- grafana版本為:9.0.5
修改values.yaml,將 Node Graph API 插件和數(shù)據(jù)源,以及 node-graph dashboard configmaps 添加到 Grafana。同時(shí)開啟數(shù)據(jù)持久化。例如:
persistence
typepvc
enabledtrue
env
GF_INSTALL_PLUGINShamedkarbasi93-nodegraphapi-datasource
dashboardProviders
dashboardproviders.yaml
apiVersion1
providers
name'default'
orgId1
folder''
typefile
disableDeletionfalse
editabletrue
options
path/var/lib/grafana/dashboards/default
dashboardsConfigMaps
defaultk8spacket-node-graph-dashboard
datasources
nodegraphapi-plugin-datasource.yaml
apiVersion1
datasources
name"Node Graph API"
jsonData
url"http://k8spacket.k8spacket.svc.cluster.local:8080"
access"proxy"
basicAuthfalse
isDefaultfalse
readOnlyfalse
type"hamedkarbasi93-nodegraphapi-datasource"
typeLogoUrl"public/plugins/hamedkarbasi93-nodegraphapi-datasource/img/logo.svg"
typeName"node-graph-plugin"
orgId1
version1
在values.yaml目錄下執(zhí)行創(chuàng)建命令:
helm install grafana -f values.yaml ./獲取到admin賬號(hào)的密碼:
kubectl get secret --namespace default grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
開啟臨時(shí)端口轉(zhuǎn)發(fā),使得集群外可以訪問grafana實(shí)例:
kubectl --namespace default port-forward service/grafana 3000:80 --address 0.0.0.0
通過http://{Kind宿主機(jī)IP}:3000打開grafana面板,并使用上面獲取到的密碼登錄,可以看到Node Graph API插件成功安裝:

在node graph面板可以看到集群中網(wǎng)絡(luò)連接拓?fù)洌?br>

使用
統(tǒng)計(jì)類型
- connection:幫助了解工作負(fù)載之間以及與外部客戶端之間建立了多少連接。它會(huì)告訴你哪些套接字保持打開狀態(tài)并可能導(dǎo)致問題。
- bytes:顯示工作負(fù)載發(fā)送或接收的字節(jié)數(shù)。
- duration:計(jì)算連接的生命周期。

過濾器
- by namespace:選擇一個(gè)或多個(gè) k8s 命名空間

- by names included:選擇工作負(fù)載名稱進(jìn)行可視化
- by names excluded:從可視化中排除工作負(fù)載名稱



































