zoukankan      html  css  js  c++  java
  • Docker的docker0网络

    参考资料:B站狂神视频教程
    https://www.bilibili.com/video/BV1og4y1q7M4?p=34

    什么是Docker0

    使用ip addr命令看一下网卡:

    root@KitDevVps:~# 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
        inet6 ::1/128 scope host 
           valid_lft forever preferred_lft forever
    2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
        link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
        inet xxx.xxx.xxx.xxx/23 brd xxx.xxx.xxx.xxx scope global dynamic ens3
           valid_lft 55158sec preferred_lft 55158sec
        inet6 xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/64 scope global dynamic mngtmpaddr noprefixroute 
           valid_lft 2591896sec preferred_lft 604696sec
        inet6 xxxx::xxxx:xxxx:xxxx:xxxx/64 scope link 
           valid_lft forever preferred_lft forever
    3: ens7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
        link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:8c:85:1a:f3 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
           valid_lft forever preferred_lft forever
        inet6 fe80::42:8cff:fe85:1af3/64 scope link 
           valid_lft forever preferred_lft forever
    30: vethxxcaxxa@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet6 xxxx::xxxx:xxxx:xxxx:xxxx/64 scope link 
           valid_lft forever preferred_lft forever
    

    其中lo是本地回环地址,docker0就是docker0地址,也就是docker的地址172.17.0.1。

    docker使用的是桥接模式,使用的技术是evth-pair技术,后面会解释。

    Docker如何处理容器的网络访问

    比如有两个容器,容器A要去访问容器B,该如何访问?使用127.0.0.1吗?还是写docker0地址?

    我们运行起一个centos01来,并且在它内部执行命令ip addr

    root@KitDevVps:~# docker run -d -it --name centos01 centos
    d07fb4674ffe04e7ef60540485c1c890faccffeb8f40c401ccf59965f1cb8760
    root@KitDevVps:~# docker sp
    docker: 'sp' is not a docker command.
    See 'docker --help'
    root@KitDevVps:~# docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
    d07fb4674ffe        centos              "/bin/bash"              7 seconds ago       Up 6 seconds                             centos01
    1cdd55fd90c5        nginx               "/docker-entrypoint.…"   2 days ago          Up 47 hours         0.0.0.0:80->80/tcp   nginx1
    root@KitDevVps:~# docker exec -it centos01 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
    115: eth0@if116: <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
    

    可以看到里面除了lo之外还有个115: eth0@if116,这是什么东西?可以发现我们每个容器启动的时候会得到一个eth0,这个容器就是eth0@if116,这是Docker给它分配的。

    尝试在本机能否ping通容器内部,我们在本地ping一下eth0@if116,也就是172.17.0.3:

    root@KitDevVps:~# ping 172.17.0.3
    PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
    64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.104 ms
    64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.093 ms
    64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.076 ms
    64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.073 ms
    64 bytes from 172.17.0.3: icmp_seq=5 ttl=64 time=0.087 ms
    ...
    ...
    ^C
    --- 172.17.0.3 ping statistics ---
    22 packets transmitted, 22 received, 0% packet loss, time 21508ms
    rtt min/avg/max/mdev = 0.064/0.085/0.114/0.019 ms
    

    发现是可以ping通的。现在已经得知主机可以ping通容器,那容器能否ping通容器?再run一个centos02试试:

    root@KitDevVps:~# docker exec -it centos02 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
    117: eth0@if118: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
           valid_lft forever preferred_lft forever
    failed to resize tty, using default size
    

    用它来ping centos01(172.17.0.3):

    [root@1ebe741425b2 /]# ping 172.17.0.3
    PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
    64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.103 ms
    64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.112 ms
    64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.075 ms
    64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.089 ms
    64 bytes from 172.17.0.3: icmp_seq=5 ttl=64 time=0.108 ms
    64 bytes from 172.17.0.3: icmp_seq=6 ttl=64 time=0.146 ms
    64 bytes from 172.17.0.3: icmp_seq=7 ttl=64 time=0.076 ms
    ^C
    --- 172.17.0.3 ping statistics ---
    7 packets transmitted, 7 received, 0% packet loss, time 129ms
    rtt min/avg/max/mdev = 0.075/0.101/0.146/0.024 ms
    

    到现在,docker0的地址是172.17.0.1,centos01的地址是172.17.0.3,centos02的地址是172.17.0.4。docker0就像是一个路由器,centos01和02就像是路由器下的设备,它们在同一个网段内,可以互相ping通。

    此时再在本机使用ip addr

    UTOOLS1593935145952.png

    发现多了两个这种网卡,而我们run起来的centos01和02的网卡分别为 115: eth0@if116 和
    117: eth0@if118。它们似乎有某种关联。

    可以发现容器的网卡都是一对一对的,这就是前面说的evth-pair技术。evth-pair就是一对虚拟设备接口,它们都是成对出现的,一端连着协议,一端彼此相连,所以可以通信。evth-pair可以充当一个桥梁。

    UTOOLS1593935496102.png

    这是B站up主狂神画的简单示意图,本来linux是ping不通容器的,但利用evth-pair在两边都搞了一个接口,接口通过一种协议可以通信,所以相当于架了一个桥,让它们可以通信。

    UTOOLS1593936383414.png

    两个容器看似是直接ping通的,实际是通过docker0来ping通的。docker0就像路由器,每run出一个容器来,就把它的地址在这个路由器上注册。

    UTOOLS1593936601114.png

    --link与docker network

    如果服务宕机重启,分配的ip地址发生了改变,如何进行通信?最好是可以不指定ip地址,而使用服务名称这个标识来进行通信。比如有很多mssql服务,服务名就叫mssql,但它们的ip地址都不一样,如果可以通过服务名来ping,就很好了。一个服务挂了重启,整个项目就不用重启。就是做到项目不重启,还能把数据库替换掉。因为docker重启是会更换ip的。我们希望能够通过名字访问,解决这个问题。

    可以通过比较老的--link来解决。

    先尝试centos01能否直接通过名字ping通centos02:

    root@KitDevVps:~# docker exec -it centos01 ping centos02
    ping: centos02: Name or service not known
    

    是ping不通的。我们将两个网络进行连接就可以解决了。我们run一个centos03,使用--link连接上centos02,然后直接在centos03中ping centos02这个名字:

    root@KitDevVps:~# docker run -d -it --name centos03 --link centos02 centos
    ad50e83c3041eb76d4905670a8cc91bc23c60d3933b5d5f51f702983e9f5711d
    root@KitDevVps:~# docker exec -it centos03 ping centos02
    PING centos02 (172.17.0.4) 56(84) bytes of data.
    64 bytes from centos02 (172.17.0.4): icmp_seq=1 ttl=64 time=0.146 ms
    64 bytes from centos02 (172.17.0.4): icmp_seq=2 ttl=64 time=0.097 ms
    64 bytes from centos02 (172.17.0.4): icmp_seq=3 ttl=64 time=0.128 ms
    64 bytes from centos02 (172.17.0.4): icmp_seq=4 ttl=64 time=0.097 ms
    ^C
    --- centos02 ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 45ms
    rtt min/avg/max/mdev = 0.097/0.117/0.146/0.021 ms
    

    发现是可以ping通的。但是02ping不通03:

    root@KitDevVps:~# docker exec -it centos02 ping centos03
    ping: centos03: Name or service not known
    

    因为centos02根本不知道centos03是什么东西,没有给它配置。想让02ping通03,肯定要对02进行一些配置。

    我们使用命令docker network ls来查看当前的网络。先看一下docker network怎么用:

    root@KitDevVps:~# docker network -h
    Flag shorthand -h has been deprecated, please use --help
    
    Usage:	docker network COMMAND
    
    Manage networks
    
    Commands:
      connect     Connect a container to a network
      create      Create a network
      disconnect  Disconnect a container from a network
      inspect     Display detailed information on one or more networks
      ls          List networks
      prune       Remove all unused networks
      rm          Remove one or more networks
    
    Run 'docker network COMMAND --help' for more information on a command.
    

    然后docker network ls

    root@KitDevVps:~# docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    1375b7ef4bbc        bridge              bridge              local
    b29eab4db971        host                host                local
    acfcd6eaf888        none                null                local
    

    可以看到上面有个bridge,我们可以使用docker network inspect 1375b7ef4bbc来查看这个bridge的详细信息:

    root@KitDevVps:~# docker network inspect 1375b7ef4bbc
    
    ...
    
    "Name": "bridge",
            "Id": "1375b7ef4bbcf53a812fc8397787f17f2b47ea412292daea3324e016c48f5738",
            "Created": "2020-07-03T02:06:46.264143987Z",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": null,
                "Config": [
                    {
                        "Subnet": "172.17.0.0/16"
                    }
                ]
            },
            "Internal": false,
            "Attachable": false,
            "Ingress": false,
            "ConfigFrom": {
                "Network": ""
            },
            "ConfigOnly": false,
    "Containers": {
        "1cdd55fd90c550de6b2ad1544df5ae08b50c85d06d2a9f2e416bf0dbd0ac164d": {
            "Name": "nginx1",
            "EndpointID": "16c89d4f905cb8437a5a539064358a37d6ca09e46d5af653db09e639d2ff56ef",
            "MacAddress": "02:42:ac:11:00:02",
            "IPv4Address": "172.17.0.2/16",
            "IPv6Address": ""
        },
        "1ebe741425b2c80226fe265d170ed0567a6321ea7d7c4b3f4ab787985b2a6308": {
            "Name": "centos02",
            "EndpointID": "6f468d178b612079095203cd0df4e58705069ead019ab72011646259dac67cec",
            "MacAddress": "02:42:ac:11:00:04",
            "IPv4Address": "172.17.0.4/16",
            "IPv6Address": ""
        },
        "ad50e83c3041eb76d4905670a8cc91bc23c60d3933b5d5f51f702983e9f5711d": {
            "Name": "centos03",
            "EndpointID": "f54109b911f200c1afaad50d5459bb67a778fd5e64358f6344d2891e463d0598",
            "MacAddress": "02:42:ac:11:00:05",
            "IPv4Address": "172.17.0.5/16",
            "IPv6Address": ""
        },
        "d07fb4674ffe04e7ef60540485c1c890faccffeb8f40c401ccf59965f1cb8760": {
            "Name": "centos01",
            "EndpointID": "89a3ea298b219971b9aa477efe67506e333a4d410083d56659fce3a6edbc259e",
            "MacAddress": "02:42:ac:11:00:03",
            "IPv4Address": "172.17.0.3/16",
            "IPv6Address": ""
        }
    },
    
    ...
    
    

    可以看到上面这一部分的containers中有我们正在运行的所有容器和他们的ip。运行容器不指定ip的时候它就会随机分配一个ip。

    docker03实际上就是在本地配置了docker02的配置。

    然后我们使用docker inspect 容器id来查看我们的centos03,因为我们用它link了02,我们看一下03里面有没有什么link的线索:

    结果我就不放了,因为没有什么线索。

    我们cat一下03中的/etc/hosts文件,看看是不是在这里面配置了。这个就跟windows的hosts文件性质是一样的:

    root@KitDevVps:~# docker exec -it centos03 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.4	centos02 1ebe741425b2
    172.17.0.5	ad50e83c3041
    

    在倒数第二行我们看到了centos02和它的ip地址以及它的id。这样我们就了解它的原理了,直接写在了hosts文件中,所以我们ping centos02或者02的id,可以直接ping到。02中的hosts文件是没有03的,我们可以手动写入,但这样就要重启容器才能生效,太麻烦,不弄了。

    实际上这种--link的方式已经不推荐使用了。docker0不支持容器名,我们需要自定义网络,不使用docker0。

  • 相关阅读:
    这些 Drawable 的小技巧,你都了解吗?
    Android 软键盘的显示和隐藏,这样操作就对了
    在 ReactNative 的 App 中,集成 Bugly 你会遇到的一些坑
    聊聊 Material Design 里,阴影的那些事儿!
    PAT 1069 1070 1071 1072
    PAT1021 Deepest Root
    关于素数:求不超过n的素数,素数的判定(Miller Rabin 测试)
    PAT《数据结构学习与实验指导》实验项目集 2-05 2-06 2-07 2-08
    LeetCode:Gas Station
    LeetCode:Candy
  • 原文地址:https://www.cnblogs.com/Kit-L/p/13246782.html
Copyright © 2011-2022 走看看