美文网首页
容器的网络通讯分析

容器的网络通讯分析

作者: wu_sphinx | 来源:发表于2019-11-11 12:30 被阅读0次

    容器以其轻量及隔离性得到了广泛的应用,本篇意在通过抓包数据来分析容器的网络通讯是如何运行的。

    先准备一下主机环境

    Distributor ID: Raspbian
    Description:    Raspbian GNU/Linux 10 (buster)
    Release:    10
    Codename:   buster
    

    对,就是树莓派了。

    查看树莓派主机上安装的Docker版本

    Docker version 19.03.3, build a872fc2
    

    我们先尝试运行一个容器并进行容器的命令行

    docker run -it busybox /bin/sh
    

    查看一上容器里面的网络设备

    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
        link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
           valid_lft forever preferred_lft forever
    

    lo本地回环网络,这个很好理解,eth0是以太网接口,这正是我们所要讨论的点,eth0是容器跟外部通信的网络接口,它到底是如何起作用的呢?

    我们知道容器是在宿主机上运行的,容器的一切网络行为必定跟宿主机有关,那不妨先看一下宿主机的网络设备

    docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
            inet6 fe80::ed99:9e76:f8a1:39f  prefixlen 64  scopeid 0x20<link>
            ether 02:42:82:79:80:c9  txqueuelen 0  (Ethernet)
            RX packets 4  bytes 634 (634.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 48  bytes 9408 (9.1 KiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 192.168.43.116  netmask 255.255.255.0  broadcast 192.168.43.255
            inet6 fe80::edab:19a:ebcc:c66f  prefixlen 64  scopeid 0x20<link>
            inet6 240e:470:320:9301:8722:7c63:7135:9414  prefixlen 64  scopeid 0x0<global>
            ether dc:a6:32:1b:92:2a  txqueuelen 1000  (Ethernet)
            RX packets 5419  bytes 652998 (637.6 KiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 3688  bytes 686046 (669.9 KiB)
            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
            inet6 ::1  prefixlen 128  scopeid 0x10<host>
            loop  txqueuelen 1000  (Local Loopback)
            RX packets 156338  bytes 42863938 (40.8 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 156338  bytes 42863938 (40.8 MiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    ......
    

    看到了一个叫做docker0的网络设备,我们知道docker是一个C/S架构,默认情况下,docker的Server端会宿主机上创建一个叫做docker0的网络设备,功能上是作为网桥存在的, 当然这是虚拟网桥,所以进出容器的网络流量都要经过docker0。我们先做一个小实验,在容器里面向宿主机发3次包

    ping -c3 192.168.43.116
    

    看看docker0会发生什么?

    ➜  ~ sudo tcpdump -nn -i docker0 icmp
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
    10:18:05.256980 IP 172.17.0.2 > 192.168.43.116: ICMP echo request, id 2816, seq 0, length 64
    10:18:05.257082 IP 192.168.43.116 > 172.17.0.2: ICMP echo reply, id 2816, seq 0, length 64
    10:18:06.257362 IP 172.17.0.2 > 192.168.43.116: ICMP echo request, id 2816, seq 1, length 64
    10:18:06.257439 IP 192.168.43.116 > 172.17.0.2: ICMP echo reply, id 2816, seq 1, length 64
    10:18:07.257661 IP 172.17.0.2 > 192.168.43.116: ICMP echo request, id 2816, seq 2, length 64
    10:18:07.257710 IP 192.168.43.116 > 172.17.0.2: ICMP echo reply, id 2816, seq 2, length 64
    

    可以看到容器ip为172.17.0.2向ip为192.168.43.116的设备发送了3次ICMP包,如官方文档所描述的那样,容器的流量确实经过了docker0,可以docker0毕竟是网桥,容器连接到网桥上总得有根网线吧?当然这根网线一定是虚拟的,那么这根网络在哪呢?这里就必须得提另外一个概念:veth(Virtual Ethernet Device)

    The veth devices are virtual Ethernet devices. They can act as
    tunnels between network namespaces to create a bridge to a physical
    network device in another namespace, but can also be used as
    standalone network devices.
    这是官网的解释,我们可以这么理解(纯属为了方便理解),veth是一根网络,它有两端,容器中的eth0@if11是网线的一端,另一端在宿主机中,11即代表对端的网络设备号,我们在宿主机树莓派上查到该网络设备

    11: vethc426d5b@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
        link/ether 82:6c:38:bf:17:cf brd ff:ff:ff:ff:ff:ff link-netnsid 3
        inet 169.254.8.145/16 brd 169.254.255.255 scope global noprefixroute vethc426d5b
           valid_lft forever preferred_lft forever
        inet6 fe80::e079:e372:5724:fe10/64 scope link
           valid_lft forever preferred_lft forever
    

    同样的,我们对宿主机的vethc426d5b网络设备进行抓包验证

    ➜  ~ sudo tcpdump -nn -i vethc426d5b icmp
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on vethc426d5b, link-type EN10MB (Ethernet), capture size 262144 bytes
    10:37:24.832645 IP 172.17.0.2 > 192.168.43.116: ICMP echo request, id 3328, seq 0, length 64
    10:37:24.832906 IP 192.168.43.116 > 172.17.0.2: ICMP echo reply, id 3328, seq 0, length 64
    10:37:25.833154 IP 172.17.0.2 > 192.168.43.116: ICMP echo request, id 3328, seq 1, length 64
    10:37:25.833256 IP 192.168.43.116 > 172.17.0.2: ICMP echo reply, id 3328, seq 1, length 64
    10:37:26.833491 IP 172.17.0.2 > 192.168.43.116: ICMP echo request, id 3328, seq 2, length 64
    10:37:26.833615 IP 192.168.43.116 > 172.17.0.2: ICMP echo reply, id 3328, seq 2, length 64
    

    事实证明流量经过了vethc426d5b, 进行合并验证,由于tcpdump不提供同时对多个网络接口抓包的功能,因为,我分别同时对vethc426d5bdocker0进行icmp监听, 然后在容器中执行

    ping -Ieth0 -c1 192.168.43.116
    

    按时间排序得到抓包结果整理如下

    vethc426d5b 11:35:33.151414 IP 172.17.0.2 > 192.168.43.116: ICMP echo request, id 8704, seq 0, length 64
    docker0     11:35:33.151545 IP 172.17.0.2 > 192.168.43.116: ICMP echo request, id 8704, seq 0, length 64
    docker0     11:35:33.151657 IP 192.168.43.116 > 172.17.0.2: ICMP echo reply, id 8704, seq 0, length 64
    vethc426d5b 11:35:33.151684 IP 192.168.43.116 > 172.17.0.2: ICMP echo reply, id 8704, seq 0, length 64
    

    这个数据很好的证明了从容器中发出的icmp包的网络流量的数据走向是:容器网络eth0->vethc426d5b->docker0,所以容器与宿主机的网络通讯已经很清晰了,那容器与外部网络通信是如何进行的呢?
    我们知道虚拟设备的功能都是需要依托于实体的,这里我的树莓派使用的是无线网络,网络设备是wlan0,同样在容器内发包

    ping -Ieth0 -c1 cn.bing.com
    

    监控到wlan0上的网络流量

    ➜  ~ sudo tcpdump -nn -i wlan0 icmp
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
    12:15:24.591014 IP 192.168.43.116 > 202.89.233.101: ICMP echo request, id 16384, seq 0, length 64
    

    此时docker0上的网络流量

    ➜  ~ sudo tcpdump -nn -i docker0 icmp
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
    listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
    12:15:24.590912 IP 172.17.0.2 > 202.89.233.101: ICMP echo request, id 16384, seq 0, length 64
    

    此时很容易印证来自于容器内的网络流程从docker0流向了wlan0,如此,我们可以画一张简单的图来总结我们上述的抓包行为:

    veth (1).png

    至此,对容器的网络行为以及流向已经有了一个基本的了解,也可以跟docker的官网描述互为印证。

    Refer:

    相关文章

      网友评论

          本文标题:容器的网络通讯分析

          本文链接:https://www.haomeiwen.com/subject/kdqtictx.html