Docker网络原理详解

Posted 我的紫霞辣辣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker网络原理详解相关的知识,希望对你有一定的参考价值。

Docker网络原理

理解docker0

Dokcer是如何处理网络访问的

[root@docker01 ~]# docker run -d -P --name tomcat01 tomcat

发现容器启动的时候会得到一个eth0@if32 ip地址,这是docker分配的。
# 查看容器的内部网络地址
[root@docker01 ~]# docker exec -it tomcat01 ip a
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
31: eth0@if32: <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

# 思考:linux能不能ping通容器内部!
[root@docker01 ~]# docker exec -it tomcat01 ip a
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
31: eth0@if32: <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@docker01 ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.053 ms

结论:linux主机可以ping通dokcer容器内部

evth-pair技术

1. 我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只有安装了dokcer,就会有一个默认的网卡docker0。
桥接模式,使用的技术是evth-pair技术!

我们发现这个容器带来的网卡,都是一对对的
evth-pair 就是一对虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连
正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备
Openstac,Docker容器之间的连接,OVS的连接,都是使用的evth-pair技术

我们来测试一下tomcat01和tomcat02是否可以ping通!

[root@docker01 ~]# docker exec -it tomcat02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.268 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.041 ms

结论:容器和容器之间是可以互相ping通的!!!

Docker使用的是Linux的桥接,宿主机中的Docker0(路由器)是容器与容器之间通信的网桥

结论:
1. tomcat01 和 tomcat02 是公用的一个路由器,docker0!!!
2. 所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们容器分配一个默认的可用IP。
3. Docker中所有的网络接口都是虚拟的,虚拟的网络接口转发效率高!!!(内网传递文件)
4. 只要容器删除,对应的一对网桥就没了

–link原理详解

思考一个场景,我们编写了一个微服务,database url=ip,项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可以使用名字来进行访问容器

