Docker网络——实现容器间通信、容器与外网通信以及容器的跨主机访问

前言

自定义网络

建议使用自定义的网桥来控制哪些容器可以相互通信,还可以自动DNS解析容器名称到IP地址。Docker提供了创建这些网络的默认网络驱动程序,你可以创建一个新的Bridge网络,Overlay或Macvlan网络。你还可以创建一个网络插件或远程网络进行完整的自定义和控制。

你可以根据需要创建任意数量的网络,并且可以在任何给定时间将容器连接到这些网络中的零个或多个网络。此外,您可以连接并断开网络中的运行容器,而无需重新启动容器。当容器连接到多个网络时,其外部连接通过第一个非内部网络以词法顺序提供。

一、容器间通信

1.创建一个bridge模式的网络

[root@server1 ~]# docker network create --driver bridge my_net1

在这里插入图片描述
由上图我们可以看到创建的网络ID为88cd89998134,使用ip addr查看本机网络:
在这里插入图片描述
查看docker自定义网络如下图,当我们创建好自定义网络后,自定为起分配IP网段和网关

docker network inspect my_net1 

在这里插入图片描述

docker的bridge自定义网络之间默认是有域名解析的;
docker的bridge自定义网络与系统自带的网桥之间默认是有解析的;
但是docker的系统自带的网桥之间默认是没有解析的。

2.再创建一个bridge的网络,自定义ip和网关

[root@server1 ~]# docker network create --driver bridge --subnet 172.20.0.0/24 --gateway 172.20.0.1 my_net2
f81bcce7691795311aadeb0815295c9ef5ac240b86bcc1317777734cfc83319a
[root@server1 ~]# 
[root@server1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
bc0331260bb7        bridge              bridge              local
2da931af3f0b        host                host                local
88cd89998134        my_net1             bridge              local
f81bcce76917        my_net2             bridge              local
63d31338bcd9        none                null                local
[root@server1 ~]# 
[root@server1 ~]# docker network inspect my_net2

        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.20.0.0/24",
                    "Gateway": "172.20.0.1"
                }
            ]
        },

[root@server1 ~]# ip a
9: br-f81bcce76917: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    link/ether 02:42:03:a3:1c:fb brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.1/24 brd 172.20.0.255 scope global br-f81bcce76917
       valid_lft forever preferred_lft forever

3.使用刚刚创建的网络建立容器

[root@server1 ~]# docker load -i ubuntu.tar 

[root@server1 ~]# docker run -it --name vm1 --network=my_net1 ubuntu
root@b9186e3ba2e6:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
root@b9186e3ba2e6:/# 

在这里插入图片描述

4.另开一个shell,再创建一个容器,使用网络my_net2

##使用–ip参数可以指定容器ip地址,但必须是在自定义网桥上(自定义的ip地址和网关地址),
默认的bridge模式不支持,同一网桥上的容器是可以通信的

[root@server1 ~]# docker run -it --name vm2 --network=my_net2  --ip=172.20.0.10 ubuntu
root@2a692ae111da:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:14:00:0a brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.10/24 brd 172.20.0.255 scope global eth0
       valid_lft forever preferred_lft forever

在这里插入图片描述

5.建立两个容器之间的连接

##连接两个网络
[root@server1 ~]# docker network connect my_net1 vm2						
[root@server1 ~]# 

##进入容器vm2
[root@server1 ~]# docker attach vm2
root@2a692ae111da:/# 

##查看网络
root@2a692ae111da:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:14:00:0a brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.10/24 brd 172.20.0.255 scope global eth0
       valid_lft forever preferred_lft forever

##容器内自动生成新的网卡,并添加与vm1网段相同的IP
16: eth1@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth1
       valid_lft forever preferred_lft forever

在这里插入图片描述

测试:两个容器是否可以直接ping通

在容器vm2内(IP=172.20.0.10)ping vm1(IP=172.18.0.2)

root@2a692ae111da:/# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.068 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.068 ms
64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.035 ms
^C
--- 172.18.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.035/0.057/0.068/0.015 ms

在这里插入图片描述

以上我们实现了:使用自定义网络实现容器间的通信

注意:

docker的bridge自定义网络之间:双方可以随便添加对方的网卡
docker的bridge自定义网络与系统自带的网桥之间:只能是,系统自带的网桥对应的容器 添加 bridge自定义网络对应的容器的网卡。而反过来会报错。
但是docker的系统自带的网桥之间:是可以通信的,因为是在一个网络桥接上。
docker 1.10开始,内嵌了一个DNS server。dns解析功能必须在自定义网络中使用。

二、容器与外网通信

