乐趣区

关于docker:有了这篇-Docker-网络原理彻底爱了

Docker 网络原理

容器是绝对独立的环境,相当于一个小型的 Linux 零碎,外界无奈间接拜访,那他是怎么做的呢,这里咱们先理解下 Linux veth pair。

1. Linux veth pair

veth pair 是成对呈现的一种虚构网络设备接口,一端连着网络协议栈,一端彼此相连。如下图所示:

veth pair 将两个网络 veth0 和 veth1 连通。

2. 了解 Docker0

咱们先查看本地 ip

这里咱们剖析可得,有三个网络:

lo      127.0.0.1      # 本机回环地址
eth0    172.31.179.120   # 阿里云的公有 IP(如果你是虚拟机就是虚拟机的 ip)docker0 172.17.0.1       # docker 网桥 

lo 和 eth0 在咱们的虚拟机启动的时候就会创立,然而 docker0 在咱们装置了 docker 的时候就会创立。docker0 用来和虚拟机之间通信。

问题:Docker 是如何解决容器网络拜访的?咱们先启动一个 tomcat 容器来阐明。

[root@jiangnan tomcat1]# docker pull tomcat
[root@jiangnan tomcat1]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
tomcat       latest    fb5657adc892   2 months ago   680MB
[root@jiangnan tomcat1]# docker run -d -p 8081:8080 --name tomcat01 tomcat
914a7d82b017f63f81c6eba49af5471441f1946c9d45509b69ab2c50c2713b6f
[root@jiangnan tomcat1]#

这里启动了 tomcat01,咱们再来查看网络

发现:咱们后面查看的时候还是三组网卡,当启动了一个 tomcat 容器之后,多了一组网卡 201: vethad33778@if200,而且还是成对的。同样咱们再来启动一个 tomcat02 会又多出一对网卡。

进入了 tomcat01 容器内能够看到 tomcat01 对应的 ip 地址为:172.17.0.2

在宿主机上也可 ping 通。

阐明:tomcat02 对应的 ip 为 172.17.0.3,也能够 ping 通。

论断:咱们每启动一个容器,就会多出一对网卡,同时他们被连贯到 docker0 上,而 docker0 又和虚拟机之间连通。

也能够通过 inspect 查看。

[root@jiangnan tomcat1]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4d3e75606593   bridge    bridge    local   # 这个就是 docker0
8e92ee24e5f6   host      host      local
e85ffb1f2cc3   none      null      local

[root@jiangnan tomcat1]# docker inspect 4d3e75606593
"IPAM": {   
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"    # 网关
                }
            ]
        },

"Containers": {   # 容器
            "15910ee083965d60c46bf9b3b292570fef9b8925905aa4df90c6d48142bb2eee": {
                "Name": "tomcat01",
                "EndpointID": "9c7a5ab65f1fc91b1d92ad61dec9b2f518f67f69f662522483dca789616f42aa",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""},"6c9a6a5d8eca9ad52926008c7b30516d23293ff8ad1f38947957d571431d5297": {"Name":"tomcat02","EndpointID":"f83c1e643236cd65f50fba03929ca14d5df8d135b1f6cb8adf203cf96084f7aa","MacAddress":"02:42:ac:11:00:03","IPv4Address":"172.17.0.3/16","IPv6Address":""}
        },

咱们能够形象为这样一个网络模型。

在这里,咱们能够看到 Docker0 相当于一个路由器的作用,任何一个容器启动默认都是 docker0 网络。

docker 默认会给容器调配一个可用 ip,并把它同 docke0 相连。应用到的就是 veth pair 技术。

3. 容器互联–Link

在网络模型图中能够看出,容器和容器之间不能间接连通。

后面咱们启动的两个 tomcat 对应的 hosts 如下:

[root@jiangnan tomcat1]# docker exec -it tomcat01 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.2  3ecb3204e2dc
root@3ecb3204e2dc:/usr/local/tomcat#
[root@jiangnan tomcat1]# 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  6c9a6a5d8eca
[root@jiangnan tomcat1]#

发现:他们的 hosts 中只有各自的 ip 地址。

然而在理论的工作中,容器应用的是虚构 ip,每次启动 ip 都会变动,思考一个场景,咱们编写一个微服务,数据库连贯地址原来是应用 ip 的,如果 ip 变动就不行了,那咱们能不能应用服务名拜访呢?咱们在启动一个 tomcat03,应用—link 绑定到 tomcat02 上。而后看它的 hosts 是什么样的。

[root@jiangnan tomcat1]# docker run -d -p 8083:8080 --name tomcat03 --link tomcat02 tomcat
db75c42f7f7f609218deb290d3e923e3c7da6bcf8c0b38cde27962fb2b9e9a54
[root@jiangnan tomcat1]# 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 e4060ea4ee28   # 发现 tomcat2 间接被写在这里
172.17.0.4  db75c42f7f7f
root@db75c42f7f7f:/usr/local/tomcat#

发现:应用了–link,岂但有了本人的 ip,而且还有了 tomcat02 的服务名。然而 tomcat02 中并没有 tomcat03 的,因为–link 是单向的。

这样就实现了容器和容器之间的连通。不须要通过 ip 地址连通,而是通过服务名就能够。

然而应用—link 的办法过期了,咱们个别应用自定义网络。

4. 自定义网络(举荐)

