自定义网络实现跨主机 Docker 通信

Posted

tags:

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

参考技术A 宿主机 ip:eth0 192.168.83.83

容器分配网段:172.172.0.0/24

启动容器指定 ip:172.172.0.10

宿主机 ip:eth0 192.168.83.85

容器分配网段:172.172.1.0/24

启动容器指定 ip:172.172.1.10

创建自定义网络之前,主机环境:

创建自定义网络,指定网桥名称为 docker-br0,当然也可以取其他的名字,指定网桥的网段为 172.172.0.0/24:

创建网络后,查看当前主机的网络环境,环境中多出了名称为 br-760119ea5907 的网卡,且 docker 网络出现刚创建的名称为 docker-br0 的网络:

创建容器,并使用自定义的网络,指定容器内的 ip 地址为 172.172.0.10,查看容器内的网络环境,ip 配置为设定值:

在容器内 ping 当前宿主机的网络地址,显示可以 ping 通:

创建自定义网络之前,主机环境:

创建自定义网络,指定网桥名称为 docker-br0,当然也可以取其他的名字,指定网桥的网段为 172.172.1.0/24:

创建网络后,查看当前主机的网络环境,环境中多出了名称为 br-563243e33ad9 的网卡,且 docker 网络出现刚创建的名称为 docker-br0 的网络:

创建容器,并使用自定义的网络,指定容器内的 ip 地址为 172.172.1.10,查看容器内的网络环境,ip 配置为设定值:

在容器内 ping 当前宿主机的网络地址,显示可以 ping 通:

在主控宿主机上的容器与线卡宿主机上的容器之间互相不能 ping 通:

添加路由规则,在主控宿主机上,设定路由 172.172.1.0/24 网络,经过线卡(192.168.83.85)上的 eth0 物理网桥:

在线卡宿主机上,设定路由 172.172.0.0/24 网络,经过主控(192.168.83.83)上的 eth0 物理网桥:

在主控宿主机上的容器与线卡宿主机上的容器之间互相能够 ping 通:

运维实战 容器部分 Docker网络

原生网络模式

Docker安装后会自动创建3种网络: Bridge. Host, None, Docker安装时会创建一个名为docker0Linux bridge, 新建的容器会自动桥接到这个接口.

docker0作为所有容器的网关,默认IP为172.17.0.1,新创建的容器分配的IP默认单调递增,因此如果不加以设置每次开启容器时的IP都可能出现变化.

##安装用于查看信息的软件包
yum install bridge-utils.x86_64

