查看docker容器的tcp連接(轉)


轉:https://blog.liu-kevin.com/2020/05/13/cha-kan-dockerrong-qi-de-tcplian-jie/

查看容器內的tcp連接

當需要查看tcp連接時,通常使用netstat或ss命令查看,但是查看docker容器的tcp連接存在兩個問題

  • docker容器中無netstat或ss命令
  • node節點上無法查看容器中的連接

查看docker容器中網絡連接

通過容器中的proc文件查看

  • 查看proc文件內容
cat /proc/net/tcp
  • 內容分析,主要關注的點是local_address、rem_address
 sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 47626 1 ffff8ad7fae25f00 100 0 0 10 0
   1: 00000000:01BB 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 47627 1 ffff8ad7fae25740 100 0 0 10 0
   2: 020011AC:01BB 8297417C:CE2C 01 00000000:00000000 00:00000000 00000000   101        0 12071491 1 ffff8ad7fa78d740 20 4 23 10 -1
   3: 020011AC:01BB 8297417C:CE2B 01 00000000:00000000 00:00000000 00000000   101        0 12071492 1 ffff8ad7fa78e6c0 20 4 30 10 -1

ip及端口格式020011AC:01BB為16進制,可通過工具解析為10進制,如地址解析工具進制轉換工具

通過namespace查看

  • 查找docker容器進程號
docker inspect -f {{.State.Pid}} nginx
  • 進入某個進程的network namespace
nsenter -n -t 2593
  • 執行netstat
[root@kevin ns]# netstat -t
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 kevin:35086             172.17.0.4:opentable    TIME_WAIT
tcp        0      0 kevin:https             124.64.18.179:41661     ESTABLISHED
tcp        0      0 kevin:https             124.65.151.130:61026    ESTABLISHED
tcp        0      0 kevin:https             124.65.151.130:61025    ESTABLISHED
tcp        0      0 kevin:https             124.65.151.130:61024    ESTABLISHED
tcp        0      0 kevin:https             124.65.151.130:59837    ESTABLISHED
tcp        0      0 kevin:https             124.65.151.130:60000    ESTABLISHED

故 netstat 默認情況下只能查看當前namespace下的連接,如果查看其它namespace的連接,需要先進入其它namespace

查看docker nginx進程對應的tcp連接

在節點上執行下述命令

cat /proc/2593/net/tcp

docker-proxy

查看節點上http或https對應的端口監聽程序

當在節點上執行netstat -ltp時,可以發現存在進程docker-proxy-current監聽着8080、443端口

[root@centos75_100-58 ~]# netstat -ltp|grep http
tcp6       0      0 [::]:http               [::]:*                  LISTEN      42138/docker-proxy-
tcp6       0      0 [::]:https              [::]:*                  LISTEN      42124/docker-proxy-

查看進程詳細信息

[root@centos75_100-58 ~]# ps -ef|grep 42138 |grep -v grep
root     42138 41940  0  2019 ?        00:00:05 /usr/libexec/docker/docker-proxy-current -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.66.3 -container-port 80
[root@centos75_100-58 ~]# ps -ef|grep 42124|grep -v grep
root     42124 41940  0  2019 ?        00:00:05 /usr/libexec/docker/docker-proxy-current -proto tcp -host-ip 0.0.0.0 -host-port 443 -container-ip 172.17.66.3 -container-port 443

docker-proxy 通過-host-ip指定了docker-proxy在主機上監聽的網絡接口,通過-host-port指定了監聽的端口號;通過-container-ip和-container-port 指定了docker-proxy鏈接到容器內部的容器ip和端口號

為什么查詢不到外部請求到 docker-proxy的tcp連接

Docker 1.7 版本起,Docker 提供了一個配置項: -userland-proxy,以讓 Docker 用戶決定是否啟用 docker-proxy,默認為 true,即啟用 docker-proxy。
現在的 Docker 環境默認的是: -userland-proxy=true。iptables 和 docker-proxy 都會起作用。

當-userland-proxy=true時,每設置一對端口映射就會啟動一個 docker-proxy 進程。

但是,當我們通過iptables-save -t nat查看iptables nat列表時,會發現所有到docker容器映射端口的請求都會被nat到docker0

-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80

所以請求不會到達docker-proxy進程,故不會出現到該進程的tcp連接,所以在一定情況下,可以將docker-proxy關閉。

關閉docker-proxy的問題:

1、ipv6場景

docker啟動時刻可以通過ipv6參數開啟docker ipv6支持功能。開啟后所有docker容器都在ipv6下工作。但是此時docker在ipv6上的工作並為完善,docker並未在ipv6table上為容器添加相應的DNAT規則。如果此時關閉docker-proxy,那么容器外部無法訪問到容器內部網絡。在不借助任何外部手段的情況下(可以使用一個叫ipv6nat工具實現ip6table nat規則的自動添加,但即便如此ipv6場景下,docker-proxy依然有存在意義詳見后文場景3),所以此場景下docker-proxy需要開啟。

2、在老內核下(2.6.x),容器內部通過hairpin 方式訪問自己暴露的服務

在第一章的例子中,如果需要在容器內部訪問自己暴露的服務,那么就出現了hairpin DNAT訪問方式:

#docker exec -it zxy-nginx /bin/bash
root@8173f601424 #curl http://192.168.126.222:8080
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body bgcolor=“white“ text=“black”>
<center><h1>Welcome to nginx!</h1></center>
</body>
</html>

可以看到在容器zxy-nginx內通過主機ip+容器映射主機端口方式一樣可以訪問到zxy-nginx容器自己暴露的nginx服務。
這就是hairpin DNAT模式。但是關閉docker-proxy時刻,數據包進過docker0上的prerouting鏈時被表3-2的DNAT命中,數據包dst-ip被轉換為172.17.0.4,dst-port被轉換為80,在docker0的forwarding動作中,判定此包需要送回zxy-nginx在docker0上的網絡接口veth17f3d1上。默認情況下,內核bridge不允許將包發送回到源接口的;只有在內核配置了hairpin mode enable時刻,才允許此類操作。在docker處理流程中,如果用戶關閉了docker-proxy,那么docker會開啟內核的hairpin mode(在centos 7x上通過echo “1”>/sys/class/net/docker0/brif/vethxxx/hairpin_mode開啟hairpin模式)。但是在老內核2.6.x上,沒有辦法啟用hairpin mode。所以此時無法借助iptables nat實現容器內部網絡可達。此刻就必須使用docker proxy了。關於hairpin模式的解釋請參考:https://wiki.mikrotik.com/wiki/Hairpin_NAT

3、在內核無法開啟route_localnet的情況下

正常情況下,內核不會對地址為localnet(127.0.0.0/8)的地址做forwarding,因為這部分地址被認為為martian 。但是在內核中可以通過配置

echo “1”>/proc/sys/net/ipv4/conf/$BridgeName/route_localnet 

開啟。docker在啟動階段會配置此配置項。但是對於低版本內核無此參數或對於ipv6地址場景(ipv6內核無此配置項,無此功能)內核依然不會對localhost(ipv6下地址為[::1])進行forwarding;所以在此部分場景下,如果需要在主機上,使用localhost:Port 與容器通訊依然需要依賴於docker-proxy

 

 

 

shell腳本:遍歷容器涉及的網絡NAMESPACE,查看網絡連接

 

 

for x in `docker ps | awk 'NR > 1 {print $1}'`
do
echo "#$x"
a=`docker inspect -f {{.State.Pid}} $x`
#echo $a
echo "nsenter -n -t $a"
echo "netstat -antp | grep 130.6"
done


免責聲明!

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



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