docker0 的特点:

  • 它是默认的
  • 域名拜访不通
  • –link 域名通了,然而删了又不行

docker 为咱们提供了三种网络模式

[root@jiangnan tomcat1]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4d3e75606593   bridge    bridge    local
8e92ee24e5f6   host      host      local
e85ffb1f2cc3   none      null      local
[root@jiangnan tomcat1]#

这其中默认应用的是 bridge,也就是咱们的 docker0 网卡。

在咱们启动容器的时候,实际上是如下命令

[root@jiangnan tomcat1]# docker run -d -P --name tomcat01 --net bridge tomcat

这个—net 是默认的,所以被省略了。

上面咱们自定义一个网络 mynet。

# 自定义创立的默认 default "bridge"
[root@jiangnan tomcat1]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
3136d64109c6f285bc69d3ee4be901524292d0e5ddd9e414d49197dfa6c19ba1
[root@jiangnan tomcat1]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4d3e75606593   bridge    bridge    local
8e92ee24e5f6   host      host      local
3136d64109c6   mynet     bridge    local   # 多了一个 mynet
e85ffb1f2cc3   none      null      local

[root@jiangnan tomcat1]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "3136d64109c6f285bc69d3ee4be901524292d0e5ddd9e414d49197dfa6c19ba1",
        "Created": "2022-02-27T14:15:44.676693958+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": {}}
]
[root@jiangnan tomcat1]#

查看网络

[root@jiangnan tomcat1]# docker inspect mynet
[
    {
        "Name": "mynet",
        "Id": "3136d64109c6f285bc69d3ee4be901524292d0e5ddd9e414d49197dfa6c19ba1",
        "Created": "2022-02-27T14:15:44.676693958+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": {"31f12c9332e8b4b6e66619dc988533f2863b80e71dbf490c8313694637814ca1": {"Name":"tomcat-net-02","EndpointID":"1c0e9dbffff295f2326bfd1e2847c0f1d9136ff00519101bb11d922e7da4f818","MacAddress":"02:42:c0:a8:00:03","IPv4Address":"192.168.0.3/16","IPv6Address":""},
            "675439c851dc29355c03f82bb163f9e5a326e230447d86d40d53ff08766cfd06": {
                "Name": "tomcat-net-01",
                "EndpointID": "2653da0a25d166f0d7222235e85d8231d9424e19949b6e6b7cfa1a3eddcc462b",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}}
]
[root@jiangnan tomcat1]#
# 咱们来测试 ping 容器名和 ip 试试,都能够 ping 通
[root@jiangnan ~]# 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.093 ms
[root@jiangnan ~]# 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.063 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.066 ms

发现:不必—link 也能够间接通过服务名 ping 通了。

5. 网络连通

docker0 和自定义网络必定不通,咱们应用自定义网络的益处就是网络隔离。然而在理论的工作中,比方咱们部署了 mysql 应用了一个网段。部署了 tomcat 应用了另一个网段,两个网段之间必定是不能互相连通的,然而 tomcat 和 mysql 又须要互相连通,咱们就要应用网络连通。原理图如下:

网络连通就是将一个容器和一个网段之间的连通。

比方我后面应用的默认 docker0 的 tomcat01,须要连贯到 mynet 网络。

# docker network connect 网络 容器
[root@jiangnan tomcat1]# docker network connect mynet tomcat01
[root@jiangnan tomcat1]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "3136d64109c6f285bc69d3ee4be901524292d0e5ddd9e414d49197dfa6c19ba1",
        "Created": "2022-02-27T14:15:44.676693958+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": {"2e709013935463c29caf28771bb49925fee4e02842459b339d7dd1ad5dedf9b7": {"Name":"tomcat-net-01","EndpointID":"9f3a46bad37ade7935e283715caa5699e9a7e22175b592f4a4792a37c351d969","MacAddress":"02:42:c0:a8:00:02","IPv4Address":"192.168.0.2/16","IPv6Address":""},
            "5c0c544f2507d9f5f456feceddbd853ebccc07cea8c39c8479693731e480bf55": {
                "Name": "tomcat01",
                "EndpointID": "d05abb2d31af4067c5a45f299ce7b4401b1fa81638a44b6c09f3de7f8f4221fe",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""},"d6066db5fdd0b508514107a896ed20b639eaa47dbd97a025ad0c52250766c8a4": {"Name":"tomcat-net-02","EndpointID":"3a5f6f2a07d900303382b290825c9f52640689c859608c741c7c7d81031e107e","MacAddress":"02:42:c0:a8:00:03","IPv4Address":"192.168.0.3/16","IPv6Address":""}
        },
        "Options": {},
        "Labels": {}}
]
[root@jiangnan tomcat1]#

通过这种形式间接将 tomcat01 加到了 mynet 网络中。

6. 总结

  • veth pair 是成对呈现的一种虚构网络设备接口,一端连着网络协议栈,一端彼此相连。
  • docker 中默认应用 docker0 网络。
  • docker0 相当于一个路由器的作用,任何一个容器启动默认都是 docker0 网络。
  • docker0 是容器和虚拟机之间通信的桥梁。
  • 举荐应用自定义网络,更好实现应用服务名的连通形式,防止 ip 扭转的难堪。
  • 网络之间不能间接连通,网络连通是将一个容器和一个网络之间的连通,实现跨网络操作。
退出移动版