目录

  • 一.Docker网络
  • 1.桥接网络
  • 2.host网络模式
  • 3.none模式
  • 二.自定义网络
  • 1.创建自定义网桥
  • 2.自定义网段
  • 3.手动指定ip
  • 4.双网卡来实现不同网段间通信
  • 三.Docker容器通信
  • 1.内部访问外部
  • 2.外部访问内部
  • 3.原理
  • 四.创建macvlan网络
  • 1.使用eth0网卡来通信
  • 测试
  • 2.使用eth1网卡来通信
  • 实现不同网段的通信
  • 结论


我们需要将前面的docker-compose仓库停掉

[root@server1 harbor]# docker-compose stop

不同主机内docker容器网络互通 docker不同网段通信_docker

一.Docker网络

docker的镜像是令人称道的地方,但网络功能还是相对薄弱的部分。
docker安装后会自动创建3种网络:bridge、host、none

1.桥接网络

安装桥接网络

ip addr show  docker0
 yum install bridge-utils -y

不同主机内docker容器网络互通 docker不同网段通信_nginx_02

[root@server1 ~]# brctl show

不同主机内docker容器网络互通 docker不同网段通信_docker_03


运行一个容器查看桥接

root@server1 ~]# docker run -d --name demo nginx
[root@server1 ~]# brctl show

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_04

当我们删除掉容器之后,桥接又消失了!

docker rm -f demo
brctl show

不同主机内docker容器网络互通 docker不同网段通信_linux_05

2.host网络模式

需要我们指定network host

我们可以看到我们的桥接口上没有出现新的桥接口

[root@server1 ~]# docker run -d --name demo --network host nginx
[root@server1 ~]# brctl show
[root@server1 ~]# brctl show docker0

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_06

我们查看端口,可以发现docker运行的镜像nginx占用的是80端口!

[root@server1 ~]# netstat -antlp

不同主机内docker容器网络互通 docker不同网段通信_docker_07


这个时候,我们再运行一个容器起名为demo2,注意观察,启动之后,查看进程有两个进程demo,demo2。但是很快在查看进程,demo2消失了!

再也不会出现。

为什么?

因为加上参数–network host会占用虚拟机的80端口,所以刚开始尝试启动会看到进程,但是会被demo的80端口挤掉demo2!!

[root@server1 ~]# docker run -d --name demo2 --network host nginx
[root@server1 ~]# docker ps

不同主机内docker容器网络互通 docker不同网段通信_docker_08


我们查看日志就知道:

docker logs

不同主机内docker容器网络互通 docker不同网段通信_docker_09

3.none模式

none模式是指禁用网络功能,只有lo接口,在容器创建时使用!
先删除掉刚才创建的容器,重新运行容器:

[root@server1 ~]# docker rm -f demo   
[root@server1 ~]# docker rm -f demo2
[root@server1 ~]# netstat -antlp ##80端口随之消失!
[root@server1 ~]# docker run -it --rm --network=none busybox
/ # ip addr

不同主机内docker容器网络互通 docker不同网段通信_iptables_10

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_11

我们发现ip addr的时候:只有lo接口

不同主机内docker容器网络互通 docker不同网段通信_nginx_12

二.自定义网络

1.创建自定义网桥

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

创建网桥!!查看类型为brodge!!

[root@server1 ~]# docker network create mynet1
[root@server1 ~]#docker network ls

不同主机内docker容器网络互通 docker不同网段通信_iptables_13


测试:

这时我们发现我们是可以ping demo可以直接成功,说明这模式是可以给提供解析的

[root@server1 ~]# docker run -d --name demo1 --network mynet1 nginx 
[root@server1 ~]# docker run -it --rm --network mynet1 busybox
/ # ip addr
/ # ping demo

不同主机内docker容器网络互通 docker不同网段通信_nginx_14

不同主机内docker容器网络互通 docker不同网段通信_iptables_15

不同主机内docker容器网络互通 docker不同网段通信_iptables_16

注意:
我们再开一个nginx,停掉所有的demo,再次开启时,顺序反一下,查看ip变化

[root@server1 ~]# docker run -d --name demo2 --network mynet1 nginx
[root@server1 ~]# docker stop demo1
[root@server1 ~]# docker stop demo2
[root@server1 ~]# docker start demo2
[root@server1 ~]# docker start demo1
[root@server1 ~]# docker inspect  demo2
[root@server1 ~]# docker inspect  demo1
[root@server1 ~]# docker ps

[root@server1 ~]# docker attach 8095eebc598a            ##进入busybox查看
/ # ping demo2
PING demo2 (172.17.0.2):
/ # ping demo
PING demo1 (172.17.0.4):