[root@docker01 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND             CREATED          STATUS          PORTS                   
82cc06227f07   tomcat    "catalina.sh run"   24 seconds ago   Up 22 seconds   0.0.0.0:49153->8080/tcp,
ded1034bc67c   tomcat    "catalina.sh run"   10 hours ago     Up 4 seconds    0.0.0.0:49154->8080/tcp,

# 使用容器名,容器与容器之间是无法ping通的。
[root@docker01 ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known

# 使用--link可以解决网络连通问题
[root@docker01 ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
a380f84173f727160ac3e1873fc02b048eae8739be78f67832e4598f0760dea8

# 加了--link,使用容器名,容器与容器之间也是可以ping通的
[root@docker01 ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.088 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.122 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.094 ms

# 反向使用容器名,容器与容器之间依然是无法ping通的。
[root@docker01 ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

# 查看tomcat03的hosts文件配置
[root@docker01 ~]# docker exec -it tomcat03 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	tomcat02 ded1034bc67c			# 添加了tomcat02的容器名,与容器的ip做了映射(因此可以使用容器名进行网络连接)
172.17.0.4	a380f84173f7

# 查看tomcat02的hosts文件配置
[root@docker01 ~]# docker exec -it tomcat02 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	ded1034bc67c				# 没有做映射(无法使用容器名进行网络连接)

结论: --link就是我们在hosts配置中增加了一个172.17.0.3	tomcat02 ded1034bc67c

结论:
其实这个tomcat03就是在本地配置了tomcat02的配置
我们现在使用Docker以及不建议使用–link了
自定义网络,不适用Docker0
docker0的问题,它不支持容器名称连接访问!!!

自定义网络

# 查看所有的docker网络
[root@docker01 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
8d86283631e5   bridge    bridge    local
e185b787c28e   host      host      local
01c19cbebe06   none      null      local

网络模式

bridge:桥接模式 dodker	(默认,自己创建也使用bridge)

none:不配置网络

host:和宿主机共享网络

container:容器内网络连通!(用的少!局限性很大)

自定义一个网络

# --driver		指定网络模式
# --subnet 		指定子网地址
# --gateway 		指定网关地址
# mynet		网卡名
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
# 清空所有的容器
[root@docker01 ~]# docker rm -f `docker ps -qa`

# 我们直接启动容器的命令(默认加参数 --net bridge),而这个就是我们的docker0
docker run -d -P --name tomcat01 --net bridge tomcat
docker run -d -P --name tomcat01 tomcat

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

- 我们可以自定义一个网络
# --driver bridge				桥接模式
# --subnet 192.168.0.0/16			子网地址
# --gateway 192.168.0.1			网关地址
[root@docker01 ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
05a0b41b0ec470afcf9cee3af9e1afd2f4e6ab7665912ca949aa65d79af3d4b0

# 创建两个容器使用我们自定义的网络mynet
[root@docker01 ~]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
46c0ca2ee004fc2f9480c94670b5919b48d056931c4c8ee87a2f745942a3d2fe
[root@docker01 ~]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
5a72dfc63a90a2ee92d05e256f3cab1db860efe48ee93bf756612e6f78d62e28

# 查看我们自定义的网络信息
[root@docker01 ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "05a0b41b0ec470afcf9cee3af9e1afd2f4e6ab7665912ca949aa65d79af3d4b0",
        "Created": "2021-07-30T11:19:14.217679899+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": {
            "46c0ca2ee004fc2f9480c94670b5919b48d056931c4c8ee87a2f745942a3d2fe": {
                "Name": "tomcat-net-01",
                "EndpointID": "072216838c62a2d8c436483f21a28d1b0cc84eb875442f7eceec9af101ea8bac",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "5a72dfc63a90a2ee92d05e256f3cab1db860efe48ee93bf756612e6f78d62e28": {
                "Name": "tomcat-net-02",
                "EndpointID": "327922b893c524d0416f6baf8d4d378199b5c7b412c7addce617467c09716f77",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

# 再次测试ping连接
[root@docker01 ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.141 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.085 ms

# 现在不使用--link也可以ping名字了
[root@docker01 ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.032 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.084 ms

结论:
我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络!
不同的集群可以使用不同的网络,保证了集群的安全和健康!!!

# 创建两个容器,使用默认的网关docker0
[root@docker01 ~]# docker run -d -P --name tomcat01 --net bridge tomcat
ba47cdb9d5a62bbe8d805361c74f8f991452731514a4ba6f9a1041b7012c18db
[root@docker01 ~]# docker run -d -P --name tomcat02 tomcat
c079eb26867546f60054de96ebcdeaa0538fbd4ee7ed264355340158375365c7

[root@docker01 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND             CREATED          STATUS          PORTS                                         NAMES
c079eb268675   tomcat    "catalina.sh run"   2 seconds ago    Up 2 seconds    0.0.0.0:49160->8080/tcp, :::49160->8080/tcp   tomcat02
5a72dfc63a90   tomcat    "catalina.sh run"   55 minutes ago   Up 55 minutes   0.0.0.0:49159->8080/tcp, :::49159->8080/tcp   tomcat-net-02
46c0ca2ee004   tomcat    "catalina.sh run"   55 minutes ago   Up 55 minutes   0.0.0.0:49158->8080/tcp, :::49158->8080/tcp   tomcat-net-01
ba47cdb9d5a6   tomcat    "catalina.sh run"   2 hours ago      Up 2 hours      0.0.0.0:49157->8080/tcp, :::49157->8080/tcp   tomcat01

# 测试,我们使用Docker0网关的tomcat01是无法ping通自定义网关mynet的tomcat-net-01的
[root@docker01 ~]# docker exec -it tomcat01 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known

Docker网络连通


如上图所示:如果我们想要将 tomcat-01 能够连接上 tomcat-net-01,
又要确保网卡与网卡之间的网络环境是独立的,那么我就需要将tomcat-01与自定义的网卡mynet打通网络。

docker network connect mynet tomcat01		# 打通 tomcat01 和 mynet 之间的网络 
# 打通 tomcat01 和 mynet 之间的网络 
[root@docker01 ~]# docker network connect mynet tomcat01

# 连通之后就是将tomcat01放到了mynet网络下
# 一个容器两个ip地址 相当于:公网ip和私网ip
[root@docker01 ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "05a0b41b0ec470afcf9cee3af9e1afd2f4e6ab7665912ca949aa65d79af3d4b0",
        "Created": "2021-07-30T11:19:14.217679899+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": {
            "46c0ca2ee004fc2f9480c94670b5919b48d056931c4c8ee87a2f745942a3d2fe": {
                "Name": "tomcat-net-01",
                "EndpointID": "072216838c62a2d8c436483f21a28d1b0cc84eb875442f7eceec9af101ea8bac",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "5a72dfc63a90a2ee92d05e256f3cab1db860efe48ee93bf756612e6f78d62e28": {
                "Name": "tomcat-net-02",
                "EndpointID": "327922b893c524d0416f6baf8d4d378199b5c7b412c7addce617467c09716f77",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "ba47cdb9d5a62bbe8d805361c74f8f991452731514a4ba6f9a1041b7012c18db": {
                "Name": "tomcat01",
                "EndpointID": "f6cdc1e280ea85e185b8f4c97df1db052c6367565c779a2b9be433d0973c5711",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

# 打通网络之后,测试连接
[root@docker01 ~]# docker exec -it tomcat01 ping -c1 tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.211 ms

[root@docker01 ~]# docker exec -it tomcat01 ping -c1 tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.117 ms

# tomcat02没有打通网络,依旧连接不上
[root@docker01 ~]# docker exec -it tomcat02 ping -c1 tomcat-net-02
ping: tomcat-net-02: Name or service not known

以上是关于Docker网络原理详解的主要内容,如果未能解决你的问题,请参考以下文章

强力的应用容器引擎——Docker网络部分详解

Docker 网络详解(hostcontainernoneBridge网络模式大解析)

七Docker网络模式详解

Docker网络及资源管理

Docker网络及资源管理

docker网络