每日一句:世界先爱了我,我不能不爱它! --- 汪曾祺【人间草木】
什么?听说有人要讲给自己听【惊讶】,别人都是讲给女朋友听,讲给3岁小孩听的啊!呃呃。。。这不是还没有女朋友嘛【嘿嘿】!!今天我们就来认真的学习一下Docker的网络基础(相信很多人仅仅停留在会用层面,一提起Docker网络内心应该也是很模糊的吧)。
Docker 的网络强依赖与Linux系统内核的支持,Docker主要用到的Linux网络技术有下面几种:
-
Network Namespace (网络命名空间)
-
Veth设备对
-
网桥
-
Iptables/Netfilter
-
路由
网络命名空间
通常物理的网络设备(连接实际硬件的设备)只能关联到root这个命名空间中,而虚拟的网络设备(虚拟的以太网接口或者虚拟网口对)则可以创建并关联到指定的命名空间中。
- Linux网络命名空间的作用就是在一个虚拟机上
虚拟出多个,不同的相互隔离的,网络环境实例
,代表着独立的网络协议栈, 他们彼此无法相互通信。 - Docker 正是利用了这个特性实现了不同容器之间网络的隔离。
- 每一个空间的网络环境实例都有自己独立的路由表和独立的Iptables/Netfilter来提供包转发,NAT和IP包的过滤等功能。
- 空间里的一些设备是可以相互转移的,如Veth,但是像桥接设备,lo设备是不可转移的。
下面是使用Linux的 iproute2工具介绍一些命名空间的常用操作:
- 创建命名空间
ip netns add <name>
- 在命名空间执行命令
ip netns exec <name> <command>
- 进入命名空间内部的sh
ip netns exec <name> bash
复制代码
Veth 设备对
那么不同的网络空间之间,以及如何和外部通信呢?答案就是“Veth设备对” ,它就像一个管子一样连接了两个不同的网络命名空间的以太网卡并进行通信。Docker与外部通信也是利用了这点。
下面是Veth设备对的常用命令:
- 创建Veth设备对veth0, veth1, 这时在一个命名空间
ip link add veth0 type veth peer name veth1
- 查看创建结果
ip link show
- 把‘网线头’丢到另一个命名空间
ip link set veth1 netns netns1
- 进入netns1查看
ip netns exec netns1 ip link show
这时候只是创建了两个命名空间的Veth设备对,还没有IP,不能通信。
- 分配ip
ip netns exec netns1 ip addr add 10.1.1.1/24 dev veth1
ip addr add 10.1.1.2/24 dev veth0
- 再次重启
ip netns exec netns1 ip link set dev veth1 up
ip link set dev veth0 up
在两个命名空间验证相互通信:
ping 10.1.1.1
ip netns exec netns1 ping 10.1.1.2
查看Veth的对端:
ip netns excec netns1 ethtool -S veth1
ip netns exec netns2 ip link | grep $(上一步的设备号)
复制代码
网桥
网桥是一个二层设备,就是解析自己收到的报文,取下MAC头和自己记录的MAC表结合,来决策报文的转发端口。如果是遇到了一个没有记录的MAC地址,就只能广播给所有的网络设备端口。
- 可以看作是一个“底层的路由器” (路由器工作在网络层,根据网络地址ip转发)
为了避免因网络设备的转移和无法感知,导致根据历史MAC表发的包的端口已经没有对方接收了,网桥通过超时时间判断,超过时间的就是重新广播发送。
从eth0 或 eth1来的报文提交给网桥后,由网桥判断报文应该被转发,丢失或者提交到上
网桥的常用操作命令:
- 增加一个网桥
brctl addbr xxxx
- 给网桥添加以太网接口卡
brctl addif xxx ethx
- 给网桥配置一个ip地址
ifconfig brxxx xxx.xxx.xxx.xxx
复制代码
Iptables/Netfilter
linux网络协议栈中一组回调函数挂接点
挂接的钩子函数
可以在Linux 处理数据包的过程中对数据包进行过滤,修改,丢弃等。这个挂接点技术叫作Iptables 和 Netfilter。
- Netfilter 在内核模式中执行各种挂接的规则
- Iptables 在用户模式下协助维护内核中的Netfilter的各种规则表
- 两者相互配合实现整个Linux网络协议栈中灵活的数据包处理机制
Netfilter可以挂接的规则点有5个:
规则表Table
规则表挂接的规则可以分为不同的类型,我们可以在不同的Table中加入我们的规则,目前支持的Table类型:
上述规则从左到右,优先级依次降低。当数据包处理到挂接点时候,会依次调用挂接点处的函数,直到明确数据包是接收或拒绝。
数据处理规则的特性:
- 表类型是什么(准备干什么事情)
- 什么挂接点(什么时候起作用)
- 匹配的参数是什么(针对什么样的数据包,流入,流出,来源,目的,协议类型等)
- 匹配后有什么动作 (匹配后具体的操作是什么)
iptables命令:
- 查看已有的规则:
iptables -L -n
复制代码
路由
路由是由IP层维护的路由表来实现的,如果报文中的IP地址不是主机自身的地址,那么报文将会被转发或丢弃。
路由表通常包含:
- 目的ip地址
- 下一个路由器的ip地址
- 标志 (是一个主机地址还是路由器地址)
- 网络接口规范
- 查看local路由表
ip route show table local type local
ip route list
netstat -rn
复制代码
Docker 的网络实现
Docker支持4类网络模式:
- host模式,--net=host
- container模式,--net=container:NAME_or_ID
- none模式,--net=none
- bridge模式,--net=bridge
在K8s的网络模式下,通常只是用bridge模式
在桥接模式下,Docker Daemon第一次启动时会创建一个虚拟的网桥,缺省的名字是docker0, 并会分配一个子网。
docker0 网桥的子网地址范围:
- 172.[17-31].42.1/16
- 10.[0-255].42.1/16
- 192.168.[42-44].1/24
很多时候docker0网桥地址是172.17.xxx.xxx 。
- Docker创建出来的每一个容器,都会创建一个虚拟的以太网设备(Veth设备对),一端放到宿主机的网络命名空间并关联到网桥,另一端映射到容器内的eth0, 然后从docker0网桥的地址段给eth0接口分配一个IP地址。
- 同一台主机容器之间可以直接通过分配的ip相互通信, 不同主机上的容器不能相互通信
- docker0网桥和Iptables规则都处于root命名空间
可以在容器中用ping 一下网关或一台主机里的其它容器
定制docker网桥设备
一般自己定义的网桥设备和默认的docker0没有什么差别。
service docker stop
ip link set docker0 down
brctl delbr docker0
brctl add addbr cookbook
ip link set cookbook up
ip addr add 10.0.0.1/24 dev cookbook
复制代码
当有多台Docker主机之间通信的时候,可以使用GRE隧道或者Weave网络自动IP分配并且集成DNS的服务发现,因为接下来还要继续总结k8s的容器覆盖网络,实现跨主机通信,所以这里就不展开了。
总结
Docker在Linux的网络技术基础上,让同一台主机上的容器可以相互彼此通信,共享一个子网段。Docker的理念是简单即为美,通过虚拟化网络技术解决了Docker之间互联的问题,以免像OpenStack那样给用户留下网络的阴影,这也是Docker迅速走红的原因。下一篇我们讲继续学习K8s的网络基础,带你详细了解刚刚组件以及组件之间是如何通信的。
参考
- 《k8s权威指南》
- 《Docker经典实例》