不同主机内docker容器网络互通 docker不同网段通信_linux_17

我们会发现之前的demo1是172.17.0.2,demo2是172.17.0.4,
现在IP地址反过来了! 为什么?
这说明:系统会自动分配ip,按照启动顺序ip单调递增,但是ping名称的时候会自动解析地址!

2.自定义网段

创建时指定参数:–subnet 、–gateway

[root@server1 ~]# docker network rm mynet1    ##定义的网络删掉
[root@server1 ~]# docker network create --subnet 172.20.0.0/24 --gateway 172.20.0.1 mynet1

不同主机内docker容器网络互通 docker不同网段通信_docker_18

[root@server1 ~]# docker inspect mynet1

不同主机内docker容器网络互通 docker不同网段通信_iptables_19

3.手动指定ip

使用–ip参数可以指定容器ip地址,但必须是在自定义网桥上

[root@server1 ~]# docker rm demo
demo
[root@server1 ~]# docker rm demo2
demo2
[root@server1 ~]# docker run -it --rm --ip 172.20.0.10 --network mynet1 busybox
[root@server1 ~]# docker run -it --rm  --network mynet1 busybox
ip addr
[root@server1 ~]# docker inspect mynet1

不同主机内docker容器网络互通 docker不同网段通信_nginx_20

不同主机内docker容器网络互通 docker不同网段通信_docker_21

不同主机内docker容器网络互通 docker不同网段通信_iptables_22

4.双网卡来实现不同网段间通信

桥接到不同网桥上的容器,彼此是不通信的。
如何使两个不同网桥的容器通信呢:
使用 docker network connect命令为demo添加一块mynet1 的网卡。

[root@server1 ~]# docker rm -f demo1
[root@server1 ~]# docker network rm mynet1
[root@server1 ~]# docker network create --subnet 172.20.0.0/24 --gateway 172.20.0.1 mynet2

不同主机内docker容器网络互通 docker不同网段通信_iptables_23

[root@server1 ~]#docker run -d --name demo --network mynet1 --ip 172.20.0.10 nginx

不同主机内docker容器网络互通 docker不同网段通信_linux_24

[root@server1 ~]#docker run -it --rm --network mynet1 busybox
ip addr

不同主机内docker容器网络互通 docker不同网段通信_linux_25

[root@server1 ~]#docker run -it --rm --network mynet2 busybox
ip addr

不同主机内docker容器网络互通 docker不同网段通信_linux_26

docker inspect demo 查看id
[root@server1 ~]# docker inspect  demo
[root@server1 ~]# docker network connect mynet1 demo(或1b22f***)
[root@server1 ~]# docker attach 1b22f******
ip addr

我们可以看到mynet1,mynet2的ip都出现在了里面!说明通信成功!

不同主机内docker容器网络互通 docker不同网段通信_docker_27

然后可以直接在容器里面:ping demo成功!

不同主机内docker容器网络互通 docker不同网段通信_linux_28

三.Docker容器通信

容器之间除了使用ip通信外,还可以使用容器名称通信。
dns解析功能必须在自定义网络中使用。
在容器创建时使用–network=container:vm1指定。(vm1指定的是运行的容器名)

[root@server1 ~]# docker run  -it --rm --network container:demo busybox
/ # ip addr

不同主机内docker容器网络互通 docker不同网段通信_iptables_29

处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用localhost高效快速通信。
–link 可以用来链接2个容器。
–link的格式:
–link **:alias

name是源容器的name,alias是源容器在link下的别名。

[root@server1 ~]# docker pull nginx:latest
[root@server1 ~]# docker run -d --name demo nginx
[root@server1 ~]# docker run -it --rm --link demo:web busybox
/ # ping demo
/ # env

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_30

不同主机内docker容器网络互通 docker不同网段通信_linux_31

我们再次打开一个终端链接server1:

[root@server1 ~]# docker stop demo 
[root@server1 ~]# docker run -d --name test nginx
[root@server1 ~]# docker start demo

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_32


不同主机内docker容器网络互通 docker不同网段通信_iptables_33

我们再一次ping,发现ip变了(由 172.17.02 >>172.17.0.4),但是仍然可以ping名字demo成功!说明它i的名字随着IP实时更新变化的!!

不同主机内docker容器网络互通 docker不同网段通信_docker_34


这时我们查看/etc/hosts,发现他已经给我们自动修改了解析

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_35

1.内部访问外部

容器内部也是可以访问外部网络的

sysctl -a | grep ip_forward

可以看到路由转发功能是开启的为1

不同主机内docker容器网络互通 docker不同网段通信_iptables_36