##查看网桥初始状态
[root@Server1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02424bfd7ed8	no

##创建容器后可以观察到有接口接在了网桥上
[root@Server1 ~]# docker run -d --name Nginx nginx:latest 
c980d6466da5a6f21c247099abec01aa2f4b333f21b0714ada8838b99d9a994c
[root@Server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
c980d6466da5        nginx:latest        "/docker-entrypoint.…"   4 seconds ago       Up 3 seconds        80/tcp              Nginx
[root@Server1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02424bfd7ed8	no		veth50c8b1c

##新的容器也会依次接入
[root@Server1 ~]# docker run -d --name Nginx2 nginx:latest 
97c176c978040853067c5268897319c4f49fc30884499bc757084671bb79d689
[root@Server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
97c176c97804        nginx:latest        "/docker-entrypoint.…"   3 seconds ago       Up 1 second         80/tcp              Nginx2
c980d6466da5        nginx:latest        "/docker-entrypoint.…"   49 seconds ago      Up 48 seconds       80/tcp              Nginx
[root@Server1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02424bfd7ed8	no		veth50c8b1c
										veth90063b4

关闭容器, 则桥接自动关闭

Bridge模式下容器没有一个公有IP, 只有宿主机可以直接访问, 外部主机是不可见的. 容器通过宿主机的NAT规则后可以访问外网.

Host模式

Host模式可以让容器共享宿主机网络栈, 这样的好处是外部主机与容器直接通信, 但是容器的网络缺少隔离性.

Host网络模式需要在容器创建时指定--network

##可以看到采用Host模式创建的容器并没有直接挂接在docker0上
[root@Server1 ~]# docker run -d --name Nginx --network host nginx:latest 
f60c42e66598f7a8557f11e42e2876c12cb957dc6bd4bcca92c693e7a28707e6
[root@Server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
f60c42e66598        nginx:latest        "/docker-entrypoint.…"   5 seconds ago       Up 4 seconds                            Nginx
[root@Server1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02424bfd7ed8	no		
[root@Server1 ~]# 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 pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:9b:66:f1 brd ff:ff:ff:ff:ff:ff
    inet 172.25.5.1/24 brd 172.25.5.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe9b:66f1/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:4b:fd:7e:d8 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:4bff:fefd:7ed8/64 scope link 
       valid_lft forever preferred_lft forever

None模式

None模式是指禁用网络功能, 只有lo接口,在容器创建时使用--network=none进行指定

[root@Server1 ~]# docker run -d --name Nginx --network none nginx:latest 
d13f5ba0fc1a10a3c325e6f000c0c8ab28ee150caec8ba26099ba53327be62a9
[root@Server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
d13f5ba0fc1a        nginx:latest        "/docker-entrypoint.…"   4 seconds ago       Up 3 seconds                            Nginx
[root@Server1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02424bfd7ed8	no	

查看容器内部网络情况

##Host模式
[root@Server1 ~]# docker run -it --name Centos --network host centos:latest 
[root@Server1 /]# 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 pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:9b:66:f1 brd ff:ff:ff:ff:ff:ff
    inet 172.25.5.1/24 brd 172.25.5.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe9b:66f1/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:4b:fd:7e:d8 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:4bff:fefd:7ed8/64 scope link 
       valid_lft forever preferred_lft forever
[root@Server1 /]# hostname
Server1

##None模式
[root@Server1 ~]# docker run -it --name Centos --network none centos:latest 
[root@80228b8f69f6 /]# 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

Docker自定义网络

自定义网络模式中, Docker提供了三种自定义网络驱动: bridge, overlaymacvlan

bridge驱动类似默认的bridge网络模式, 但增加了一些新的功能;

overlaymacvlan是用于创建跨主机网络.

建议使用自定义的网络来控制哪些容器可以相互通信, 还可以自动DNS解析容器名称到IP地址.

创建自定义网桥

#没有指定,默认为桥接docker
[root@Server1 ~]# docker network create MyNet1
f7778a9243a9115df2232bce7f51b7f2e0cad255dde85f2e62aab3c7d353345a
[root@Server1 ~]# docker network ls
NETWORK ID          NAME                DRIVER           
SCOPEf7778a9243a9        MyNet1              bridge              
localaa1073e86d69        bridge              bridge              
local2c8ef7f4a10e        host                host                
local48d010d8c011        none                null                local
  • 指定容器运行在该网络中
docker run -it --name Node1 --network MyNet1 busybox

ip addr    	#可以看到ip呈单调递增趋势
ctrl+p+q	#将运行的容器打入后台, 不要关闭, 如果关闭, 分配的ip会被回收

docker run -it --name Node2 --network MyNet1 busybox
ip addr 

##可以ping通同一网络中的容器
ping Node1
##自带DNS解析功能
cat /etc/hosts

自定义网段及网关

  • 删除之前测试用的容器, 创建新的网络源MyNet2
[root@Server1 ~]# docker network create --subnet 172.20.0.0/24 --gateway 172.20.0.1 MyNet2
2c8c1dc7fcbc9e4848103248ce074af88ee9a3fc0f37ed507780288b699a99fd

[root@Server1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              
SCOPEf7778a9243a9        MyNet1              bridge              
local2c8c1dc7fcbc        MyNet2              bridge              
localaa1073e86d69        bridge              bridge              
local2c8ef7f4a10e        host                host                
local48d010d8c011        none                null                local

[root@Server1 ~]# docker network inspect MyNet2
[    
{	"Name": "MyNet2",
	"Id": "2c8c1dc7fcbc9e4848103248ce074af88ee9a3fc0f37ed507780288b699a99fd",
	"Created": "2021-04-28T13:51:37.120782352+08:00",
	"Scope": "local", 
	"Driver": "bridge",
	"EnableIPv6": false,
	"IPAM": {
				"Driver": "default",
				"Options": {},
				"Config": [
				{
					"Subnet": "172.20.0.0/24",
					"Gateway": "172.20.0.1"
				}
				]
			},
	"Internal": false,
	"Attachable": false,
	"Ingress": false,
	"ConfigFrom": {
					"Network": "" 
				},
	"ConfigOnly": false,
	"Containers": {},
	"Options": {},
	"Labels": {}
	}]
  • 运行容器并指定IP
docker run -it --name Node1 --network MyNet2 --ip 172.20.0.10 ubuntu
ip addr
ctrl+p+q将该容器进程打入后台,注意不能直接关闭

docker run -it --name Node2 --network MyNet2 --ip 172.20.0.11 ubuntu

使用--ip参数可以指定容器IP地址, 但必须是在自定义网桥上, 默认的bridge模式不支持.

同一网桥上的容器是可以互通的.

  • 不同网桥的容器通信

MyNet1中运行新容器, 由于MyNet1没有使用自定义模式, 不需要指定IP

docker run -it --name Node3 --network MyNet1 ubuntu
docker run -it --name Node4 --network MyNet1 ubuntu

MyNet1中的Node3Node4属于同一网络, 互相可以联通.

但与Node1Node2不在同一网络中, 互相不能联通.

  • 不同网络MyNet1MyNet2实现通信
##为Node1添加一块MyNet1的网卡
docker network connect MyNet1 Node1
##进入容器
docker container attach vm1
ip addr
##可以连通Node3和Node4了

Docker容器通信

容器之间除了使用IP通信外, 还可以使用容器名称通信, Docker 1.10开始, 内嵌了一个DNS server, dns解析功能必须在自定义网络中使用, 启动容器时使用 --name 参数指定容器名称.

Joined容器方式通信

docker run -it --name Node1 --network MyNet1 ubuntu
docker run -it --name Node2 --network container:Node1 ubuntu

处于这个模式下的Docker容器会共享一个网络栈, 这样两个容器之间可以使用localhost高效快速通信.

Link链接方式通信

--link可以用来链接2个容器

docker run -it --name Node1 ubuntu
docker run -it --name Node2 --link Node1:web ubuntu

##都可以ping通,上面设置了Node1的别名为web
ping vm1
ping web
##可以看到自动设置了解析
cat /etc/hosts

外网如何访问容器

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

docker-proxyDNAT实现了双冗余, 只要其中一个存在都可以实现从外网访问容器

image-20210503024021423

跨主机容器网络

跨主机网络解决方案

  • Docker原生的overlaymacvlan
  • 第三方的flannel, weave, calico

众多网络方案是如何与Docker集成在一起的

  • 采用libnetwork 这一Docker容器网络库

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

CNM分三类组件

  • Sandbox: 容器网络栈,包含容器接口, DNS, 路由表
  • Endpoint: 作用是将Sandbox接入Network
  • Network: 包含一组endpoint,同一Networkendpoint可以通信

image-20210503024353140

Macvlan网络方案实现

特点

  • Linux kernel提供的一种网卡虚拟化技术.
  • 无需Linux bridge, 直接使用物理接口, 性能极好.
  • 无需NAT和端口映射
  • 会独占主机网卡 但可以通过子接口进行设置

操作流程

  • 首先在实验用虚拟机上增加新的一块网卡
  • 打开网卡混杂模式
[root@Server2 docker]# ip link set eth1 promisc on
[root@Server2 docker]# ip addr show
[root@Server2 docker]# ip link set up eth1
[root@Server2 docker]# ip addr show
[root@Server2 docker]# docker network create -d macvlan --subnet 10.0.0.00/24 --gateway 10.0.0.1 -o parent=eth1 MacVlan
[root@Server2 docker]# docker network ls
NETWORK ID          NAME                DRIVER              
SCOPE42c1b23d732f        MacVlan1            macvlan             
locala1fc6d2b4881        bridge              bridge              
locala8e736a43b65        host                host                
local1cea84391117        none                null
local
[root@Server2 docker]# docker run -it --name Node1 --network MacVlan1 --ip 10.0.0.10 busybox:latest
/ #

##在Server1进行同样的操作后进行联通测试
/ # ping 10.0.0.10PING 10.0.0.10 (10.0.0.10): 
56 data bytes64 bytes from 10.0.0.10: seq=0 ttl=64 time=0.611 ms
64 bytes from 10.0.0.10: seq=1 ttl=64 time=1.349 ms
64 bytes from 10.0.0.10: seq=2 ttl=64 time=1.278 ms
64 bytes from 10.0.0.10: seq=3 ttl=64 time=1.131 ms

--- 10.0.0.10 ping statistics ---4 packets transmitted, 4 packets received, 0% packet lossround-trip min/avg/max = 0.611/1.092/1.349 ms

可以看出, macvlan方式确实做到了外部主机相互连接

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

vlan可以将物理二层网络划分为4094个逻辑网络并彼此隔离.

因此vlan id的取值为1-4094

[root@Server1 docker]# docker network create -d macvlan --subnet 20.0.0.00/24 --gateway 20.0.0.1 -o parent=eth1.1 MacVlan
2831f365c16bf92878c1bd31caba449e230ae0149be66e7f9915e3b0dd854c7cd
[root@Server1 docker]# docker run -it --name Node2 --network MacVlan2 --ip 20.0.0.11 busybox:latest

Macvlan网络间的隔离和连通

  • macvlan网络在二层上是隔离的,所以不同macvlan网络的容器时不能相互通信的
  • 可以在三层上通过网关将macvlan连通起来
  • Docker本身不做任何限制,像传统vlan网络那样管理即可

以上是关于自定义网络实现跨主机 Docker 通信的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Calico实现跨主机Docker网络通信

Docker容器跨主机多网段通信解决方案

Docker实践 -- 使用Open vSwitch实现跨主机通信

精讲docker跨主机通信

docker实现跨主机通信(使用静态路由方式)

Docker 容器跨主机多网段通信解决方案