Docker 网络详解(十一)

首页 / 🐋Docker / 正文

一、Docker 网络简介

1、网络模式

  Docker 基础网络类型一共有三种(bridge、host 和 none),还有两种由基础网络类型派生的网络类型(container 和 custom)。本文详细讲解这五种网络类型。

查看 docker 网络:

[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
994c4bd64f70   bridge    bridge    local
9eeb43076ad2   host      host      local
ad2da4225045   none      null      local

网络模式说明:

网络模式配置说明
host--network=host容器不会创建自己的网卡,配置 IP 等,而是使用宿主机的 IP 和端口
none--network=none容器关闭网络功能,不进行任何网路设置
bridge--network=bridge为每个容器分配 IP 。并将容器连接到 docker0 虚拟网桥上,这种模式是默认模式
container--network=container:NAME_or_ID容器不会创建自己的网卡和IP,而是和一个指定的容器共享 IP 和端口
custom--network=new_bridge为每个容器分配 IP 。并将容器连接到自定义的虚拟网桥上

2、组件原理

(1)网络命名空间(network namespace)

  Network Namespace 是 linux 内核提供的用于实现网络虚拟化的重要功能,是 Linux 内核用来隔离不同容器间的网络资源(每个 Docker 容器都拥有一个独立的网络命名空间),网络命名空间主要隔离的资源包括:

  • iptables规则表
  • 路由规则表
  • 网络设备列表

  网络空间结构如下图所示,当系统中拥有 2 个网络命名空间:

image-20220905132737725

  由于不同的网络命名空间之间是相互隔离的,所以不同的网络命名空间之间并不能直接通信。 就好比两台电脑,如果没有任何网线连接,它们之间是不能通信的。所以,Linux 内核提供了 虚拟网络设备对(veth) 这个功能,用于解决不同网络命名空间之间的通信。

(2)虚拟网络设备对(veth-pair)

  虚拟网络设备对(veth-pair)用于解决不同网络命名空间之间的通信,可以将其看成是两块有网线连接的网卡。只要将其中一块网卡放置到网络命名空间A,另外一块网卡放置到网络命名空间B,那么两个不同的网络命名空间就能够通信,如下图所示:

image-20220905133354142

  如上图所示,veth0 与 veth1 组成一个虚拟网络设备对。虚拟网络设备对就像管道一样,只要向其中一端发送数据,就可以从另外一端接收到数据。

Docker 就是使用 虚拟网络设备对 来实现不同容器之间的通信,其原理如下图:

image-20220905134216059

(3)docker0 网桥

  Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。

  Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。

查看 docker0 网桥:

[root@localhost ~]# ip a
...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:60:fc:72:3b 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:60ff:fefc:723b/64 scope link
       valid_lft forever preferred_lft forever
...

查看 docker0 详细:

[root@localhost ~]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "b2f23dec622af41e1976542bc1633f6c785f7a6ff4eeaaf2a779c761dba03941",
        "Created": "2022-09-04T22:15:41.831270638-04:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

查看连接到 docker0 的虚拟网络设备对(veth-pair):

[root@localhost ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.024260fc723b       no              veth1870812
                                                        veth1de92fe
                                                        veth5b85033
                                                        vethbfd4b66

  注意:每启动一个容器,就会生成一个 veth-pair 。

  如果没有 brctl 这个命令,可以通过以下命令进行安装:

yum install -y bridge-utils    

二、网络模式详细说明

1、Host 模式

  在 host 模式下,容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

  使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。

结构如下图所示:

image-20220902105014515

查看该网络模式配置:

[root@localhost ~]# docker network inspect host
[
    {
        "Name": "host",
        "Id": "9eeb43076ad21e4891954ab2f6682213adaa52c64f3c3668ad8fa8d4493785e4",
        "Created": "2022-06-19T23:25:06.060598453-04:00",
        "Scope": "local",
        "Driver": "host",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

2、None 模式

  使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过–network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

结构如下图所示:

image-20220902153414430

查看该网络模式配置:

[root@localhost ~]# docker network inspect none
[
    {
        "Name": "none",
        "Id": "ad2da4225045337a2192fc016ca7d7fc984a82a1452221e19e07d9a5dce0cb71",
        "Created": "2022-06-19T23:25:05.946788343-04:00",
        "Scope": "local",
        "Driver": "null",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

3、Bridge 模式

  Bridge 模式是 docker 的默认网络模式,不写 --network 参数,就是 bridge 网桥模式。

  当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚拟网桥,此主机上启动的Docker容器默认都会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

从 docker0子网中分配一个IP给容器使用,并设置 docker0 的IP地址为容器的默认网关。在主机上创建一对虚拟网卡 veth pair 设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以 vethxxx 这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过 brctl show 命令查看。

结构如下图所示:

docker_bridge

查看该网络模式配置:

[root@localhost ~]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "44529eeb55f59f1af6d75c7d54fab3a5283b0e021ee91b7a1163c710d5dbc573",
        "Created": "2022-09-05T04:34:26.929819942-04:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

4、Container 模式

  Container 模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

结构如下图所示:

image-20220902152236371

  在以上示例中,Docker 2 容器可以通过--network=container:Docker 1 参数,指定自己的网络和一个容器 Docker 1 共享 IP 和端口。

示例:

docker run -it --name docker2 --network=container:docker1  nginx:latest /bin/bash

5、Custom 模式

  Custom 模式用于自定义 docker 网络。

结构如下图所示:

image-20220902153137551

  如上图所示,新建自定义网桥 custom ,指定网络(192.168.10.0/24)和网关(192.168.10.1)。

# 新建自定义网络
docker network create --driver bridge --subnet 192.168.10.0/24 --gateway 192.168.10.1 Custom

# 查看自定义网络,查看定义网络
docker network ls

NETWORK ID     NAME      DRIVER    SCOPE
994c4bd64f70   bridge    bridge    local
9eeb43076ad2   host      host      local
24cd1b0769bd   Custom    bridge    local
ad2da4225045   none      null      local

# 查看自定义网桥 IP 地址
[root@localhost ~]# ip addr

316: br-24cd1b0769bd: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:cb:b3:6c:a3 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.1/24 brd 192.168.10.255 scope global br-24cd1b0769bd
       valid_lft forever preferred_lft forever

三、自定义网络实战 - 网络联通

  在没有使用 connect 命令的情况下,不同网络间的容器是无法进行网络连接的。

  如下图所示:container1 和 container2,使用不同的网络,所以无法联通。

image-20220906110732392

1、验证不同网络无法联通性

(1)创建容器 container1

# 创建容器
docker run -it --name container1 centosjava:latest /bin/bash

# 查看容器 IP
[root@41eea42d9980 /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.8  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:08  txqueuelen 0  (Ethernet)
        RX packets 8  bytes 656 (656.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
...

(2)创建容器 container2

# 创建容器
docker run -it --name container2 --network Custom centosjava:latest /bin/bash

# 查看容器 IP
[root@7279af38152a /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.10.2  netmask 255.255.255.0  broadcast 192.168.10.255
        ether 02:42:c0:a8:0a:02  txqueuelen 0  (Ethernet)
        RX packets 12  bytes 1032 (1.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
...

(3)两台容器之间互相 ping 测试

# 容器 container1 ping container2 ,不通
[root@41eea42d9980 /]# ping 192.168.10.2
PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data.

# 容器 container2 ping container1 ,不通
[root@7279af38152a /]# ping 172.17.0.8
PING 172.17.0.8 (172.17.0.8) 56(84) bytes of data.

2、不同网络之间网络联通

(1)将容器 container1 和容器 container2 分别添加到对方所在的网络中

docker network connect Custom container1
docker network connect bridge container2

(2)再次检查两台容器之间网络联通性

# 容器 container1 ping container2 ,通
[root@41eea42d9980 /]# ping 192.168.10.2
PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data.
64 bytes from 192.168.10.2: icmp_seq=123 ttl=64 time=0.087 ms
64 bytes from 192.168.10.2: icmp_seq=124 ttl=64 time=0.085 ms


# 容器 container2 ping container1 ,通
[root@7279af38152a /]# ping 172.17.0.8
PING 172.17.0.8 (172.17.0.8) 56(84) bytes of data.
64 bytes from 172.17.0.8: icmp_seq=229 ttl=64 time=0.090 ms
64 bytes from 172.17.0.8: icmp_seq=230 ttl=64 time=0.077 ms

通过以上实战说明,docker 不同网络之间互联需要使用 connect 命令进行网络发布!!!

打赏
文章目录