那么我们在容器里面可以ping baidu.com

docker run -it --rm --link demo:web busybox
ping baidu.com

不同主机内docker容器网络互通 docker不同网段通信_iptables_37

2.外部访问内部

容器如何访问外网是通过iptables的SNAT实现的

外网如何访问容器:
端口映射
-p 选项指定映射端口

[root@server1 ~]# docker rm -f demo
[root@server1 ~]# docker rm -f test
docker history nginx 看到本身的端口为80
[root@server1 ~]# docker run -d --name demo -p 80:80 nginx
[root@server1 ~]# docker port demo
[root@server1 ~]# iptables -t nat -nL
[root@server1 ~]#netstat -antlp

不同主机内docker容器网络互通 docker不同网段通信_nginx_38

不同主机内docker容器网络互通 docker不同网段通信_iptables_39

不同主机内docker容器网络互通 docker不同网段通信_docker_40


netstat -antlp查看端口发现有docker-proxy

不同主机内docker容器网络互通 docker不同网段通信_linux_41

3.原理

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

测试:

[root@server1 ~]# curl 172.25.0.1
[root@server1 ~]# curl localhost

都是nginx的发布页面

不同主机内docker容器网络互通 docker不同网段通信_nginx_42


现在尝试将iptables里面的策略时删除,再次测试

iptables -t nat -D DOCKER 6

不同主机内docker容器网络互通 docker不同网段通信_linux_43


已经删掉了策略!

[root@server1 ~]# iptables -t nat -nL

不同主机内docker容器网络互通 docker不同网段通信_docker_44

[root@server1 ~]# curl localhost

发现nginx发布页面还在

不同主机内docker容器网络互通 docker不同网段通信_docker_45


但是如果将docker-proxy进程杀掉,再次访问查看效果

不同主机内docker容器网络互通 docker不同网段通信_nginx_46


已经访问不到了

不同主机内docker容器网络互通 docker不同网段通信_linux_47


当我们重新添加iptables策略

[root@server1 ~]# iptables -t nat -A DOCKER -p tcp --dport 80 -j DNAT --to-det 172.17.0.2:80

不同主机内docker容器网络互通 docker不同网段通信_docker_48


再次在真机上访问curl 172.25.0.1

或者在server1上访问本地localhost

发现又可以访问到nginx的发布页面了!!!

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_49

所以总结:docker-proxy,iptables里面的策略至少需要存在一个才可以!!

四.创建macvlan网络

1.使用eth0网卡来通信

需要两台虚拟机server1,server2:

在两台docker主机上各创建macvlan网络
我们先用eth0网卡连作为两台虚拟机通信的网卡!

首先在server1上操作:

[root@server1 ~]# ip addr show eth0
[root@server1 ~]#ip link set eth1 promisc on
[root@server1 ~]# ip addr show eth0

不同主机内docker容器网络互通 docker不同网段通信_iptables_50

我们发现ip link set eth1 promisc on打开之后,ip addr的eth0出现了promisc模式!!

不同主机内docker容器网络互通 docker不同网段通信_nginx_51

将之前实验的网络桥接删除掉!

docker network ls
docker network rm mynet1
docker network rm mynet2
cd harbor/
docker-compose stop

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_52

不同主机内docker容器网络互通 docker不同网段通信_iptables_53


先在server1上创建指定条件的容器然后运行容器:

[root@server1 ~]#docker network  create -d macvlan --subnet 172.20.0.0/24 --gateway=172.20.0.1 -o parent=eth0 macvlan1
[root@server1 ~]# docker run -it --rm --network macvlan1 --ip 172.20.0.10 busybox
ip addr

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_54


接着在server2上操作:

删除不用的桥接网络,本人是因为做过实验所以需要删除!

[root@server2 ~]#ip link set eth1 promisc on
[root@server2 ~]# ip addr show eth0
[root@server2 ~]#docker network ls
[root@server2 ~]#docker network rm macvlan1
[root@server2 ~]#docker network rm mynet1

不同主机内docker容器网络互通 docker不同网段通信_iptables_55

不同主机内docker容器网络互通 docker不同网段通信_docker_56

接着创建容器并运行和server1操作一样(只有IP不一致!)!

[root@server2 ~]#docker network  create -d macvlan --subnet 172.20.0.0/24 --gateway=172.20.0.1 -o parent=eth0 macvlan1
[root@server2 ~]#docker network ls
[root@server2 ~]# docker run -it --rm --network macvlan1 --ip 172.20.0.11 busybox
ip addr

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_57

``

不同主机内docker容器网络互通 docker不同网段通信_linux_58

这个时候已经完成了两台docker主机网卡的通信:

