标签:dockerd 发送 def std nss from 交互模式 规则 write
一、docker网络简介
网络作为docker容器化实现的6个名称空间的其中之一,是必不可少的。其在Linux内核2.6时已经被加载进内核支持了。网络名称空间主要用于实现网络设备和协议栈的隔离,列如;一个docker host有4块网卡,在创建容器的时候,将其中一块网卡分配给该名称空间,那么其他名称空间是看不到这块网卡的。且:一个设备只能属于一个名称空间。因为一个名称空间绑定一个物理网卡和外界通信,且一个物理网卡不能分配多个名称空间,这使得我们只能创建4个名称空间。如果要创建的名称空间多于我们的物理网卡数量,那该怎么办呢?
1、 虚拟网络通信的三种方式
1.1、桥接网络:在kvm的虚拟网络中,我们使用的是虚拟网卡设备(用纯软件的方式来模拟一组设备来使用),而在docker中,也不例外。在Linux内核级,支持两种级别设备的模拟,分别是2层设备(工作在链路层能实现封装物理报文并在各网络设备中报文转发的组件);而这个功能,是可以在Linux上利用内核中对二层虚拟设备的支持创建虚拟网卡接口的。而且,这种虚拟网卡接口非常独特,每一个网络接口设备是成对出现的,可以模拟一根网线的两端,其中,一端可以插在主机上,另一端可以插在交换机上。这就相当于让一个主机连接到一个交换机上了。而Linux内核原生支持二层虚拟网桥设备(用软件来构建一个交换机)。例如;我有两个名称空间,都分别使用虚拟网络创建一对网络接口,一头插在名称空间上,另一头插在虚拟网桥设备上,并且两个名称空间配置在同一个网段上,这样就实现了容器间的通信,但是这种桥接方式,如果用在有N多个容器的网络中,由于所有容器全部是桥接在同一块虚拟网桥设备上,会产生广播风暴,在隔离上也是极为不易的,因此在规模容器的场景中,使用桥接这种方式无疑是自讨苦吃,否则都不应该直接桥接的。
1.2、nat网络:如果不桥接,又能与外部通信,用的是nat技术。NAT(network address transfer)网络地址转换,就是替换IP报文头部的地址信息,通过将内部网络IP地址替换为出口的IP地址提供不同网段的通信。比如:两个容器都配置了不同的私网地址,并且为容器配置了虚拟网桥(虚拟交换机),把容器1的网关指向虚拟网桥的IP地址,而后在docker host上打开核心转发功能,这时,当容器1与容器2通信时,报文先送给各自的虚拟网桥经由内核,内核判定目的IP不是自己,会查询路由表,而后将报文送给对应的网卡,物理网卡收到报文之后报文的原地址替换成自己的IP(这个操作称为snat),再将报文发送给容器2的物理网卡,物理网卡收到报文后,会将报文的原IP替换为自己的IP(这个操作称作dnat)发送给虚拟交换机,最后在发送给容器2。容器2收到报文之后,同样的也要经过相同的操作,将回复报文经过改写原ip地址的操作(snat和dnat)送达给容器1的物理网卡,物理网卡收到报文之后在将报文转发给虚拟网桥送给容器1。在这种网络中,如果要跨物理主机,让两个容器通信,必须经过两次nat(snat和dnat),造成了通信效率的低下。在多容器的场景中也不适合。
1.3、Overlay Network
叠加网络,在这种网络中,不同主机的容器通信会借助于一个虚拟网桥,让当前主机的各个容器连接到这个虚拟网桥上来,随后,他们通信时,借助物理网络,来完成报文的隧道转发,从而可以实现容器可以直接看到不同主机的其他容器,进而互相通信。例如;容器1要和其他host上的容器2通信,容器1会把报文发送给虚拟网桥,虚拟网桥发现目的IP不在本地物理服务器上,于是这个报文会从物理网卡发送出去,在发出去之前不在做snat,而是在添加一层IP报头,原地址是容器1的物理网卡地址,目的地址是容器2所在主机的物理网卡地址。报文到达主机,主机拆完第一层数据报文,发现还有一层报头,并且IP地址是当前主机的容器地址,进而将报文发送给虚拟网桥,最后在发送给容器2。这种用一个IP来承载另外一个IP的方式叫做隧道。
2、docker支持的四种网络模型
2.1、Closed container:只有loop接口,就是null类型
2.2、Bridged container A:桥接式类型,容器网络接入到docker0网络上
2.3、joined container A:联盟式网络,让两个容器有一部分名称空间隔离(User、Mount、Pid),这样两个容器间就拥有同一个网络接口,网络协议栈
2.4、Open container:开放式网络:直接共享物理机的三个名称空间(UTS、IPC、Net),世界使用物理主机的网卡通信,赋予容器管理物理主机网络的特权
二、Docker网络的指定
1、bridge网络(NAT)
docker在安装完以后自动提供了3种网络,默认使用bridge(nat桥接)网络,如果启动容器时,不指定--network=string,就是用的bridge网络,使用docker network ls可以看到这三种网络类型
docker在安装完成后,会自动在本机创建一个软交换机(docker0),可以扮演二层的交换机设备,也可以扮演二层的网卡设备
当我们在创建容器时,docker会通过软件自动创建2个虚拟的网卡,一端接在容器上,另一端接在docker0交换机上,从而使得容器就好像连接在了交换机上。
这是我还没有启动容器之前本地host的网络信息
下面我启动两个容器,查看网络信息的变化,可以看到多出来两个vethf的虚拟网卡
这就是docker为容器启动创建的一对虚拟网卡中的一半
另一半在容器中
并且他们都被关联到了docker0虚拟交换机中,可以使用brctl和ip link show查看到
可以看到,vethf虚拟网卡后面还有一半“@if6和@if8”,这两个就是在容器中的虚拟网卡
bridge0是一个nat桥,因此docker在启动容器后,还会自动为容器生成一个iptables规则
其中在POSTROUTING的chain上,有一个“MASQUERADE”从任何地址进入,只要不从docker0出去,原地址是172.17网段,到任何地址去的数据,都将被地址转换,snat
上面提到过,当docker使用nat网络时,仅仅只有当前docker host和当前docker host上的容器之间可以互相访问,那么不同主机的容器要进行通信,就必须要进行dnat(端口映射的方式),且同一个端口只能映射一个服务,那么在这个docker host中如果有多个web服务,就只能映射到一个80端口,其他的web服务就只能改默认端口,这也为我们带来了很大的局限性。
1.1、使用ip命令操作net名称空间
由于docker的Net、UTS以及IPC是可以被容器共享的,所以能够构建出一个此前在KVM的虚拟化网络中所谓的隔离式网络、桥接式网络、NET式网络、物理桥式网络初次之外所不具有的特殊网络模型,我们可以用ip命令手动去操作网络名称空间的,ip命令所能操作的众多对象当中包括netns
查询是否安装ip命令
创建net名称空间
如果没有单独为netns创建网卡接口的话,那么默认就只有一个loop网卡
创建网卡接口对并放入net名称空间
这样就完成了ip命令创建netns并设置网卡接口的配置
2、Host网络
重新启动一个容器,指定--network为host网络
使用交互模式连接到容器内部,查看网络信息
可以看到,这个容器使用的网络和物理主机的一模一样。注意:在这个容器内部更改网络信息,就和改物理主机的网络信息是同等的。
使用inspect也可以看到该容器的网络信息使用的是host