Docker网络详解(docker0/使用服务名访问通信/自定义网络)


学习视频链接,以示尊重:https://www.bilibili.com/video/BV1og4y1q7M4?p=37


Docker 网络详解
一、理解Docker0

Docker使用的是Linux的桥接,在宿主机中是一个Docker容器的网桥docker0。

每启动一个docker容器,docker就会给docker容器分配一个ip,只要安装了docker,就会有一个网卡docker0。

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

[root@iZ2ze436suxwekgjxx28iaZ ~]# 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:16:3e:32:87:68 brd ff:ff:ff:ff:ff:ff
    inet 172.17.7.69/20 brd 172.17.15.255 scope global dynamic noprefixroute eth0
       valid_lft 304994615sec preferred_lft 304994615sec
    inet6 fe80::216:3eff:fe32:8768/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:05:a3:f5:55 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:5ff:fea3:f555/64 scope link 
       valid_lft forever preferred_lft forever       
9: vethd68b892@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 66:19:f1:51:8f:d9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::6419:f1ff:fe51:8fd9/64 scope link 
       valid_lft forever preferred_lft forever
11: veth7542a6e@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 4e:d8:89:41:43:33 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::4cd8:89ff:fe41:4333/64 scope link 
       valid_lft forever preferred_lft forever
13: veth55d563b@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 4a:cb:72:7c:6a:ea brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::48cb:72ff:fe7c:6aea/64 scope link 
       valid_lft forever preferred_lft forever
17: veth2ebfe1b@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether ba:31:48:6f:62:a3 brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::b831:48ff:fe6f:62a3/64 scope link 
       valid_lft forever preferred_lft forever

其中:

  • lo 是本地回环地
  • docker0就是 docker0 地址,也就是 docker 的地址 172.17.7.69

那么,Docker如何处理容器的网络访问?

经过测试,发现主机可以ping通容器,而且容器和容器之间也可以ping通。docker0就像是一个路由器,各个容器就像是路由器下的设备,它们在同一个网段内,可以互相ping通

这正是由于docker的evth-pair技术。


二、evth-pair技术

docker使用的是桥接模式,使用的技术是evth-pair技术。

每启动一个容器,就会多一对网卡。因为这个容器带来的网卡都是一对对的。

evth-pair 是一对的虚拟设备接口,它们都是成对出现的。一端连接着协议,一端彼此相连,所以可以彼此通信。正因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备

本来linux是ping不通容器的,但利用evth-pair在两边都搞了一个接口,接口通过一种协议可以通信,所以相当于架了一个桥,让它们可以通信。

在这里插入图片描述

结论:tomcat01 和 tomcat02 是公用的一个路由器 docker0.

所有的容器不指定网络的前提下,都是docker0路由的,docker会给我们的容器分配一个默认的ip。

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

在这里插入图片描述

Docker网络的核心使用的是Linux的虚拟化技术,在容器内和docker0内分别建立一个虚拟网卡,再使用evth-pair技术进行连接。

Docker中的所有的网络接口都是虚拟的。因为虚拟的转发效率高。

只要容器删除,对应网桥一对就没有了。


三、- - link

如果服务宕机重启,docker分配的ip地址发生了改变,如何进行通信?

最好是可以不指定ip地址,而使用服务名称这个标识来进行通信

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

将两个网络通过--link进行连接:我们run一个centos03,使用--link连接上centos02,然后直接在centos03中ping centos02这个名字,发现可以ping通:

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

但是如果反过来操作,发现centos02是ping不通centos03的。

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,但是其中并没有任何关于link的信息。

紧接着,浏览一下03中的/etc/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。

到此可以得知,link信息是直接写在了hosts文件中,所以我们ping centos02或者02的id,可以直接ping到。

02中的hosts文件是没有03的,有一种方案是可以手动写入,但这样就要重启容器才能生效,很麻烦。

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


四、自定义网络

查看所有的docker网络:docker network ls

[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b47982b38d80        bridge              bridge              local
28a1b197470b        host                host                local
1a3c604475c8        none                null                local

其中:

  • bridge:桥接,即docker0(默认)
  • none:不配置网络
  • host:和宿主机共享网络

使用如下启动命令时,--net bridge可以指定,但是这个参数一般是默认的(不用写)

docker run -d -P --name tomcat01 --net bridge tomcat

docker0的特点:默认,域名不能访问,–link可以打通连接。

我们可以自定义一个网络,之后启动时指定并使用我们的自定义网络。

首先查看一下create方法的帮助文档:

[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network create --help

Usage:	docker network create [OPTIONS] NETWORK

Create a network

Options:
      --attachable           Enable manual container attachment
      --aux-address map      Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
      --config-from string   The network from which copying the configuration
      --config-only          Create a configuration only network
  -d, --driver string        Driver to manage the Network (default "bridge")
      --gateway strings      IPv4 or IPv6 Gateway for the master subnet
      --ingress              Create swarm routing-mesh network
      --internal             Restrict external access to the network
      --ip-range strings     Allocate container ip from a sub-range
      --ipam-driver string   IP Address Management Driver (default "default")
      --ipam-opt map         Set IPAM driver specific options (default map[])
      --ipv6                 Enable IPv6 networking
      --label list           Set metadata on a network
  -o, --opt map              Set driver specific options (default map[])
      --scope string         Control the network's scope
      --subnet strings       Subnet in CIDR format that represents a network segment

创建:

docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
af0c32b2c5fcbd92247d9e1f9a645ce901e0c8e3681b35b891074f5a5f355f3c

[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b47982b38d80        bridge              bridge              local
28a1b197470b        host                host                local
af0c32b2c5fc        mynet               bridge              local
1a3c604475c8        none                null                local
[root@iZ2ze436suxwekgjxx28iaZ ~]# 

查看自定义的网络:

[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "af0c32b2c5fcbd92247d9e1f9a645ce901e0c8e3681b35b891074f5a5f355f3c",
        "Created": "2020-10-14T21:30:47.972334524+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

至此,自定义网络创建成功!docker会帮我们维护好自定义网络中的对应关系,推荐使用。

启动容器时,使用该自定义网络,即可支持容器名访问。


五、网络连通

我们自定义的网络 mynet 中的容器和 docker0中的容器 如何连通呢?

核心命令:docker network connect,查看其帮助文档:

[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network --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.
[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network connect --help

Usage:	docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
      --alias strings           Add network-scoped alias for the container
      --driver-opt strings      driver options for the network
      --ip string               IPv4 address (e.g., 172.30.100.104)
      --ip6 string              IPv6 address (e.g., 2001:db8::33)
      --link list               Add link to another container
      --link-local-ip strings   Add a link-local address for the container

使用该命令:docker network connect

假设 tomcat01 是 docker0 中的容器,mynet 是我们的自定义网络,现在要使得 mynet 中的容器和 tomcat01连通。

[root@iZ2ze436suxwekgjxx28iaZ ~]# docker network connect mynet tomcat01

连通之后,会将tomcat01直接加到mynet之下(可以理解为一个容器,两个ip地址)。但是docker0下的其他未connect的容器仍旧无法连通。

结论:假设要跨网络操作别人,就需要使用 docker network connect 网络名 容器名

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值