Docker容器的网络连接
一、Docker容器的网络基础
首先使用ifconfig命令来查看宿主机的网络配置,结果如下:

在系统中有一个名为docker0的网络设备,docker的守护进程就是通过docker0为docker的容器提供网络连接的各种服务。docker0实际上就是Linux的虚拟网桥。网桥是数据链路层的一种设备,它用来通过Mac地址也就是网络设备的物理地址来对网络进行划分,以及在不同的网络之间传递数据(协议转换)。Linux的虚拟网桥相比于普通的网桥有如下的特点:
- 可以设置IP地址——docker0就有一个ip地址
Linux的虚拟网桥是通用网络设备的一种,当虚拟网桥拥有ip之后,linux便可通过路由表或者ip表规则在网络层定位网桥,这就相当于拥有一个隐藏的虚拟网卡,这个网卡的名字就是docker0。
默认docker0的网络地址划分为:
- IP:172.17.0.1 子网掩码:255.255.0.0
- MAC:02:42:22:0b:00:00 到 02:42:22:0b:ff:ff
- 总共提供了65534个地址
docker根据ip范围为每一个容器提供相应的mac地址,从而避免mac地址冲突。docker守护进程在一个容器启动时还要创建创建网络连接的两端,一端是在容器中的网络设备,而另一端是在运行docker守护进程的主机上。打开一个名为veth*的接口,用来实现docker0这个网桥与容器的网络通信

1.查看网桥设备
安装网桥管理程序:
1 | sudo apt-get insatll bridge-utils #在ubuntu中 |
查看网桥设备:
1 | sudo brctl show |
结果如下,有一个docker0 的网桥设备。
2.运行一个容器查看网络设备情况
随便运行一个docker容器,然后查看这个容器的网络情况:
1 | docker start -i web #重新启动一个容器 |

可以看到容器的ip地址为172.17.0.2,mac地址为:02:42:ac:11:00:02
以守护进程的方式运行成容器,然后在host中查看网桥的状态:

可以看到interfaces中多了一个接口,这就是docker在容器创建时为容器连接docker0所创建的一个网络接口,同样使用ifconfig也能查看到这个网络接口:

3.自定义docker0,修改docker0默认ip地址
使用linux自带的ifconfig命令来修改docker0:
1 | sudo ifconfig docker0 192.168.200.1 netmask 255.255.255.0 |
再次查看网络设备信息,发现docker0的ip地址已经发生了变化:

注意不能直接在容器中修改ip地址,会报没有权限错误:
1 | root@4acef7f0c1a9:/# ifconfig docker0 192.168.200.2 netmask 255.255.255.0 |
然后重新启动docker以及重新运行一个容器,查看它们的ip地址。
4.自定义虚拟网桥
也可以自定义虚拟网桥,配置号ip地址和子网掩码,然后让docker使用这个网桥:
1 | sudo brctl addbr br0 #新建网桥br0 |

