云原生环境网络方案1 --- 容器网络模型与K8S网络模型

云原生环境网络方案1 --- 容器网络模型与K8S网络模型

K8S系统将网络方面的功能托管给了第三方插件来完成,本文将简略描述其基本通讯原理以及常见的几种网络方案。

Docker网络通讯模型

Docker容器的网络设置有4种形式,去除None和共享Namespace之外,其实只有两种网络即:

  • 主机网络

  • Bridge网络

其中Bridge是Docker容器的默认网络。

在任何安装了Docker的宿主机环境上,我们都能发现系统中新增了一个名为Docker0的网桥设备。

$ brctl show
bridge name  bridge id          STP enabled  interfaces
docker0      8000.024204b14ad5  no           veth9d63d04 vethbf226b3

这个名为Docker0的网桥是默认用来给Docker容器通信用的。在容器创建过程中,默认会产生一对虚拟网口veth,一头连在Docker0上,另外一头连接在容器内的eth0上。如下图:

k8s-Container-Network.png

我们查看一下这个eth0的ip地址

$ sudo docker ps
CONTAINER ID  IMAGE  COMMAND  CREATED      STATUS          PORTS               NAMES
157545493a1b nginx:latest "/docker-en.…"   26 minutes ago   Up 26 minutes   0.0.0.0:80->80/tcp        nginx_demo

$ sudo docker container inspect 157545493a1b
...
            "Gateway": "172.18.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.18.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:12:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "91397797f09b069b9472a638861e21e9c0e861c14d2374cec9184997b52a2ba1",
                    "EndpointID": "8e8230218df826a1005625a09398785833497d79af2c69b0b82db37eaa0798a2",
                    "Gateway": "172.18.0.1",
                    "IPAddress": "172.18.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:12:00:03",
                    "DriverOpts": null
                }
            }

可以看到这个容器的eth0的IP地址被设置为了172.18.0.2,而网关被设置为了172.18.0.1。那这个网关的地址是谁的呢?

$ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        inet6 fe80::42:4ff:feb1:4ad5  prefixlen 64  scopeid 0x20<link>
        ether 02:42:04:b1:4a:d5  txqueuelen 0  (Ethernet)
        RX packets 494147  bytes 23247538 (23.2 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 886037  bytes 1319084427 (1.3 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

在宿主机中使用ifconfig命令,我们可以看到一个名为docker0的设备其网络地址为172.18.0.1,正是容器设置里的网关地址。在Linux环境中,可以为网桥配置网络地址,其实质上是一个名为Docker0的虚拟网卡设备插在Docker0网桥上,做为一个可参与路由的节点:

$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.1.1      0.0.0.0         UG    0      0        0 ens160
172.17.1.0      0.0.0.0         255.255.255.0   U     0      0        0 ens160
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

如果此时,我再启动另外一个容器,这个容器的eth0的地址为172.18.0.3,那这两个容器中,相互是可以ping通的。那么他们之间的网络拓扑如下图:

k8s-Page-2.png

此时,数据包还是只能在宿主机内部传输,我们启动的这个容器是一个nginx web服务器,从上面的容器信息输出可以看到0.0.0.0:80->80/tcp,其实现上是通过NAT进行的,从刚才的输出可以看到,宿主机的80端口被映射到了容器的80端口上。查看一下宿主机的NAT表,我们可以看到这个映射:

$ sudo iptables -L -n -t nat
...
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination              
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           
MASQUERADE  tcp  --  172.18.0.2           172.18.0.2           tcp dpt:80

Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.18.0.2:80

可以看到,Docker网络模型的设计,采用了私网地址+Linux 网桥的方法与外部外诺做解耦,流量进入宿主机时,使用DNAT方式映射端口,容器网络内部出去则需要做SNAT借用宿主机的网络地址。由于使用了大量的NAT映射,大规模网络出现问题的情况下,定位是非常困难的。

另外一种使用主机网络的方案,和直接跑一个程序在宿主机上是完全一致的,本文不做赘述,Docker的视角实际上只着眼于宿主机内部的网络通讯,跨宿主机通讯的场景实际上并没有考虑的。这样的考量应当是对多宿主机组成的容器云进行调度和编排的方案需要考虑的,比如K8S。

K8S跨宿主机网络通讯模型

上一节提到的是同一个宿主机内部容器间的通信,本节描述跨宿主机通讯的几种方式。

目前,跨宿主机通讯在网络层面一般有两种即:

  • 基于隧道的宿主机间通讯
  • 基于路由的宿主机间通讯

这两种方式又被称为overlayer和underlayer,其区别在于容器网络和宿主机网络是否在同一层面。

基于隧道的宿主机通讯

其中基于隧道的宿主机间通讯可能有多种类型,目前最常见的是基于VxLAN的隧道,这也是虚拟化网络的常规方案。以flannel的VxLAN方案为例。

k8s-宿主机间VxLAN.png

在每台宿主机上,会有一个VxLAN的VTEP虚拟设备flannel.1,其负责与其他VTEP设备打通,构成2层VxLAN虚拟交换网络。以上图为例,当宿主机2加入到网络中时,宿主机1上会有如下路由信息:


$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
...
172.18.1.0      172.18.1.0       255.255.255.0   UG    0      0        0 flannel.1

其中172.18.1.0是宿主机2的VTEP设备的网络地址。宿主机1上所有发往该网段的网络包会发往VTEP设备flannel.1,然后走VxLAN隧道发往宿主机2。

flannel的隧道方案除了VxLAN以外还有一种基于存UDP的早期方案,由于性能问题,目前已被废弃。

基于路由的宿主机通讯

上述基于隧道的宿主机间通讯,由于多了两次拆解包的过程,性能会有所下降。据有关数据表明,网络传输效率下降约20%-30%。除了这种通讯方式之外,还有一种基于路由的跨宿主机通信方式。例如除了上节提到的基于VxLAN隧道的方案外,flannel还有一种基于host-gateway的3层路由方案。其原理比较简单,即将各个宿主机网络进行子网划分,并在每台宿主机上设置相同的路由,类似以下:

$ ip route
...
172.18.0.0/24 via 172.17.1.41 dev ens160
172.18.1.0/24 via 172.17.1.42 dev ens160

利用Linux的路由功能实现容器的跨宿主机通信。剩下的问题就是如何保证各个宿主机上的路由表一致了。不同的插件方案使用的解决方案是不同的。例如flannel使用了etcd来存储同步路由信息,而Calico则使用了BGP来实现这一点。除此以外,Calico方案也不会在宿主机上建立任何网桥设备,这一点与flannel有很大区别。在Calico方案组veth-pair的另一端不会被插入到任何网桥设备中,而只是放在宿主机的网络命名空间内。

172.18.2.2 dev cali3863f3 scope link

宿主机上会有类似以上的路由记录,将相关数据包发送至虚拟设备cali3863f3上。

k8s-Calico.png

与flannel方案相比,由于没了虚拟网桥连接同一宿主机内各个容器,Calico方案需要在宿主机的路由表中添加多得多的路由表项。

基于路由的宿主机通信要求各个宿主机在二层网络层面是直连互通的,对底层网络有一定的要求。

常见容器网络插件

由于k8s将网络这部分开放给社区,目前CNI这部分的插件较多,常见的有如下几种:

  • Flannel,目前最普遍的实现,同时支持overlayer(UDP,VxLAN)和underlayer(Host-gw)的网络后端实现。
  • Calico,基于BGP的underlayer方案,功能丰富,对底层网络有一定要求。
  • Cilium,基于eBPF和XDP的高性能Overlayer方案
  • Kube-Route,采用BGP提供网络直连,集成基于LVS的负载均衡能力
  • WeaveNet,采用UDP封装实现的L2 Overlayer方案,支持用户态(慢,可加密)和内核态(快,无加密)两种实现

总结

宿主机内部的容器间网络通讯有基于网桥的,基于宿主机网络的。跨宿主机容器间网络通讯有Overlayer和Underlayer两种,区别在于容器间通讯是否和宿主机间通讯属于同一层面。

现有普适性最强的方案是Flannel,同时具备Overlayer和Underlayer的方案,为了统一架构,宿主机内部通讯使用了Linux虚拟网桥方案。需要注意的是,Flannel方案不支持K8S的NetworkPolicy,需要其他CNI插件配合,比如Calico。

Calico方案是目前比较成熟的Underlayer方案,其采用了BGP来同步多宿主机的路由表。

本文讨论的是网络层的解决方案,着眼于从网络层面联通各个容器的网络,至于访问控制,熔断,限流等内容是在其他组件比如Service Proxy,Service Mesh,API Gateway来实现的,不在本文讨论范围内。

最后,我们回顾一下K8S网络模型的3原则:

  • 任意两个容器(或者POD-共享网络命名空间的一组容器)之间可以直接通讯,无需显式NAT。
  • 宿主机与容器(POD)之间也是可以直接通讯,无需显式NAT。
  • 容器(POD)看到自己的IP和其他人看到它的IP是一致的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • CNI CNI(Container Network Interface,容器网络接口)是 Google 和 Cor...
    小梦唠娱乐阅读 456评论 0 0
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,485评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,551评论 0 11
  • 可爱进取,孤独成精。努力飞翔,天堂翱翔。战争美好,孤独进取。胆大飞翔,成就辉煌。努力进取,遥望,和谐家园。可爱游走...
    赵原野阅读 2,713评论 1 1
  • 在妖界我有个名头叫胡百晓,无论是何事,只要找到胡百晓即可有解决的办法。因为是只狐狸大家以讹传讹叫我“倾城百晓”,...
    猫九0110阅读 3,255评论 7 3