美文网首页docker
一文搞懂Docker的网络模式

一文搞懂Docker的网络模式

作者: 明翼 | 来源:发表于2022-05-08 07:49 被阅读0次

    一 前言

    根据上篇知识了解到,通过设置不同的网络空间来达到网络协议栈的完全隔离,对于不同空间的协议栈是完全隔离,每个网络空间都可以有自己的iptables来进行单独的转发过滤等,不同的网络空间默认无法进行网络通信的,但是通过veth可以把两个不同的网络空间打通达到通讯的目的,前一篇文章也进行了相关的说明。

    二 Docker的网络模式

    2.1 桥接模式

    Docker的默认使用的是linux的桥接模式,有个docker0的虚拟桥,docker 每启动一个容器就给这个容器分配一个container ip,同时设置了docker0 桥作为默认的网关,默认情况下容器的网络都通过veth的技术来接到docker0这个虚拟桥上来达到通讯的目的。

    docker run  -d  --name nginx02 -P   nginx
    docker run  -d  --name nginx03 -P   nginx
    

    启动两个nginx镜像,用docker ps看下是否存在:

    root@ubuntu-lab:/home/miao# docker ps
    CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                                     NAMES
    bd64ce2fdfd2   nginx     "/docker-entrypoint.…"   4 minutes ago   Up 4 minutes   0.0.0.0:49154->80/tcp, :::49154->80/tcp   nginx03
    687427d720b1   nginx     "/docker-entrypoint.…"   5 minutes ago   Up 5 minutes   0.0.0.0:49153->80/tcp, :::49153->80/tcp   nginx02
    

    我们知道veth都是成对出现的,我们来验证下,是否有两个veth,且一端应该是配置了ip的即container-ip,另一端可以理解为插在虚拟网桥上的。

    由于nginx的容器默认是没有带ip命令的,需要安装下:

    docker exec -it nginx02 /bin/bash
    apt-get update
    apt-get install iproute2
    

    用命令看下容器内的网卡情况:

    root@ubuntu-lab:~# docker exec -it nginx03 ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
    29: eth0@if30: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
           valid_lft forever preferred_lft forever
    root@ubuntu-lab:~# docker exec -it nginx02 ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
    27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
           valid_lft forever preferred_lft forever
    root@ubuntu-lab:~# 
    

    清楚的看到配置的地址分别为:172.17.0.2172.17.0.3
    注意看下网卡名都是含有@符号的,这个是veth的标识,eth0是其中的一端,这个配置了上面的地址,另一端是if30和if28,这个需要到宿主机器上查看:

    # ip addr show
    28: vethd7194ee@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 66:c6:93:2e:6b:7d brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet6 fe80::64c6:93ff:fe2e:6b7d/64 scope link 
           valid_lft forever preferred_lft forever
    30: veth8236973@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether be:9d:3d:ca:38:53 brd ff:ff:ff:ff:ff:ff link-netnsid 3
        inet6 fe80::bc9d:3dff:feca:3853/64 scope link 
           valid_lft forever preferred_lft forever
    

    看到了28序号的30序号的网卡,刚好对应容器内的27和29两个序号的网卡。

    那我们再来看下网桥情况:

    root@ubuntu-lab:~# brctl show
    bridge name bridge id       STP enabled interfaces
    docker0     8000.0242726f7fa2   no  veth8236973
                                          vethd7194ee
    
    

    看到了吧,网桥上插着veth的一端,画出图形如下:

    docker 桥接模式

    注意到这里面和上一篇桥接模式的区别为没有看到单独的网络空间(实际上应该有,不然怎么做网络隔离那,通过下面的命令没看到):

    root@ubuntu-lab:~# ip netns list
    

    但是两者网络是互通的,测试:

    root@ubuntu-lab:~# docker exec -it nginx02 ping 172.17.0.3
    PING 172.17.0.3 (172.17.0.3): 56 data bytes
    64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.224 ms
    64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.108 ms
    ^C--- 172.17.0.3 ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max/stddev = 0.108/0.166/0.224/0.058 ms
    

    顺便说下,我们启动nginx的时候,通过-P指定了随机端口和80端口的映射,这个是通过nat来实现的,测试如下图:

    root@ubuntu-lab:~# iptables -t nat -vnL 
    

    桥接模式缺点,虽然我们可以互通,但是不能通过容器的名称ping通,有一定局限性。

    3.2 host模式

    host模式比较简单,如果容器以host模式启动,容器不会获得独立的Network namespace,和宿主主机共享Network namespace,不能配置ip,也不会虚拟出网卡。
    它启动的端口也会占用主机的端口,外部访问直接通过宿主机器的ip进行访问即可。

    root@ubuntu-lab:/home/miao# docker run -d  --name nginx01    --network host nginx
    
    root@ubuntu-lab:/home/miao# docker ps
    CONTAINER ID   IMAGE     COMMAND                  CREATED             STATUS          PORTS     NAMES
    0ebd1b751f50   nginx     "/docker-entrypoint.…"   About an hour ago   Up 36 seconds             nginx01
    
    root@ubuntu-lab:/home/miao# netstat -antp|grep 80
    tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      79104/nginx: master 
    tcp6       0      0 :::80                   :::*                    LISTEN      79104/nginx: master 
    

    外部访问测试:


    host模式外部直接访问

    3.3 none模式

    这个模式下没有网络,端口也不能通过-p来映射出来,没办法联网,监听只能在lo上,也就是只能本机访问,容器更安全,不过也只能测试玩玩。

    root@ubuntu-lab:/home/miao# docker run --name mynginx --network none -d nginx
    99a861a124099946d6f8802f09871b6cc9881d5c10161c084997bd4847e872a7
    root@ubuntu-lab:/home/miao# docker ps
    CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
    99a861a12409   nginx     "/docker-entrypoint.…"   3 seconds ago   Up 2 seconds             mynginx
    
    

    三 其他

    3.1 容器名是否可以ping通

    如果我们想通过容器名ping通,那么我们就可以通过容器名做连接,即实现:

    root@ubuntu-lab:/home/miao# docker exec -it nginx02 ping nginx03
    ping: unknown host
    

    最简单的采用link方式:

    root@ubuntu-lab:/home/miao# docker run -d -P --name nginx02 --link nginx03 nginx
    #安装ping工具
    root@ubuntu-lab:/home/miao# docker exec -it nginx02
    root@3748ab1cb1e0:/# apt-get install -y iputils-ping
    root@ubuntu-lab:/home/miao# docker exec -it nginx02 ping nginx03
    PING nginx03 (172.17.0.3) 56(84) bytes of data.
    64 bytes from nginx03 (172.17.0.3): icmp_seq=1 ttl=64 time=0.106 ms
    64 bytes from nginx03 (172.17.0.3): icmp_seq=2 ttl=64 time=0.087 ms
    ^C
    

    ok,就这样简单的通了,那么反过来那:

    root@ubuntu-lab:/home/miao# docker exec -it nginx03 ping nginx02
    OCI runtime exec failed: exec failed: unable to start container process: exec: "ping": executable file not found in $PATH: unknown
    

    不行,反向不通.其实只是将nginx03的ip和host的映射,配置到了nginx02容器的/etc/hosts里面。

    root@ubuntu-lab:/home/miao# docker exec -it nginx02 cat /etc/hosts
    127.0.0.1   localhost
    ::1 localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    172.17.0.3  nginx03 bd64ce2fdfd2
    172.17.0.2  3748ab1cb1e0
    
    

    3.2 docker的自定义网络

    我们原来使用docker0作为虚拟网桥进行容器的连接,但是有docker0有限制,比如不能通过容器名直接访问。

    确保网络环境干净

    root@ubuntu-lab:/home/miao# docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    d8f1fa7ccbd3   bridge    bridge    local
    1bd98c27e839   host      host      local
    84542ce461aa   none      null      local
    
    

    创建自定义网络

    root@ubuntu-lab:/home/miao# docker network create --driver bridge --subnet 192.168.3.0/24 --gateway 192.168.3.1 mynet
    db74fc9a41e40002755989da5d83d59cca1dfb490f6c26a9f85026617d2d25cc
    root@ubuntu-lab:/home/miao# docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    ...
    48ee4153016f   mynet     bridge    local
    ...
    
    

    启动两个新的容器,网络设置成我们新建的网络:

    root@ubuntu-lab:/home/miao# docker run -d -P --name nginx-net-01 --net mynet nginx
    c44262be7824f4649f96b0df83ac44460f7c49c135577ee832af2a93f0cf81e3
    root@ubuntu-lab:/home/miao# docker run -d -P --name nginx-net-02 --net mynet nginx
    c488ece52f691fd228916df2046fa17efd971ad81299d46f358be6c372593095
    root@ubuntu-lab:/home/miao# docker ps
    CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS         PORTS                                     NAMES
    c488ece52f69   nginx     "/docker-entrypoint.…"   3 seconds ago    Up 3 seconds   0.0.0.0:49161->80/tcp, :::49161->80/tcp   nginx-net-02
    c44262be7824   nginx     "/docker-entrypoint.…"   10 seconds ago   Up 9 seconds   0.0.0.0:49160->80/tcp, :::49160->80/tcp   nginx-net-01
    
    

    可以看到ip是我们网络内的ip如下:

    root@ubuntu-lab:/home/miao# docker inspect nginx-net-02|grep IPAddress
                "SecondaryIPAddresses": null,
                "IPAddress": "",
                        "IPAddress": "192.168.3.3",
    root@ubuntu-lab:/home/miao# docker inspect nginx-net-01|grep IPAddress
                "SecondaryIPAddresses": null,
                "IPAddress": "",
                        "IPAddress": "192.168.3.2",
    

    测试下:

    root@ubuntu-lab:/home/miao# docker exec -it nginx-net-02 ping nginx-net-01
    PING nginx-net-01 (192.168.3.2) 56(84) bytes of data.
    64 bytes from nginx-net-01.mynet (192.168.3.2): icmp_seq=1 ttl=64 time=0.215 ms
    64 bytes from nginx-net-01.mynet (192.168.3.2): icmp_seq=2 ttl=64 time=0.175 ms
    
    

    不用额外配置,自定义网络直接可以ping通,牛了。

    3.3 跨网络访问

    我们把nginx02,nginx03也启动起来,现在的docker的容器的网络情况如下图:


    docker容器环境

    如上图,如果我们想通过nginx02访问nginx-net-01怎么办,这个场景也比较常见,比如我们的应用在一个网络环境,数据库在另外一个网络环境(我这么懒应该不会这么部署)。

    # 我们把nginx02 连接到mynet网络上去
    root@ubuntu-lab:/home/miao# docker network connect mynet nginx02
    # 查看执行成功后的变化:
    root@ubuntu-lab:/home/miao# docker network inspect mynet
            "Containers": {
                "3748ab1cb1e07f590dce7283d9e40f2edcc6fa15c1ebfefe4a4d6441e9ec5a25": {
                    "Name": "nginx02",
                    "EndpointID": "7f7aea9645f2dee4502122f3bd302aa662b55ec31f972827246b8e381904b42b",
                    "MacAddress": "02:42:c0:a8:03:04",
                    "IPv4Address": "192.168.3.4/24",
                    "IPv6Address": ""
                },
                "c44262be7824f4649f96b0df83ac44460f7c49c135577ee832af2a93f0cf81e3": {
                    "Name": "nginx-net-01",
                    "EndpointID": "b925305ae883ca4d621983bac339f16e87580a37e9e89dfb41c8fbd51b819213",
                    "MacAddress": "02:42:c0:a8:03:02",
                    "IPv4Address": "192.168.3.2/24",
                    "IPv6Address": ""
                },
                "c488ece52f691fd228916df2046fa17efd971ad81299d46f358be6c372593095": {
                    "Name": "nginx-net-02",
                    "EndpointID": "5e1ecdcbbaba78fa050a69780543f82dd90a445e8fcea8170e383b5161ca5dd7",
                    "MacAddress": "02:42:c0:a8:03:03",
                    "IPv4Address": "192.168.3.3/24",
                    "IPv6Address": ""
                }
            },
    

    原来是把nginx02直接加入到mynet网络,分配一个新的ip:192.168.3.4, 相当于这个容器有了两个ip:

    root@ubuntu-lab:/home/miao# docker exec -it nginx02 ping nginx-net-01
    PING nginx-net-01 (192.168.3.2) 56(84) bytes of data.
    64 bytes from nginx-net-01.mynet (192.168.3.2): icmp_seq=1 ttl=64 time=11.9 ms
    64 bytes from nginx-net-01.mynet (192.168.3.2): icmp_seq=2 ttl=64 time=0.127 ms
    ^C
    --- nginx-net-01 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1003ms
    rtt min/avg/max/mdev = 0.127/6.003/11.880/5.876 ms
    root@ubuntu-lab:/home/miao# docker exec -it nginx02 ping nginx-net-02
    PING nginx-net-02 (192.168.3.3) 56(84) bytes of data.
    64 bytes from nginx-net-02.mynet (192.168.3.3): icmp_seq=1 ttl=64 time=0.184 ms
    64 bytes from nginx-net-02.mynet (192.168.3.3): icmp_seq=2 ttl=64 time=0.080 m
    

    如上,现在ping稳稳的,那么我们来看看nginx02的网卡信息:

    root@3748ab1cb1e0:/# ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
    47: eth0@if48: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
           valid_lft forever preferred_lft forever
    49: eth1@if50: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:c0:a8:03:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 192.168.3.4/24 brd 192.168.3.255 scope global eth1
           valid_lft forever preferred_lft forever
    

    原来是新建立veth对,配置ip是mynet里面网段的ip,看看桥里面信息:

    root@ubuntu-lab:/home/miao# brctl show
    bridge name bridge id       STP enabled interfaces
    br-db74fc9a41e4     8000.024238d7721a   no      veth28769e3
                                                    veth8adc720
                                                    vetha525bf6
    

    这个是通过新建个网桥把三个网卡对连接起来了。我理解这相当于通过一个交换机把三者都接起来,只是在nginx02上新增了一块网卡。
    看下:

    root@ubuntu-lab:/home/miao# docker exec -it nginx-net-02 /bin/bash
    root@c488ece52f69:/# ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
    41: eth0@if42: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:c0:a8:03:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 192.168.3.3/24 brd 192.168.3.255 scope global eth0
           valid_lft forever preferred_lft forever
    
    

    这里面有要注意的地方,mynet网络的主机只有一个ip。其实还有更复杂的场景没测试,我觉得现在这个也够了,下次用到再说。

    相关文章

      网友评论

        本文标题:一文搞懂Docker的网络模式

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