然后更改docker守护进程的启动配置:
在/etc/default/docker 中添加DOCKER_OPS值 -b=br0
1 | vim /etc/default/docker #在ubuntu中,在/etc/default目录下新建docker文件,添加DOCKER_OPS=“ -b=br0” |
在centos中编辑/etc/docker/daemon.json为:
1 | { |
然后重新加载守护进程以及重启docker服务:
1 | systemctl daemon-reload #重启守护进程 |
然后新建或重新运行一个docker容器:
1 | docker start web |

此时容器的ip已经变成了br0网桥设置的ip段了。
更多关于docker守护进程的配置和操作查看:Docker守护进程的配置和操作
二、Docker容器的互联
1.docker在默认情况下运行所有容器互联
新建Dockerfile:
1 | #Dockerfile for network test |
build:
1 | docker build -t df/web . |
之后安装net-utils查看ip
apt insatll net-tools
这个容器的ip为192.168.100.3
现在docker中运行了两个容器:
| container | ip | images | intsall |
|---|---|---|---|
| web | 192.168.100.2 | ubuntu:latest | nginx,ping,ifconfig |
| web1 | 192.168.100.3 | df/cnt:latest | nginx,ping,ifconfig,curl |
docker默认允许容器互相连接:
1 | ▶ docker attach web1 |
可以发现在web1容器中ping web容器,正常ping通,同样在web1中ping web1也是正常ping通。然后分别打开两个容器的nginx,在web1容器中使用curl命令访问web容器,结果如下:

这里使用的是ip进行访问,但是容器停止或者重启之后,ip地址可能发生变化,所以如果写死了ip,则很容易出问题,docker提供了另一种方式来获得容器的ip地址:
1 | docker run --link=[CONTAINER_NAME]:[ALIAS] [IMAGE] [COMMOND] |
这里新建了一个web2容器,并让web2容器和web容器绑定,接着在web2中ping web容器,可以顺利地ping通。
查看web2的/etc/hosts文件,可以发现web2有到web ip地址的映射,并且这个映射永远是准确的,docker会自动修改ip地址和别名对应。

2.拒接容器间的互联
1 | vim /etc/docker/daemon.json |
添加:"icc":false
然后重新允许容器web,web1,web2,发现都不能ping通了。
1 | root@ef62e24881b3:/# ping 192.168.100.2 |
3.运行特定容器间的互联
- –icc设置为false
- –iptables设置为true
- 设置–link
在centos中:vim /etc/docker/daemon.json
1 | { |
在ubuntu中:
vim /etc/default/docker
1 | DOCKER_OPTS="--icc=false --iptables=true" |
重启docker,重启容器
docker run -it --name web2 --link=web:别名 df/cnt #web2容器和web容器绑定
三、Docker容器与外部网络的连接
1.ip_forward
出于安全考虑,Linux系统默认是禁止数据包转发的。所谓转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的ip地址将数据包发往本机另一块网卡,该网卡根据路由表继续发送数据包。这通常是路由器所要实现的功能。
要让Linux系统具有路由转发功能,需要配置一个Linux的内核参数net.ipv4.ip_forward。这个参数指定了Linux系统当前对路由转发功能的支持情况;其值为0时表示禁止进行IP转发;如果是1,则说明IP转发功能已经打开。
- 临时生效的配置方式
临时生效的配置在主机重启或者主机网络重启之后失效,适合用于测试。
1 | sysctl -w net.ipv4.ip_forward=1 |
配置完之后,输入sysctl net.ipv4.ip_forward查看,结果如下:
1 | net.ipv4.ip_forward = 1 |
- 永久生效的配置方式
修改/etc/sysctl.conf 配置文件,在sysctl.conf配置文件中有一项名为net.ipv4.ip_forward的配置项,将其值设为1。修改sysctl.conf文件后需要执行指令sysctl -p 后新的配置才会生效。
或者:
修改/etc/sysconfig/network配置文件,在文件最后添加一行:FORWARD_IPV4=YES,修改配置文件后需要重启网络服务(service netwrok restart)才能使新的配置生效。
配置完之后输入命令sysctl net.ipv4.conf.all.forwarding查看当前的配置,输出结果如下:
1 | net.ipv4.conf.all.forwarding = 1 |
2.iptables
Iptables是与linux内核集成的包过滤防火墙,几乎所有的linux发行版本都会包含Iptables的功能。

表(table)
链(chain)
规则(rule)
ACCEPT REJECT DROP
当主机收到一个数据包后,数据包先在内核空间中处理,若发现目的地址是自身,则传到用户空间中交给对应的应用程序处理,若发现目的不是自身,则会将包丢弃或进行转发。
iptables实现防火墙功能的原理是:在数据包经过内核的过程中有五处关键地方,分别是PREROUTING、INPUT、OUTPUT、FORWARD、POSTROUTING,称为钩子函数,iptables这款用户空间的软件可以在这5处地方写规则,对经过的数据包进行处理,规则一般的定义为“如果数据包头符合这样的条件,就这样处理数据包”。
iptables中定义有5条链,说白了就是上面说的5个钩子函数,因为每个钩子函数中可以定义多条规则,每当数据包到达一个钩子函数时,iptables就会从钩子函数中第一条规则开始检查,看该数据包是否满足规则所定义的条件。如果满足,系统就会根据该条规则所定义的方法处理该数据包;否则iptables将继续检查下一条规则,如果该数据包不符合钩子函数中任一条规则,iptables就会根据该函数预先定义的默认策略来处理数据包
iptables中定义有表,分别表示提供的功能,有filter表(实现包过滤)、nat表(实现网络地址转换)、mangle表(实现包修改)、raw表(实现数据跟踪),这些表具有一定的优先级:raw–>mangle–>nat–>filter

3.允许端口映射访问
4.限制IP访问容器
在iptables中禁用ip就行了
四、容器跨主机网络访问
宿主主机可以对容器进行访问(端口映射),同一机器上的容器之间可以互相访问(同一网段),但是容器默认是无法访问主机的,因此别的主机上的容器也不能访问别的主机。因为相对于容器来说,主机是外网,可以使用主机的外网ip进行访问,但这相当于走了一次网络,并不是直接访问,没有享受到同一主机上进行网络访问的优点。
使用网桥实现跨主机连接
解决方案就是让docker容器和host主机ip在同一个网段,可以将它们都使用一个相同的网桥br0,默认是使用不同的网桥(docker0/br0,eth0)。

评论加载中