容器如何访问外网是通过iptables的SNAT实现的?
在这里插入图片描述

外网如何访问容器

  • 端口映射,-p指定对应端口

外网访问容器用到了docker-proxy和iptables DNAT
宿主机访问本机容器使用的是iptables DNAT
外部主机访问容器或容器之间的访问是docker-proxy实现

在这里插入图片描述

示例:

  • 查看当前iptable的nat表火墙策略
    在这里插入图片描述
  • 创建nginx的容器,配置端口映射
    在这里插入图片描述
    在这里插入图片描述
    我们可以在nat表的最后一行看到使用了端口转发

三、Docker的跨主机网络访问

1.跨主机网络解决方案

  • docker原生的overlay和macvlan

  • 第三方的flannel、weave、calico

2.众多网络方案是如何与docker集成在一起的?

libnetwork docker容器网络库
CNM (Container Network Model)这个模型对容器网络进行了抽象

3.CNM三类组件

组件 功能
Sandbox 容器网络栈,包含容器接口、dns、路由表。(namespace)
Endpoint 作用是将sandbox接入network (veth pair)
Network 包含一组endpoint,同一network的endpoint可以通信。

在这里插入图片描述


4.macvlan网络方案的实现

Macvlan是一个新的尝试,是真正的网络虚拟化技术的转折点。Linux实现非常轻量级,因为与传统的Linux Bridge隔离相比,它们只是简单地与一个Linux以太网接口或子接口相关联,以实现网络之间的分离和与物理网络的连接。

Macvlan提供了许多独特的功能,并有充足的空间进一步创新与各种模式。这些方法的两个高级优点是绕过Linux网桥的正面性能以及移动部件少的简单性。删除传统上驻留在Docker主机NIC和容器接口之间的网桥留下了一个非常简单的设置,包括容器接口,直接连接到Docker主机接口。由于在这些情况下没有端口映射,因此可以轻松访问外部服务。

实验准备:

(1)两台虚拟机
(2)两台虚拟机上添加两块虚拟网卡,并安装好相应的docker服务(因为我们模拟的时docker容器的跨主机访问)

在这里插入图片描述
在这里插入图片描述
1.server1:修改网卡eth1配置文件

[root@server1 network-scripts]# cp ifcfg-ens3 ifcfg-eth1
[root@server1 network-scripts]# vim ifcfg-eth1 
[root@server1 network-scripts]# cat ifcfg-eth1 
BOOTPROTO=none
DEVICE=eth1
ONBOOT=yes
[root@server1 network-scripts]# pwd
/etc/sysconfig/network-scripts
[root@server1 network-scripts]# 
[root@server1 network-scripts]# systemctl restart network
[root@server1 network-scripts]# ifup eth1					##开启网卡

2.server2:修改网卡eth2配置文件

[root@server2 ~]# cd /etc/sysconfig/network-scripts/
[root@server2 network-scripts]# cat ifcfg-eth1
BOOTPROTO=none
DEVICE=eth1
ONBOOT=yes
[root@server2 network-scripts]# ifup eth1
[root@server2 network-scripts]# 

在这里插入图片描述

macvlan本身是linxu kernel的模块,本质上是一种网卡虚拟化技术。其功能是允许在同一个物理网卡上虚拟出多个网卡,通过不同的MAC地址在数据链路层进行网络数据的转发,一块网卡上配置多个 MAC 地址(即多个 interface),每个interface可以配置自己的IP,Docker的macvlan网络实际上就是使用了Linux提供的macvlan驱 动。

因为多个MAC地址的网络数据包都是从同一块网卡上传输,所以需要打开网卡的混杂模式ip link set eth1 promisc on。

3.打开server1和server2的eth1网卡的混杂模式

只要我们可以看到PROMISC,则表示成功

[root@server1 ~]# ip link set eth1 promisc on
[root@server1 ~]# ip addr show | grep eth1
3: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000

[root@server2 ~]# ip link set eth1 promisc on
[root@server2 ~]# ip addr show | grep eth1
3: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000

在这里插入图片描述
在这里插入图片描述

注意:如果不开启混杂模式,会导致macvlan网络无法访问外界,具体在不使用vlan时,表现为无法ping通路由,无法ping通同一网络内其他主机。

4.在两台主机上各创建macvlan网络

创建macvlan网络不同于桥接模式,需要指定网段和网关(因为要保证跨主机上网段和网关是相同的),并且都得是真实存在的

server1:

