zoukankan      html  css  js  c++  java
  • 查看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

  • 相关阅读:
    机器学习之线性回归
    机器学*-K*邻算法模型预测实战
    机器学习-特征抽取
    机器学习sklearn和字典特征抽取
    机器学习第一讲
    spark统计每个省份广告点击量top3
    spark统计单位时间内访问量
    并发容器之 ConcurrentHashMap源码剖析
    并发之 Java中的锁
    并发之 深入剖析volatile底层原理
  • 原文地址:https://www.cnblogs.com/nanxiang/p/14807774.html
Copyright © 2011-2022 走看看