隨着微服務架構和雲計算的普及,愈來愈多企業的應用都上了雲,不只是雲基礎設施 IaaS ,如 kubernetes 等 PaaS 項目也是愈來愈熱門。但新的技術會帶來新的架構複雜,同時也會使排查問題更加困難,所以不少運維和開發同窗都以爲用平時用的順手的工具和手段在容器裏排查問題很差使了。工欲善其事必先利其器,正是因爲這樣的狀況,因此咱們排查容器問題的時候,須要引入新的工具和手段。java
在學習工具的使用前,咱們首先須要簡單的瞭解下容器的原理。假如一臺機器是一間房子,那麼進程就是住在裏面的一個個的人,在單體應用的時代,全部人都住在一間房子裏,而容器技術就是經過一些手段把這些人都隔開,讓每一個人都覺得本身住上有獨衛(網絡,IPC,namespace 等資源)的單間。而
這些隔離和限制的主要使用的以下技術:node
在單體應用的時代,全部的進程都在同一個命名空間裏,且啓動的進程都沒有隔離命名空間,那麼天然調試工具進程也在同一個命名空間,也就能夠 debug 其餘進程。而容器技術因爲分割成一個個的小房間,若是想要查看單個房間的狀況,雖然在大管家(宿主機)的上帝視角同樣能夠看到, 但爲了減小干擾並更加符合咱們平時的使用習慣,咱們就須要進入到房間(命名空間)裏面查看。python
例如咱們能夠經過 docker inspect CONTAINER_ID
獲取到某個容器資源隔離的文件的地址,以下"SandboxKey": "/var/run/docker/netns/50def85bf6e2"
就是。linux
@ubuntu ➜ k8s-debug docker inspect 0dde03166e02 ... "SandboxKey": "/var/run/docker/netns/50def85bf6e2", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "7faa1e764317cdfadf7f31b7ed2fecff62b458211f79fadb3362c8e22755f326", "Gateway": "172.17.0.1", ...
而容器的診斷工具就是自帶了部分調試工具的鏡像,並能根據容器 ID 幫咱們自動地進入到房間(網絡,IPC 命名空間等)。
在初步瞭解了容器的原理後,咱們即可進入工具的介紹了。git
首先介紹的第一個工具是netshoot,netshoot 的自我定位就是容器網絡診斷的瑞士軍刀,簡單來講,netshoot 其實就是一個裝滿了各類工具的鏡像,他用起來也很簡單。github
docker run -it --net container:<container_name|container_id> nicolaka/netshoot
就行,這裏的--net
是 docker 命令指定該容器要聯結到哪一個容器的網絡命名空間--net host
就好了nsenter
進入NIC 設備的命名空間排查,後面我會介紹這個工具另外,若是是在 kubernetes 裏面,咱們能夠經過執行kubectl run test-lab --generator=run-pod/v1 --rm -i --tty --overrides='{"spec": {"hostNetwork": true}}' --image nicolaka/netshoot -- /bin/bash
這個命令進入宿主機的網絡。別怕這個命令長,我來一一解釋下這條命令的各個選項的做用docker
kubectl run test_lab --generator=pod/v1 --rm -i --tty
意思是建立一個一次性的名叫test_lab
的 Pod 資源而且使用標準輸入輸出交互--overrides='{"spec": {"hostNetwork": true}}'
意思是使用宿主機網絡,具體哪臺宿主機要看這個 Pod 調度到哪一個節點。--image nicolaka/netshoot
指定 Pod 的鏡像--
這是 bash 的內置命令選項,是標誌命令的結束的意思,舉個例子:若是我想要在文件裏用grep
搜索-v
字符串,grep -v filename
中-v
會被視爲選項,但我若是使用grep -- -v filename
那麼就能夠正常搜索了下面我來演示幾個例子:ubuntu
使用 tcpdump 抓容器的包並拷貝 pcap 文件出來,便於用 wireshark 分析api
@ubuntu ➜ k8s-debug mkdir -p /tmp/netshoot @ubuntu ➜ k8s-debug docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0dde03166e02 jumpserver/jms_all:1.5.4 "entrypoint.sh" 3 weeks ago Up 3weeks ... mystifying_williamson @ubuntu ➜ k8s-debug docker run -it -v /tmp/netshoot:/tmp --net container:0dde03166e02 nicolaka/netshoot Welcome to Netshoot! (github.com/nicolaka/netshoot) root @ / [1] → tcpdump -nn -i any -w /tmp/pkg.pcap [2] → exit
具體命令使用與以前的差很少,只不過把宿主機上的/tmp/netshoot
目錄 bind-mount 到了容器的/tmp
目錄tomcat
有時候咱們還須要調試 bridge 或者 overlay 網絡,可使用 nsenter,nsenter 能夠進入任何命名空間
@ubuntu ➜ ~ docker network ls NETWORK ID NAME DRIVER SCOPE ... 0ipu2p43c6jh ingress overlay swarm 697402c52a87 none null local @ubuntu ➜ ~ docker run -it --rm -v /var/run/docker/netns:/var/run/docker/netns --privileged=true nicolaka/netshoot Welcome to Netshoot! (github.com/nicolaka/netshoot) root @ / [1] 🐳 → ls /var/run/docker/netns/ 1-0ipu2p43c6 50def85bf6e2 83f9ffa847d7 default ingress_sbox root @ /var/run/docker/netns [6] 🐳 → nsenter --net=/var/run/docker/netns/1-0ipu2p43c6 sh root @ /run/docker/netns [#] 🐳 → ifconfig br0 Link encap:Ethernet HWaddr 02:61:F2:E4:26:3B inet addr:10.255.0.1 Bcast:10.255.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 ... vxlan0 Link encap:Ethernet HWaddr 02:61:F2:E4:26:3B UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) root @ /run/docker/netns [#] 🐳 → bridge fdb show br0 33:33:00:00:00:01 dev br0 self permanent 01:00:5e:00:00:01 dev br0 self permanent 02:61:f2:e4:26:3b dev vxlan0 master br0 permanent ...
上面的命令首先咱們是進入了1-0ipu2p43c6
的命名空間,即那個叫 ingress 的 overlay 網絡,而後能夠經過查看這個 NIC 設備上的fdb 表
咱們也能夠經過掛載 docker 的 unix sock 文件查看容器的 metrics
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock nicolaka/netshoot ctop
以下圖所示
netshoot 工具很是強大,還有不少功能能夠自行去探索,netshoot上有詳細的說明。
上面介紹的 netshoot 主要定位於 docker 網絡的診斷,從名字就能夠看出來。而咱們如今介紹的工具 docker-debug能夠說是 netshoot 的升級版,他不只能夠進入目標容器的網絡命名空間,還能夠進入 pid,user,filesystem,ipc 的命名空間,因此咱們能夠操做的空間就更大了。話很少說,咱們開始演示。
首先咱們要下載 docker-debug 的二進制文件
@ubuntu ➜ docker-debug wget docker-debug https://github.com/zeromake/docker-debug/releases/download/0.6.2/docker-debug-linux-amd64 -O docker-debug @ubuntu ➜ docker-debug chmod +x docker-debug @ubuntu ➜ docker-debug mv docker-debug /usr/bin @ubuntu ➜ docker-debug docker-debug info Version: 0.6.2 Platform: TravisLinux Commit: cf4cc41 Time: 2019-06-20 05:40:52 +0000
而後我賦予了文件執行權限並移動到/usr/bin
目錄下,若是執行docker-debug info
看到有正確輸出,則說明安裝成功了
使用就很簡單了,首先咱們獲取到容器的名字或者容器 ID
@ubuntu ➜ docker-debug docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0dde03166e02 jumpserver/jms_all:1.5.4 "entrypoint.sh" 3 weeks ago Up 3 weeks ... mystifying_williamson
而後執行docker-debug <CONTAINER_ID|CONTAINER_NAME> COMMAND
就能夠了
@ubuntu ➜ docker-debug docker-debug 0dde03166e02 bash bash-5.0# netstat -lntp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name ... tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 52/python3.6 tcp 0 0 0.0.0.0:8081 0.0.0.0:* LISTEN 110/java ... bash-5.0# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:32776325 errors:0 dropped:0 overruns:0 frame:0 ... bash-5.0# ls /mnt/container/ anaconda-post.log dev lib mnt root srv usr bin etc lib64 opt run sys var config home media proc sbin tmp
咱們能夠看到已經進入了目標容器的 ipc,network,filesystem,pid 的命名空間了,而目標容器的root則掛載在了/mnt/container
目錄下。
此外,咱們還能夠經過設置 docker-debug 在~/.docker-debug/config.toml
的配置文件使用自定義的診斷鏡像
version = "0.6.1" image = "nicolaka/netshoot:latest" mount_dir = "/mnt/container" timeout = 10000000000 config_default = "default" [config] [config.default] host = "unix:///var/run/docker.sock" tls = false cert_dir = "" cert_password = ""
其餘就不作過多介紹了
在介紹了 docker 的 debug 的工具後,咱們瞭解了容器診斷工具的原理和使用,接下來咱們要學習 kubernetes 的容器診斷工具。雖然 kubernetes 上也能夠用我上面介紹的那些工具,但 kubernetes 上的容器畢竟運行在不一樣的 node 上,用起來就不太方便,因此就要用到 kubectl-debug 這個工具了。
kubectl-debug 其實就是一個 kubectl 的插件,他的原理和 docker 容器診斷工具大同小異。kubectl-debug 能夠幫咱們在 某個 Pod 的節點上起一個容器,並將這個容器加入到目標容器的pid,network,user,icp 的命名空間。kubectl-debug 架構主要能夠分爲兩部分:
客戶端經過控制 node 上的 agent 服務端與容器運行時通訊,從而啓動一個容器並進入到指定 Pod 的命名空間,能夠說 agent 就是一個 debug 容器與客戶端之間的中繼。而從 kubectl-debug 的工做模式來看,能夠分爲兩種模式:
簡單來講就是 agentless 模式只有在每次 kubectl-debug 進行調試 Pod 的時候纔會啓動一個 agent 服務端,調試完成後自動清理 agent,此模式的優勢是不那麼佔用 kubernetes 集羣資源,而 DaemonSet 模式就是在每一個節點上都會常駐一個 DaemonSet 的 agent, 好處就是啓動快。
此外針對 node 節點沒法直接訪問的狀況,kubectl-debug 還有一個 port-forward 模式,這裏就很少介紹了。
因爲 kubectl-debug 可能還不太完善,agentless 模式我這裏用不了,因此我用的是 DaemonSet 模式,下面開始演示。
安裝過程和 docker-debug 差很少
wget https://github.com/aylei/kubectl-debug/releases/download/v0.1.0/kubectl-debug_0.1.0_linux_amd64.tar.gz -O kubectl-debug.tar.gz
tar -zxvf kubectl-debug.tar.gz kubectl-debug
wget -f https://raw.githubusercontent.com/aylei/kubectl-debug/master/scripts/agent_daemonset.yml
修改agent_daemonset.yml
文件
... 18 hostNetwork: true # 須要加上 hostNetwork: true,hostPort:10027 纔會生效 19 hostPID: true 20 tolerations: 21 - key: node-role.kubernetes.io/master 22 effect: NoSchedule 23 containers: 24 - name: debug-agent 25 image: aylei/debug-agent:v0.1.1 # 老版本鏡像有問題,使用 v0.1.1新版本 ... 39 ports: 40 - containerPort: 10027 41 hostPort: 10027 ...
建立 DaemonSet:kubectl apply -f agent_daemonset.yaml
, 接下來咱們能夠看到每一個節點上都建立了 debug-agent 的 DaemonSet,而且宿主機上都監聽了10027端口。
root @ master ➜ k8s-debug kubectl get pods NAME READY STATUS RESTARTS AGE debug-agent-5gfk6 1/1 Running 0 22h ... root @ master ➜ k8s-debug netstat -lntp | grep 10027 tcp6 0 0 :::10027 :::* LISTEN 15510/debug-agent
執行命令kubectl-debug <POD_NAME>
就能夠進行調試了
root @ master ➜ k8s-debug kubectl get pods NAME READY STATUS RESTARTS AGE licai-gwapi-77465b4c66-hdjlb 1/1 Running 0 3d ... root @ master ➜ k8s-debug kubectl-debug licai-gwapi-77465b4c66-hdjlb --agentless=false --port-forward=false pulling image nicolaka/netshoot:latest... ... bash-5.0# ps -ef | grep java 1 root 23:24 /usr/local/openjdk-8/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties... 192 root 0:00 grep java bash-5.0# exit exit root @ master ➜ k8s-debug
咱們能夠看到已經進入了目標容器的命名空間了,而kubectl-debug 客戶端正是與每一個 node 上的 10027 端口通訊來控制 agent 對 Pod 的調試。
除了這些以外,kubectl-debug 還有不少配置能夠自定義,kubectl-debug頁面也有詳細的介紹,至此從 docker 到 kubernetes 的調試工具介紹完成了。