容器网络

容器的网络栈

所谓的网络栈包括:网卡、回环设备、路由表、Iptables规则,而对于一个进程来讲,这些要素是构成发起和响应网络请求的基本环境。而对于容器来讲可以直接使用宿主机的网络栈,即不开启Network Namespace,例如:

docker run -d --net=host --name nginx-host nginx 

直接监控到宿主机80端口

 netstat -ntlp  | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      29133/nginx: master 

虽然这种方式会提高容器网络性能,但也会不可避免的引入共享网络资源的问题,例如端口冲突等。所以,在大多数情况下,我们都希望容器进程能使用自己的Netword Namespace里的网络栈,拥有自己的IP和端口。

容器与容器之间如何通信

这里我们可以把每一个容器看做一台主机,他们都有自己的一套网络栈。如下想让两个容器互通最简单的办法就是连接一根网线。而想要多台主机相互通信,那就需要一根网线连接到交换机上。在Linux中能起虚拟交换机的作用设备那就是网桥(Bridge),它是工作在数据链路层的设备,主要功能就是根据MAC地址学习来将数据包转发到网桥的不同端口。

而Docker创建的时候会默认在宿主机上创建一个docker 0的网桥,凡是连接在docker 0网桥上的容器,就可以通过他来通信。连接docker 0网桥需要一个Veth Pair的虚拟设备。

Veth Pair特点:它被创建后,总是以两张虚拟网卡的形式成对出现,并且,从其中一个“网卡”发出的数据包可以直接出现在另一张“网卡”上,哪怕这两张网卡在不通的namespace里。这使得Veth Pair常常被称作两个容器间的“网线”。

演示:

启动一个myapp启动,命名为myapp-1

docker run -d --name myapp-1 ikubernetes/myapp:v1

进入到容器,查看一下网络

