一、Docker网络间通信
启动一个测试容器
docker run -d --name test busybox sleep 36000
查看容器的IP地址
docker exec -it test ip a s
 网卡eth0@if11和172.17.0.2/16的IP是docker自动分配给容器的
1.1.宿主机ping容器,可以正常通信

1.2.容器ping宿主机,可以正常通信

1.3.容器ping外网,可以正常通信(前提条件是宿主机能访问外网)

1.4.容器ping另外一个容器
再启动一个容器test1
docker run -d --name test1 busybox sleep 36000
查看容器test1的IP  ping测试  容器之间是可以正常通信的
问题:那么它们之间是如何实现通信的呢?
二、Docker网络常用技术
查看Docker容器在哪个网络命名空间
2.1.网络命名空间
-
为了支持网络协议栈的多个实例,Linux在网络栈中引入了网络命名空间。 -
处于不同命名空间中的网络栈是完全隔离 的,彼此之间无法通信,就好像两个“平行宇宙” -
通过对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境
网络命名空间的操作
ip netns add ns1
ip netns list
ip netns exec ns1 ifconfig
ip netns exec ns1 bash
exit
ip link set br0 netns ns1
ethtool -k br0 | grep netns
ip netns del ns1
2.2.Veth设备对
通过Veth设备对可以直接将两个网络命名空间连接起来,实现不同网络命名空间之间的通信
创建veth设备对
ip link add veth0 type veth peer name veth1
ip link show
在当前网络命名空间出现了一对veth设备对 
ip netns add ns1
ip link set veth1 netns ns1
ip link show
veth1已经查看不到了 
ip netns exec ns1 ip link show
veth1已经移动到ns1网络命名空间了
14: veth1@if15解释
14表示设备的编号
veth1表示设备名
if15表示该设备的peer设备编号为15

注意:我们在Docker容器中看到的网络设备是eth0,这是因为Docker在将Veth设备放入容器后改名为eth0,简直以假乱真
实现veth设备对之间的通信
ip netns exec ns1 ip addr add 10.1.1.11/24 dev veth1
ip netns exec ns1 ip link set dev veth1 up
ip addr add 10.1.1.10/24 dev veth0
ip link set dev veth0 up
ping 10.1.1.11
设置IP地址后可以正常通信,这也就实现了不同网络命名空间的通信 
常用操作
Veth设备查看对端
ip netns exec ns1 ethtool -S veth1

2.3.网桥
把veth0连接到网桥docker1
brctl addbr docker1
brctl addif docker1 veth0
ifconfig veth0 0.0.0.0
ifconfig docker1 10.1.1.1/24
brctl show
网桥docker1下连接了veth0 
bridge link

删除网桥
ip link set dev docker1 down
brctl delbr docker1
三、理解docker0

Docker启动后会自动创建一块网卡——docker0,默认地址为172.17.0.1/16  docker0相当于一个可以配置IP的网桥,类似于三层交换机,所有容器均连接到docker0上,由docker0来实现MAC寻址和路由转发
每启动一个容器,就会分配一个IP地址
默认使用桥接(bridge)模式,通过Veth设备对 技术来实现通信
3.1.iptables和Netfilter
Netfilter 负责在内核中执行各种挂接的规则,运行在内核模式 中
而iptables 是在用户模式 下运行的进程,负责协助和维护内核中Netfilter的各种规则表。
iptables 命令介绍
3.2.路由
路由表的创建
Linux的路由表至少包括两个表,一个是LOCAL表 ,另一个是MAIN表 。
LOCAL表包含所有本地设备地址,LOCAL路由表是在配置网络设备地址时自动创建的,用于供Linux协议栈识别本地地址,以及进行本地各个不同网络接口之间的数据转发
通过如下命令查看LOCAL表的内容:
ip route show table local type local
MAIN表用于各类网络IP地址的转发。
路由表的查看
ip route list

netstat -rn或route -n
 标志是U,说明是可达路由 标志是G,说明这个网络接口连接的是网关,否则说明这个接口是直连主机
四、Docker的网络实现
详细介绍Docker启动后、运行不映射端口的容器、运行映射了端口的容器时iptables的区别(使用iptables-save 查看)
4.1.Docker启动后
NAT表
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
前两条匹配生效后,都会执行DOCKER链,而此时DOCKER链为空,所以前两条只是做了一个框架,并没有实际效果
若本地出发的数据包不是发往docker0的,则需要进行动态地址修改(MASQUERADE),将源地址从容器的地址(172段)修改为宿主机网卡的IP地址,之后就可以发送给外面的网络了,即SNAT
filter表
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
第1条:如果接收到的数据包属于以前已经建立好的连接,那么允许直接通过。这样接收到的数据表又走回docker0,并中转到相应的容器
第2条是框架,发往docker0的包都会走DOCKER链
第3条:来自docker0的包,如果Forward到非docker0的本地IP地址设备,是允许的。这样,docker0设备的包就可以根据路由规则中转到宿主机的网卡设备,从而访问外面的网络
第4条:docker0的包还可以被中转给docker0本身,即连接在docker0网桥上的不同容器之间的通信 也是允许的
4.2.运行不映射端口的容器
iptable与Docker启动后一样
4.3.运行映射了端口(80:80)的容器
共增加了如下三条规则
NAT表
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80
第1条:作用是将原地址和目标地址为容器IP 172.17.0.2/32, 且目标端口为80,MASQUERADE动态地转换为可用的宿主机IP地址—没搞懂为什么要这么做
第2条:其作用是将访问宿主机80端口请求的流量转发到容器172.17.0.2的80端口上,所以,外界访问Docker容器是通过iptables做DNAT实现的。
filter表
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
从非docker0发往docker0且目的地址为172.17.0.2/32,端口是tcp 8443的包是允许的
|