摘要:本文重點關注進入目標程序的「網路ns」視角,即站在「容器中的程序視角」看待容器裡面的網路世界,並在那個視角中執行命令。
本文分享自華為雲社群《《跟唐老師學習雲網路》 - nsenter魔法棒》,作者:tsjsdbd 。
有時候Docker容器中缺少需要的軟體。比如 curl,wget,ifconfig,ip,tcpdump 等基礎軟體包,什麼都幹不了,很是讓人抓狂。
[root@tsjsdbd home]# docker exec -it 8402 /bin/bash root@8402d89fe04a:/# ifconfig bash: ifconfig: command not found root@8402d89fe04a:/# ip bash: ip: command not found root@8402d89fe04a:/# tcpdump bash: tcpdump: command not found root@8402d89fe04a:/# curl bash: curl: command not found root@8402d89fe04a:/# nslookup bash: nslookup: command not found root@8402d89fe04a:/# wget wget: missing URL Usage: wget [OPTION]... [URL]...
面對這種容器映象,定位問題就會很困難,因為你進入容器後,想執行命令還得重新安裝各種基礎軟體,非常麻煩。
這個時候,我們要拿起「nsenter」這個根魔法棒,在主機上上面揮舞起來。
ns-enter,顧名思義,就是「進入各種namespace」,即nsenter命令可以進入到指定目標程序的ns視角。
所以nsenter可以站在指定程序的「視角」看世界,本文重點關注進入目標程序的「網路ns」視角,即站在「容器中的程序視角」看待容器裡面的網路世界,並在那個視角中執行命令。
首先,我們要找到,要進入的「目標ns」的目標程序ID。即:容器裡面的根程序
[root@tsjsdbd ubuntu]# docker inspect 8402d89fe04a [ { "Id": "8402d89fe04a7e161faf8a01a86c47f8402d4c8d7207b6897d8e6d661d670df4", "State": { "Status": "running", "Pid": 18751, "ExitCode": 0, "Error": "", "StartedAt": "2023-05-10T03:12:19.221460059Z", "FinishedAt": "0001-01-01T00:00:00Z" },
容器裡的「老大」是程序18751號。
所以我們直接在Host主機上,跟蹤這個程序,並進入它的「視角」,我們就可以看到容器裡面的世界了。而且由於我們這個時候,作為控制者,還是處在Host主機上的,因此可以執行Host主機上的各種命令列。
如下:
[root@tsjsdbd ubuntu]# nsenter -t 18751 -n ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet) RX packets 1688355 bytes 194318903 (185.3 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 138826 bytes 146246172 (139.4 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 0 (Local Loopback) RX packets 13939 bytes 13140220 (12.5 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 13939 bytes 13140220 (12.5 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
其他命令,照搬都可以執行。
比如,容器裡面沒有nslookup命令,但是隻有Host主機上有,咱就可在容器中執行它:
[root@tsjsdbd ubuntu]# nsenter -t 18751 -n nslookup www.baidu.com Server: 10.129.2.34 Address: 10.129.2.34#53 Non-authoritative answer: www.baidu.com canonical name = www.a.shifen.com. Name: www.a.shifen.com Address: 14.119.104.254 Name: www.a.shifen.com Address: 14.119.104.189
所以原本在容器裡面,無法執行的偵錯行為,就這麼可以完成偵錯。
更直接的,如果不帶最後的執行命令引數,可以直接進到「目標視角」裡面去,進行互動式執行cli:
[root@tsjsdbd ubuntu]# nsenter -t 18751 -n #這裡就進入互動模式,相當於沒有填寫cli時,預設執行[當前bash] [root@tsjsdbd ubuntu]# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 4261: eth0@if4262: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP [root@tsjsdbd ubuntu]# curl curl: try 'curl --help' or 'curl --manual' for more information [root@tsjsdbd ubuntu]# tcpdump listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes ^C 0 packets captured 0 packets received by filter 0 packets dropped by kernel [root@tsjsdbd ubuntu]# exit #執行exit,可退出「目標視角」
可以看到,所有的網路相關的cli命令列都可以執行。
並且,這些命令,都是站在容器內的「視角」執行的,所以效果與在容器中是一樣的(雖然它們本身在Host中發起的)。
類似電影《原始碼》《駭客帝國》中那樣,用外面世界中的「人」,去控制「裡面世界」中的行為。希望可以理解這種上帝視角的邏輯:-)
總結用法:
(1) 找到目標程序PID
docker inspect xxx
(2)直接執行特定的cli命令
nsenter -n -t 822647 ifconfig
(3)進入容器視角,進行互動式cli
nsenter -n -t 822647 exit