root@server1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
9d480647ec64        bridge              bridge              local
2da931af3f0b        host                host                local
88cd89998134        my_net1             bridge              local
f81bcce76917        my_net2             bridge              local
63d31338bcd9        none                null                local
[root@server1 ~]# docker network rm my_net1
my_net1
[root@server1 ~]# docker network rm my_net2
my_net2
[root@server1 ~]# docker network create -d macvlan --subnet=172.22.0.0/24 --gateway=172.22.0.1 -o parent=eth1 macvlan1
da5a56f05fbbddf4eefea78673e4a4812435280249847229a9e9da6d7f656f9a
[root@server1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
9d480647ec64        bridge              bridge              local
2da931af3f0b        host                host                local
da5a56f05fbb        macvlan1            macvlan             local
63d31338bcd9        none                null                local
[root@server1 ~]# 

在这里插入图片描述
server2:

[root@server2 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5f028f69c850        bridge              bridge              local
99ce8bdb850d        host                host                local
47f283b1256e        none                null                local
[root@server2 ~]# 
[root@server2 ~]# docker network create -d macvlan --subnet=172.22.0.0/24 --gateway=172.22.0.1 -o parent=eth1 macvlan1
15ca8ed5e089e3cf8b46a9e0bb5224f29b705f4149ed086dc4848a68e9b86f29
[root@server2 ~]# 
[root@server2 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5f028f69c850        bridge              bridge              local
99ce8bdb850d        host                host                local
15ca8ed5e089        macvlan1            macvlan             local
47f283b1256e        none                null                local

在这里插入图片描述

macvlan会独占主机网卡,但可以使用vlan子接口实现多macvlan网络

vlan可以将物理二层网络划分为4094个逻辑网络,彼此隔离,vlan id取值为1~4094

5.在两台主机上分别使用创建的macvlan1运行一个容器

server1:

[root@server1 ~]# docker run -it --name vm1 --network=macvlan1 --ip=172.22.0.10 ubuntu
WARNING: IPv4 forwarding is disabled. Networking will not work.
root@38222ed87ea5:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
7: eth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 02:42:ac:16:00:0a brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.10/24 brd 172.22.0.255 scope global eth0
       valid_lft forever preferred_lft forever
root@38222ed87ea5:/# 

server2:

[root@server2 ~]# docker run -it --name vm2 --network=macvlan1 --ip=172.22.0.20 ubuntu
WARNING: IPv4 forwarding is disabled. Networking will not work.
root@22510f08f0ea:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
5: eth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 02:42:ac:16:00:14 brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.20/24 brd 172.22.0.255 scope global eth0
       valid_lft forever preferred_lft forever
root@22510f08f0ea:/# 

访问测试:sever1容器vm1中ping server2的vm2容器

root@38222ed87ea5:/# ping 172.22.0.10
PING 172.22.0.10 (172.22.0.10) 56(84) bytes of data.
64 bytes from 172.22.0.10: icmp_seq=1 ttl=64 time=0.023 ms
64 bytes from 172.22.0.10: icmp_seq=2 ttl=64 time=0.023 ms
64 bytes from 172.22.0.10: icmp_seq=3 ttl=64 time=0.024 ms
^C
--- 172.22.0.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.023/0.023/0.024/0.004 ms
root@38222ed87ea5:/# 

macvlan模式不依赖网桥,所以brctl show查看并没有创建新的bridge,但是查看容器的网络,会看到虚拟网卡对应了一个interface是3。

在这里插入图片描述
查看宿主机的网络,3正是虚机的eth1网卡

在这里插入图片描述

可见,容器的 eth0 就是宿主机的eth0通过macvlan虚拟出来的interface。容器的interface直接与主机的网卡连接,这种方案使得容器无需通过NAT和端口映射就能与外网直接通信(只要有网关),在网络上看起来与其他独立主机没有区别。


四、macvlan会独占主机的网卡的解决方案

前面说过macvlan会独占主机网卡,但可以使用vlan子接口实现多macvlan网络
vlan可以将物理二层网络划分为4094个逻辑网络,彼此隔离,vlan id取值为1~4094
我们只需要在创建容器时使用vlan子接口就可以i解决:

server1:

##使用前面建好的macvlan1
[root@server1 ~]# docker run -it --name vm3 --network=macvlan1 --ip=172.22.0.30 ubuntu			
WARNING: IPv4 forwarding is disabled. Networking will not work.
root@67fc78b9d861:/# 
root@67fc78b9d861:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
8: eth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 02:42:ac:16:00:1e brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.30/24 brd 172.22.0.255 scope global eth0
       valid_lft forever preferred_lft forever
root@67fc78b9d861:/# 

在这里插入图片描述

测试是否能ping通server2上的vm2容器
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/meltsnow/article/details/94548066