之前介绍过:Docker容器网络-基础知识上一篇文章提到了容器网络对Linux虚拟化技术的依赖。在本章中,我们将了解并了解Docker是如何做到的。通常,Linux容器的网络隔离在自己的NetworkNamespace中,包括:网络接口(NetworkInterface)、环回设备(LoopbackDevice)、路由表(RoutingTable)和iptables规则。对于一个进程来说,这些元素构成了它发起和响应网络请求的基本环境。豹纹一瞥我们执行dockerrun-d--namexxx后进入容器:##dockerps可以查看所有docker##进入容器dockerexec-it228ae947b20e/bin/bash,执行ifconfig:$ifconfigeth0linkencap:EthernetHWaddr22:A4:C8:79:DD:1Ainetaddr:192.168.65.28Bcast:我们在容器的这一端看到一个名为eth0的网卡,它是一个VethPair设备。我们通过route查看容器的路由表:$routeKernelIProutingtableDestinationGatewayGenmaskFlagsMetricRefUseIf我们可以看到eth0是这个容器的默认路由设备。我们还可以通过第二条路由规则看到,169.254.1.1/16网段的所有请求都会被eth0处理。VethPair设备的另一端在主机上。我们也可以通过查看宿主机的网络设备来查看:$ifconfig......eth0:flags=4163mtu1500inet172.16.241.192netmask255.255.240.0broadcast172.16。255.255以太00:16:3e:0a:f3:75txqueuelen1000(以太网)RX数据包3168620550字节727592674740(677.6GiB)RX错误0丢弃0超限0帧0TX数据包2937180637字节86619140527B7丢弃TX0Ti错误7溢出0载体0碰撞0......docker0:flags=4099mtu1500inet172.17.0.1netmask255.255.0.0broadcast172.17.255.255ether02:42:16:58:92:43txqueuelen0(以太网)RX数据包0字节0(0.0B)RX错误0丢弃0溢出0帧0TX数据包0字节0(0.0B)TX错误0丢弃0溢出0载波0冲突0......vethd08be47:flags=4163mtu1500ether16:37:8d:fe:36:ebtxqueuelen0(以太网)RX数据包193字节22658(22.1KiB)RX错误0丢弃0overruns0frame0TXpackets134bytes23655(23.1KiB)TXerrors0dropped0overruns0carrier0collisions0......在宿主机上,容器对应的VethPair设备是虚拟网卡,我们再使用brctlshow命令查看网桥:$brctlshowbridgenamebridgeidSTPenabledinterfacesdocker08000.0242afb1a841novethd08be47可以清楚的看到VethPairvethd08be47的一端插到了docker0上。现在执行dockerrun启动两个容器,你会发现docker0VethPair的一端插入到两个容器中。如果我们在一个容器内ping另一个容器的IP地址,是否也能互相ping通?$brctlshowbridge名称网桥IDSTP启用接口docker08000.0242afb1a841noveth26cf2ccveth8762ad2container1:$dockerexec-itf8014a4d34d0/bin/bash$ifconfigeth0Linkencap:EthernetHWaddr02:42:AC:0container1exec-it9a6f3807/6bc04/binifconfigeth0Linkencap:EthernetHWaddr02:42:AC:11:00:0从一个容器Ping另一个容器:#->container1internalpingcontainer2$ping172.17.0.3PING172.17.0.3(172.17.0.3):56databytes64bytesfrom172.17我们看到ping一个容器内部的另一个容器的ip是可以ping通的。也就是说,两个容器是可以互相通信的。容器通信我们不妨结合上面所说的来理解为什么一个容器可以访问另一个容器?先看一张简单的图:在容器1访问容器2的地址时,目的IP地址会匹配容器1的第二条路由规则,这条路由规则的Gateway是0.0.0.0,也就是说这是一个直连rule,也就是说,任何符合这条路由规则的请求都会通过二层网络直接通过eth0网卡发送到目的主机。通过二层网络到达容器2,需要127.17.0.3对应的MAC地址。所以容器1的网络协议栈需要通过eth0网卡发送ARP广播,??通过IP找到MAC地址。所谓ARP(AddressResolutionProtocol)就是通过第三层IP地址找到第二层MAC地址的协议。这里说的eth0是VethPair的一端,另一端插在宿主机的docker0网桥上。在docker0上插了一个虚拟网卡比如eth0,也就是说eth0成为了docker0网桥的“从设备”。slave设备会降级到docker0设备的端口,调用网络协议栈处理数据包的资格全部交给docker0网桥。因此,docker0收到ARP请求后,会起到二层交换机的作用,将ARP广播发送给插在docker0网桥中的其他虚拟网卡,这样127.17.0.3就会收到这个广播并发送MAC地址返回给容器1,有了这个MAC地址,容器1的eth0的网卡就可以发送数据包了。这个数据包会经过宿主机另一端的VethPair,veth26cf2cc,直接交给docker0。docker0的转发过程就是继续充当二层交换机。docker0根据数据包的目的MAC地址,在CAM表中查到对应的端口为veth8762ad2,然后将数据包发送到该端口。而这个端口就是宿主机另一端容器2的VethPair。这样数据包就进入了容器2的NetworkNamespace,最后容器2返回响应(Ping)给容器1。在真正的数据传输中,Linux内核Netfilter/Iptables也会参与其中,所以我赢了在这里详述。CAM是交换机通过MAC地址学习和维护端口与MAC地址的对应表。这里介绍的容器间通信方式是docker中最常见的桥接方式。当然还有host模式,container模式,none模式等等,还有其他的模式。有兴趣的可以阅读相关资料。跨主机通信完成。忍不住在这里发问。到目前为止,它只是单个主机内容器之间的通信。跨主机网络呢?在Docker的默认配置下,一台主机的docker0网桥是不能和其他主机通信的,它们之间没有任何关系,所以这些网桥上的容器自然不能在多台主机之间进行通信。但无论怎么变,道理都是一样的。如果我们创建一个公共网桥,是不是集群中所有的容器都可以通过这个公共网桥连接起来呢?当然,一般情况下,点对点通信往往可以通过NAT。但是,在互联网发达的今天,这可能不适用于容器化的环境。比如在注册中心注册实例的时候,肯定会带上IP。当然,在普通物理机中应用是没有问题的,但在容器化环境中就不一定了。容器中的IP很可能就是上面提到的172.17.0.2。每个节点都会有这个IP,这个IP很有可能是冲突的。如果我们想避免这个问题,我们会携带主机的IP和映射的端口进行注册。但是这样又带来了另一个问题,就是容器内部的应用程序意识到这是一个容器,而不是物理机。在容器内部时,应用程序需要获取容器所在物理机的IP。在容器外时,应用程序需要获取当前物理机的IP。显然,这不是一个很好的设计,需要应用程序来匹配配置。所以,基于此,我们必须寻找其他的容器网络解决方案。在上图的容器网络中,我们需要在我们现有的主机网络上搭建一个覆盖多台主机并通过软件连接所有容器的虚拟网络。这就是OverlayNetwork(覆盖网络)。关于这些具体的网络解决方案,比如Flannel、Calico等,我会在后续的篇幅中继续说明。_链接:https://www.cnblogs.com/sally...作者Mr_Zack_