测试

在server1上的docker去ping一下server2的docker的ip地址:
发现可以通信!

ping 172.20.0.11

不同主机内docker容器网络互通 docker不同网段通信_docker_59

同理在server2上的docker去ping一下server2的docker的ip地址
也是可以成功的!

ping 172.20.0.10

2.使用eth1网卡来通信

首先需要在server1,2上再添加一块网卡:

virt-manager
分别选择两个虚拟机
添加网卡:add hardware
network网卡:virtio桥接的模式
finish

不同主机内docker容器网络互通 docker不同网段通信_docker_60

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_61

添加网卡之后,查看eth1可以看到没有ip只是一个网卡
ip link set up eth1让它启用!

ip addr show eth1
 ip link set up eth1

不同主机内docker容器网络互通 docker不同网段通信_docker_62

我们需要编辑网卡的配置文件

cd /etc/sysconfig/network-scripts
cp ifcfg-eth0 ifcfg-eth1
vim ifcfg-eth1

不同主机内docker容器网络互通 docker不同网段通信_linux_63

不同主机内docker容器网络互通 docker不同网段通信_iptables_64

让eth0网卡不能获得ip,随网络服务启动

不同主机内docker容器网络互通 docker不同网段通信_iptables_65

重新激活网卡

ifup eth1

不同主机内docker容器网络互通 docker不同网段通信_nginx_66

我们查看一下eth1

ip addr show eth1

发现已经激活但是promisc模式还没有打开!

不同主机内docker容器网络互通 docker不同网段通信_docker_67


开启promisc模式

ip link set eth1 promisc on

不同主机内docker容器网络互通 docker不同网段通信_docker_68

创建容器并运行,注意网段需要改变一下和前面eth0不一样172.21..

[root@server1 ~]#docker network  create -d macvlan --subnet 172.21.0.0/24 --gateway=172.21.0.1 -o parent=eth1.1 macvlan2

[root@server1 ~]# docker run -it --rm --network macvlan2 --ip 172.21.0.10 busybox
ip addr

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_69


在server2也需要激活网卡打开promisc模式

ip link set up eth1
ip link set eth1 promisc on
ip addr show eth1

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_70

不同主机内docker容器网络互通 docker不同网段通信_docker_71

在server2也需要创建容器并运行:

[root@server2 ~]#docker network  create -d macvlan --subnet 172.21.0.0/24 --gateway=172.21.0.1 -o parent=eth1.1 macvlan2

[root@server2 ~]# docker run -it --rm --network macvlan2 --ip 172.21.0.11 busybox
ip addr

不同主机内docker容器网络互通 docker不同网段通信_nginx_72


测试:

server1里可以ping通server2 的ip;172.21.0.11ping 172.21.0.11

不同主机内docker容器网络互通 docker不同网段通信_docker_73


同理server2也可以ping通server1

ping 172.21.0.10

不同主机内docker容器网络互通 docker不同网段通信_iptables_74

实现不同网段的通信

我们在server2上运行前面的macvlan1

[root@server2 ~]# docker run  --rm --network macvlan1 --ip 172.20.0.11 busybox

不同主机内docker容器网络互通 docker不同网段通信_nginx_75

在server1上
如何使两个不同网桥的容器通信呢:
使用 docker network connect命令为demo添加一块macvlan1 的网卡。

先将macvlan2刚才的进程结束:
docker ps
docker rm -f ********
docker run -d --name demo --network macvlan2 --ip 172.21.0.10 nginx
docker network connect macvlan1 demo
docker inspect demo

不同主机内docker容器网络互通 docker不同网段通信_nginx_76

不同主机内docker容器网络互通 docker不同网段通信_不同主机内docker容器网络互通_77

然后运行容器,为demo添加一块macvlan1 的网卡。

不同主机内docker容器网络互通 docker不同网段通信_iptables_78

我们可以看到demo的信息中会自动生成和 macvlan1同网段172.20.*.*的ip:172.20.0.2

不同主机内docker容器网络互通 docker不同网段通信_docker_79

测试:
我们发现不同网段 172.21.0.10还是不能通信,但是生成的Ip172.20.0.2可以访问。

ping 172.21.0.10
ping 172.20.0.2

不同主机内docker容器网络互通 docker不同网段通信_iptables_80

结论

我们得出结论:不同网段的ip是无法互通的,但是两个处于不同网段的容器可以通过docker network connect macvlan1 demo的方式来生成同一网段IP地址的方式来实现容器间的通信!!

在server2上去访问172.25.0.2

curl 172.25.0.2

成功!

不同主机内docker容器网络互通 docker不同网段通信_linux_81