#进去容器
$ docker exec -it myapp-1 /bin/sh
#查看网络
$ ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1046 (1.0 KiB)  TX bytes:866 (866.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      *               255.255.0.0     U     0      0        0 eth0

可以看到,这个容器有一张eth0的网卡,这个网卡就是Veth Pair设备在容器的这一端,通过route命令查看myapp-1的路由表,可以看到,这个eth0网卡是这个容器的默认路由设备。所有对172.17.0.0/16 网络的请求,也会被交给eth0来处理(第二条规则)

而Veth Pair设备另一端而在宿主机上,我们可以查看宿主机网络设备。如下:

$ ifconfig
.....
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:a0ff:fed8:f7fb  prefixlen 64  scopeid 0x20<link>
        ether 02:42:a0:d8:f7:fb  txqueuelen 0  (Ethernet)
        RX packets 41  bytes 2581 (2.5 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 15  bytes 1178 (1.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
vethf34d9da: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::7cf9:b4ff:fefc:fc3c  prefixlen 64  scopeid 0x20<link>
        ether 7e:f9:b4:fc:fc:3c  txqueuelen 0  (Ethernet)
        RX packets 16  bytes 1173 (1.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 19  bytes 1458 (1.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
.....
$ brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242a0d8f7fb       no              vethf34d9da

通过ifconfig命令输出,可以看到,myapp-1容器对应的Veth Pair设备在宿主机上是一张虚拟网卡。名字叫vethf34d9da。并且,通过brctl show的输出,可以看到这张网卡被“插”在docker0上了。

我们再启动一个容器,我们看一下会发生什么

docker run -d --name myapp-2 ikubernetes/myapp:v1

宿主机上查看一下网络设备

brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242a0d8f7fb       no              veth90a25df
                                                        vethf34d9da

我们发现vethf34d9da的虚拟网卡“插”在docker0上

我们在myapp-1上ping一下myapp-2的ip,我们会发现是通的。

$ docker exec -it myapp-1 /bin/sh
/ # ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.296 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.310 ms

解释一下为什么会通。

当我们myapp-1访问myapp-2的时候,这个目的IP地址会匹配到myapp-1容器里路由规则的第二条,可以看到,这条路由规则的网关是“*”,这就意味是直连规则,即:凡是匹配这个规则的IP包,应该经过eth 0网卡,通过二层网络直接发往目的主机。而要通过二层网络到达nginx-2容器,就需要有172.17.0.3这个IP对应的MAC地址,所以myapp-1容器的网络协议栈,就需要通过eth0网卡发送一个ARP广播,来通过IP地址查找对应的MAC地址。这个eth0网卡是一个Veth Pair,它的一段在myapp-1容器的Network Namespace里,而另一端则位于宿主机上,并“插”在docker0网桥上。

一旦一张虚拟网卡“插”在网桥上,它就变成该网桥的“从设备”,“从设备”会被“剥夺”调用网络协议栈处理数据包的资格,从而降级成为网桥上的一个端口,而这个端口的唯一作用,就是接收流入的数据包,然后这个数据包的“生杀大权”(例如转发、丢弃)全部交给对应的网桥。

所以,在收到这些ARP请求后,docker0网桥就会扮演二层交换机的角色,把ARP广播转发到其他被“插”在docker0上虚拟网卡上。这样,同样连接在docker0上的myapp-2容器的网络协议栈就会收到这个ARP请求,从而将172.17.0.3所对应的MAC地址回复给myapp-1容器。有了这个目的MAC地址,myapp-1容器的eth0网卡就可以将数据包发出去了。而根据Veth Pair设备原理,这个数据包会立即出现在宿主机vethf34d9da虚拟网卡上,不过,此时这个vethf34d9da虚拟网卡的网络协议栈被宿主机docker0剥夺,所以这个数据包将直接流入到docker0网桥里。

对于网桥上流入的数据包,就会通过宿主机的网络协议栈进行处理。需要注意的是,在宿主机上,Docker会为你设置如下路由规则:

route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         bogon           0.0.0.0         UG    100    0        0 ens160
172.16.138.0    0.0.0.0         255.255.255.0   U     100    0        0 ens160
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

而这次流入的数据包的目的地址是172.17.0.3,所以,当他出现宿主机之后,就会按照上述172.17.0.0这条路由规则,在进过docker0网桥(FORWORD)转发出去。

docker0处理转发的过程,则继续扮演二层交换机的角色,此时,docker0根据数据包的目的MAC地址(myapp-2容器的MAC地址),在它的CAM表(既交换机通过MAC地址学习维护的端口和MAC地址对应表)里查到对应的端口为: vethf34d9da,然后将数据转发到这个端口。而这个端口是myapp-2“插”在docker0网桥上的另一张虚拟网卡,当然他也是Veth Pair设备,这样数据包就进入到myapp-2容器里Network Namespace里。这样myapp-2容器的网卡上出现了流入的数据包,就可以对请求进行处理了,处理完成将响应返回给myapp-1。

上述流程示意图

与此类推,当宿主机访问容器的时候,如下示意图:

当一个容器访问另一个宿主机上的容器时,例如:ping 172.16.138.40,它发出的请求数据包,首先经过docker0网桥出现在宿主机上。然后根据宿主机的路由表里直连路由规则(172.16.138.0/24  ens160)对172.16.138.40的访问请求就会交给宿主机的eth0。数据包经过宿主机的eth0 网卡转发宿主机网络上,最终到达172.16.138.40对应的宿主机上,要实现这个首先两台宿主机的网络是连通的,如下图:

所以说当遇到容器连不通“外网”的时候,应该先试试ping docker0的地址通不通,然后在查docker0 和 Veth Pair 设备相关的iptables规则是不是正常。

网络栈

极客时间版权所有: https://time.geekbang.org/column/article/64948网络

网络栈

极客时间版权所有: https://time.geekbang.org/column/article/64948

网络栈

极客时间版权所有: https://time.geekbang.org/column/article/64948

1在大多数情况下,我们都希望容器进程能使用自己 Network...

极客时间版权所有: https://time.geekbang.org/column/article/64948

原文地址:https://www.cnblogs.com/xzkzzz/p/9929804.html

时间: 2024-10-11 04:50:19

容器网络的相关文章

Swarm基于多主机容器网络-overlay networks 梳理

前面介绍了Docker管理工具-Swarm部署记录,下面重点说下Swarm基于多主机容器通信的覆盖网络 在Docker版本1.12之后swarm模式原生支持覆盖网络(overlay networks),可以先创建一个覆盖网络,然后启动容器的时候启用这个覆盖网络, 这样只要是这个覆盖网络内的容器,不管在不在同一个宿主机上都能相互通信,即跨主机通信!不同覆盖网络内的容器组之间是相互隔离的(相互ping不通). swarm模式的覆盖网络包括以下功能: 1)可以附加多个服务到同一个网络. 2)默认情况下

理解Docker(6):若干企业生产环境中的容器网络方案

本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 (4)Docker 容器的隔离性 - 使用 cgroups 限制容器使用的资源 (5)Docker 网络 (6)若干企业生产环境中的容器网络方案 Docker 在早期只有单机上的网络解决方案,在 1.19 版本引入了原生的 overlay 网络解决方案,但是它的性能损耗较大,可能无法适应一些生产环

Docker的单主机容器网络

作者:杨冬 欢迎转载,也请保留这段声明.谢谢! 出处: https://andyyoung01.github.io/ 或 http://andyyoung01.16mb.com/ 本篇文章主要探索Docker的单机容器网络,了解一下单个Docker主机上网络的各种模式,从而为后续理解跨主机容器网络打下基础. Docker默认容器网络的建立和控制是一种结合了network namespace,iptables,Linux网桥及route table等多种技术的综合解决方案,本篇主要针对于如何使用单

理解Docker单机容器网络

在” 理解Docker单机容器网络 “一文中,还有一个Docker容器网络的功能尚未提及,那就是Docker容器的端口映射.即将容器的服务端口P’ 绑定到宿主机的端口P上,最终达到一种效果:外部程序通过宿主机的P端口访问,就像直接访问Docker容器网络内部容器提供的服务一样. Docker针对端口映射前后有两种方案,一种是1.7版本之前docker-proxy+iptables DNAT 的方式:另一种则是1.7版本(及之后)提供的完全由iptables DNAT实现的端口映射.不过在目前do

4 个你需要了解的容器网络工具

摘要: 有如此之多的各种新的云计算技术.工具和技术需要我们跟进,到底从哪里开始学习是一个艰难的决定.这一系列下一代云计算技术的文章旨在让你快速了解新兴和快速变化领域的重大项目和产品,比如软件定义网络(SDN).容器,以及其交叉领域:容器网络. 有如此之多的各种新的云计算技术.工具和技术需要我们跟进,到底从哪里开始学习是一个艰难的决定.这一系列下一代云计算技术的文章旨在让你快速了解新兴和快速变化领域的重大项目和产品,比如软件定义网络(SDN).容器,以及其交叉领域:容器网络. 对于企业容器部署,容

从 Kubernetes 谈容器网络

Pod 首先,Kubernetes 中的基本单元是 Pod,而非 Docker 容器. Pod 是一组共享了下面资源的容器: 进程命名空间 网络命名空间 IPC 命名空间 UTS 命名空间 简单的讲,一个 Pod 是一个小型的"虚拟机",里面运行若干个不同的进程,每个进程实际上就是一个容器. Kubernetes 要干的事情是要把这些 Pod 给互相连接起来,是不是联想到了什么了? 设计理念 其实 Docker 默认采用 NAT 的方式已经组成了简单的网络了.但Kubernetes 认

有容云:容器网络那些事儿

编者注: 本文根据7月31日有容云<Docker Live时代线下沙龙-北京站>嘉宾分享内容整理而成,分享嘉宾杜东明,有容云高级技术顾问,十年IT经验,IT行业的全栈工程师.涉足领域包括存储.网络.备份/容灾.服务器/终端虚拟化.Docker等.拥有丰富的一线客户经验,曾帮助工行.建行.光大.国寿.泰康等诸多金融客户设计其虚拟化基础架. 我相信,真正拿容器工作或者是去运维一个容器环境,真正在容器上面做生产的时候大家都会遇到的一个话题就是容器网络,所以我今天给大家分享下这个话题,有不同意见的地方

容器网络——从CNI到Calico

从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道.我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理.虚拟环境对网络环境需求是有差别的,主要面临以下两个问题: 过去IaaS层在网络方便做了很多工作,已经形成了成熟的环境,如果和容器环境适配,两边都需要做很多改造 容器时代提倡微服务,导致容器的粒度之小,离散程度之大,原有IaaS层网络解决方案很难承载如此复杂的需求 我们来看下一些主流的容器网络接入方案: Host network 最简单的网络模型就是让容器共享Host

docker管理应用程序数据、容器网络

管理应用程序数据 Docker提供三种方式将数据从宿主机挂载到容器中: ? volumes:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes).保存数据的最佳方式. ? bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中. ? tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统.如果不希望将数据持久存储在任何位置,可以使用 tmpfs,同时避免写入容器可写层提高性能. 管理卷:路径都是在/var/lib/docker/vol