Kubernetes网络一直是一个很是复杂的主题。本文将介绍Kubernetes实际如何建立网络以及如何为Kubernetes集群设置网络。node
本文不包括如何设置Kubernetes集群。这篇文章中的全部例子都将使用Rancher 2.0集群(其余平台也一样适用)。即便你打算使用其余的公有云管理Kubernetes服务,也但愿你对Kubernetes网络的工做原理有更好的了解。git
许多Kubernetes部署指南中包含了在K8S部署中部署Kubernetes网络CNI的说明。可是若是你的K8S集群已经运行,而且还没有部署任何网络,那么部署网络就像在K8S上运行其提供的配置文件同样简单(对于大多数网络和基本用例而言)。例如,要部署flannel:github
这样,从网络的角度来看,K8S已经可使用。为了测试一切是否正常,咱们建立了两个Pod。docker
这将建立两个pod,它们正在使用咱们的驱动器。查看其中一个容器,咱们发现网络的IP地址范围为10.42.0.0/24。数组
在另外一个Pod进行的快速ping测试代表,网络运行正常。缓存
Kubernetes经过Docker之上的CNI管理网络,并将设备附加到Docker。尽管有Docker Swarm的Docker也具备本身的联网功能(例如overlay、macvlan、bridging等),但CNI也提供了相似类型的功能。安全
还有一点十分重要,K8S并不使用docker0(这是Docker的默认网桥),而是建立本身的网桥,名为cbr0,该网桥须要与docker0区分开来。服务器
诸如vxlan或ipsec之类的overlay网络能够将数据包封装到另外一个数据包中。这使得实体在另外一台计算机的范围以外依旧能够寻址。Overlay网络的替代方案包括如macvtap(lan)之类的L3解决方案,甚至包括ivtap(lan)之类的L2解决方案,可是这些方案具备必定的局限性。网络
L2或L3上的任何解决方案均可以让pod在网络上寻址。这意味着pod不只在Docker网络内部访问,还能直接从Docker网络外部访问。这些是公共IP地址或私有IP地址。架构
然而,在L2上进行通讯比较麻烦,而且你的经验会由于网络设备而异。某些交换机须要一些时间来注册你的Mac地址,而后才能将其实际链接到网络的其他部分。你还可能会遇到一些麻烦,由于系统中其余主机的neighbor(ARP) table仍在过期的缓存上运行,而且始终须要使用dhcp运行而不是host-local,这样能够避免主机之间的ip冲突。Mac地址和neighbor table问题是诸如ipvlan之类的解决方案存在的缘由。这些解决方案不会注册新的mac地址,而是在现有地址上路由流量(尽管它们也有本身的问题)。
所以,个人建议是,对于大多数用户而言,将overlay网络做为默认解决方案应该足够了。可是,一旦工做负载变得更加高级并提出了更具体的要求,你将须要考虑其余的解决方案,如BGP和直接路由。
在Kubernetes中首先要了解的是,pod实际上并不等同于容器,而是容器的集合。在同一集合的容器中共享一个网络堆栈。Kubernetes经过在暂停容器上设置网络来进行管理,你能够在你所建立的每一个pod中找到这些暂停容器。全部其余pod都链接到暂停容器的网络,该容器自己除了提供网络外不执行任何操做。所以,也可使一个容器经过localhost与不一样容器中的服务进行通讯,此时该容器具备相同pod的相同定义。
除了本地通讯以外,pod之间的通讯看起来与Docker网络中的container-to-container通讯几乎相同。
我将以两种场景为例,详细地说明如何在Pod之间路由流量。
在两种状况下,流量不会离开主机。一是当调用的服务在同一节点上运行,一是单个pod中的同一个容器集合。
若是从第一个pod中的容器1调用localhost:80并在容器2中运行服务,则流量将经过网络设备并将数据包转发到其余目的地。在这种状况下,路由流量的路线很短。
若是咱们想要与其余pod进行通讯,时间会更长一些。首先,流量将传递到cbr0,接下来cbr0将会注意到咱们在同一个子网通讯,所以它会将流量转发到目标Pod,过程以下图所示:
当咱们离开节点时,这将变得更加复杂。如今,cbr0会将流量传递到下一个节点,该节点的配置由CNI管理。这些基本上只是以目标主机为网关的子网路由。而后,目标主机能够继续使用本身的cbr0并将流量转发到目标容器,以下所示:
CNI是Container Networking Interface(容器网络接口)的缩写,基本上是一个具备定义明确的外部接口,Kubernetes能够调用它来提供网络功能。
你能够在如下连接中找到维护的参考插件,其中包括容器网络官方repo中的大多数重要插件:
https://github.com/containernetworking/plugins
CNI 3.1版不是很复杂。它包含三个必需的功能,ADD、DEL和VERSION,这些功能能够尽其所能管理网络。有关每一个函数应返回和传递的内容的更详细说明,您能够在此处阅读规范:
https://github.com/containernetworking/cni/blob/master/SPEC.md
如下咱们将介绍一些最受欢迎的CNI:
Flannel
Flannel是一个简单的网络,而且是overlay网络最简单的设置选项。它的功能包括原生网络,但在多个网络中使用时会受到限制。对于大多数用户来讲,Flannel是Canal下面的默认网络,部署起来很是简单,甚至还有本地网络功能,如主机网关。可是Flannel有一些限制,包括缺少对网络安全策略的支持以及没有多网络的功能。
Calico
Calico与Flannel采用不一样的方法,从技术的角度来讲,它不是overlay网络,而是在全部相关系统之间配置路由的系统。为此,Calico利用边界网关协议(BGP),它在名为peering的过程当中用于Internet。其中每方peering交换流量并参与BGP网络。BGP协议自己会在其ASN下传播路由,不一样之处在于它们是私有的,不须要再RIPE中注册它们。
可是,在某些状况下,Calico可与overlay网络配合使用,如IPINIP。当节点位于不一样网络上时使用,以便启动两个主机之间的流量交换。
Canal
Canal基于Flannel,但有一些Calico本身的组件,例如felix(主机代理),它能够利用网络安全策略。这些一般在Flannel中不存在。所以,它基本上经过添加安全策略来扩展Flannel。
Multus
Multus是一个CNI,但实际上它自己并非网络接口。只是它编排了多个接口,而且没有配置实际的网络,于是Pod没法单独与Multus通讯。实际上,Multus是多设备和多子网网络的推进者。下图显示了它是如何工做的,Multus自己基本上调用了真正的CNI而不是kubelet,并将结果传递回kubelet。
Kube-Router
一样值得一提的是kube-router,与Calico同样,它能够与BGP和路由而不是overlay网络一块儿使用。就像Calico同样,它在必要的时候可使用IPINIP。它还能利用ipvs进行负载均衡。
若是您须要使用多个网络,则可能须要Multus。
咱们须要作的第一件事是设置Multus。咱们使用的几乎是Multus仓库示例中的配置,但进行了一些重要的调整。请参阅下面的示例。
首先是调整configmap。由于咱们计划使用Flannel建立默认网络,因此咱们在Multus配置的delegates数组中定义配置。这里用红色标记的一些重要设置是“ masterplugin”:true,用于定义Flannel网络自己的网桥。你将在接下来的步骤中了解为何咱们须要这样作。除此以外,还须要添加配置映射的安装定义,其余则不须要调整,由于因为某些缘由,此示例未完成。
关于此configmap的另外一件重要事情是,这一configmap中定义的全部内容都是默认网络,这些默认网络会自动安装到容器,而无需进一步说明。另外,若是要编辑此文件,请注意,你要么须要终止并从新运行守护进程的容器,要么从新启动节点才能使更改生效。
示例yaml文件:
对于主要的Flannel网络,设置很是简单。咱们能够从Multus仓库中获取示例,而后进行部署。此处所作的调整是CNI安装、容差的调整以及对Flannel的CNI设置所作的一些调整。例如,添加“ forceAddress”:true并删除“ hairpinMode”:true。
这已在使用RKE设置的集群上进行了测试,可是只要您从主机正确安装CNI(在本例中为/ opt / cni / bin),它就能够在其余集群上工做。
Multus自己并无太大的改变。他们只注释了initcontainer配置,你能够删除它。之因此如此,是由于Multus将创建其delegates,并充当主要的“ CNI”。
这是修改后的Flannel daemonset:
部署了这些样本以后,咱们已经完成了不少工做,如今应该为pod分配一个IP地址。让咱们测试一下:
如你所见,咱们已经成功部署了Pod,并在eth0接口(默认接口)上为其分配了IP 10.42.2.43。全部其余接口都将显示为netX,即net1。
辅助网络还须要进行一些调整,这些调整的前提是假设你要部署vxlan。为了实际服务于辅助overlay,咱们须要更改VXLAN标识符“ VIN”,默认状况下将其设置为1,而且咱们的第一个overlay网络如今已经使用了它。所以,咱们能够经过在etcd服务器上配置网络来更改此设置。咱们使用本身的集群etcd,此处标记为绿色(而且假设job在运行etcd客户端的主机上运行),而后从本地主机(在咱们的状况下,将其存储在本地主机)中装入密钥(此处标记为红色),存储在/ etc / kubernetes / ssl文件夹中。
完整的YAML文件示例:
接下来,咱们能够实际部署辅助网络。此设置几乎与主要网络设置相同,但有一些关键区别。最明显的是,咱们更改了子网,可是咱们还须要更改其余一些内容。
首先,咱们须要设置一个不一样的dataDir,即/ var / lib / cni / flannel2,以及一个不一样的subnetFile,即/run/flannel/flannel2.env。这十分必要,由于它们已经被咱们的主要网络占用。接下来,咱们须要调整网桥,由于主要的Flannel overlay网络已经使用了kbr0。
其他还需更改的配置包括将其更改成实际针对咱们以前配置的etcd服务器。在主网络中,这是经过–kube-subnet-mgr flag直接链接到K8S API来完成的。可是咱们不能这样作,由于咱们还须要修改要读取的前缀。你能够在下面看到橙色标记的内容,而集群etcd链接的设置则显示为红色。最后一个设置是再次指定子网文件,在示例中以绿色标记。最后一点是,咱们添加了一个网络定义。其他部分与咱们的主要网络配置相同。
有关上述步骤,请参见示例配置文件:
完成此操做后,咱们便准备好了辅助网络。
既然咱们已经准备好辅助网络,那么咱们如今须要分配他。为此,咱们须要先定义一个NetworkAttachmentDefinition
,以后咱们可使用它将网络分配给容器。基本上,这是在初始化Multus以前,咱们设置的configmap的动态替代方案。这样,咱们能够按需安装所需的网络。在此定义中,咱们须要指定网络类型(本例中是Flannel)以及必要的配置。这包括前面提到的subnetFile、dataDir和网桥名称。
咱们须要肯定的最后一件事是网络的名称,咱们将其命名为flannel2。
如今,咱们终于可使用辅助网络生成第一个pod。
如今应该使用辅助网络建立新的Pod,而且咱们将那些附加网络视为额外添加的网络接口。
成功啦,辅助网络分配10.5.22.4做为其IP地址。
若是该示例没有正常工做,你须要查看kubelet的日志。
一个常见的问题的是缺乏CNI。我第一次测试的时候,遗漏了CNI网桥,由于RKE没有部署它。可是这个问题十分容易解决。
如今咱们已经创建并运行网络,接下来咱们要作的是使咱们的应用程序能够访问并将其配置为高可用和可扩展。高可用性和可伸缩性不只能够经过负载均衡来实现,它还咱们须要具有的关键组件。
Kubernetes有四个概念,可使应用程序在外部可用。
Ingress
Ingress基本上就是具备Layer7功能的负载均衡器,特别是HTTP(s)。最经常使用的ingress controller是NGINX ingress。但这主要取决于你的需求以及你的使用场景。例如,你还能够选择traefik或HA Proxy。
配置一个ingress十分简单。在如下例子中,你将了解一个连接服务的例子。蓝色标注的是指向服务的基本配置。绿色标注的是连接SSL证书所需的配置(须要在此以前安装这一证书)。最后,你会看到调整了NGINX ingress的一些详细设置。
Layer 4 负载均衡器
在Kubernetes中,使用type: LoadBalancer定义Layer 4 负载均衡器,这是一个依赖于负载均衡解决方案的服务提供程序。对于本地计算机,大几率会使用HA代理或一个路由解决方案。云提供商会使用本身的解决方案以及专用硬件,也可使用HA代理或路由解决方案。
最大的区别是第4层负载平衡器不了解高级应用程序协议(layer 7),而且仅可以转发流量。此级别上的大多数负载均衡器还支持SSL终止。这一般须要经过注释进行配置,而且还没有标准化。
使用 {host,node} 端口
{host,node} Port基本上等同于docker -p port:port
,尤为是hostPort。与hostPort不一样,nodePort在全部节点上可用,而不是仅在运行pod的节点上可用。对于nodePort,Kubernetes首先建立一个clusterIP,而后经过该端口负载均衡流量。nodePort自己只是将端口上的流量转发到clusterIP的iptable规则。
除了快速测试外,不多使用nodePort,只有在你但愿每一个节点公开端口(即用于监视)时才会在生产中使用nodePort。大多数时候,你须要使用Layer 4负载均衡器。hostPort仅用于测试,或者少数时候,将pod粘贴到特定节点并在指向该节点的特定IP地址下发布。
例如,在容器规范中定义了hostPort,以下所示:
什么是ClusterIP ?
clusterIP是Kubernetes集群及其中全部服务的内部可访问IP。该IP自己将负载均衡流量到与其selector规则匹配的全部Pod。在不少状况下,例如在指定类型:LoadBalancer服务或设置nodePort时,也会自动生成clusterIP。其背后的缘由是全部负载均衡都是经过clusterIP进行的。
clusterIP做为一个概念是为了解决多个可寻址主机以及这些主机的有效更新的问题。具备不变的单个IP比始终经过服务发现针对服务的全部性质从新获取数据要容易得多。尽管有时在某些状况下更适合使用服务发现,但若是你想要explicit control,那么仍是建议使用clusterIP,如在某些微服务环境中。
若是您使用公有云环境并手动设置主机,则您的集群可能缺乏防火墙规则。例如,在AWS中,您将须要调整安全组,以容许集群间通讯以及ingress和egress。若是不这样作,将致使集群没法运行。确保始终打开主节点和worker节点之间的必要端口。直接在主机上打开的端口(即hostPort或nodePort)也是如此。
既然咱们已经设置了全部Kubernetes网络,咱们还须要确保它们具有必定的安全性。保证安全性的最低原则是为应用程序提供其运行所需的最少访问量。这能够在必定程度上确保即便在发生安全漏洞的状况下,攻击者也将难以深刻挖掘你的网络。虽然它不能彻底确保你的安全,但无疑会使攻击者进行攻击时变得更加困难和耗时。这很重要,由于它会使你有更多的时间作出反应并防止进一步的破坏。这里有一个典型的例子,不一样应用程序的不一样exploits/漏洞的组合,这使得攻击者只有从多个维度(例如,网络、容器、主机)到达任何攻击面的状况下,才能进行攻击。
这里的选择要么是利用网络策略,要么是寻求第三方安全解决方案以实现容器网络安全。有了网络策略,咱们有坚实的基础来确保流量仅在流量应流的地方进行,但这仅适用于少数几个CNI。例如,它们可与Calico和Kube-router一块儿使用。Flannel不支持它,可是幸运的是,你能够移至Canal,这使得Flannel可使用Calico的网络策略功能。对于大多数其余CNI,则没有支持,目前还没有有支持的计划。
但这不是惟一的问题。问题在于,网络策略规则只是针对特定端口的防火墙规则,它十分简单。这意味着你没法应用任何高级设置。例如,若是你发现某个容器可疑,就不能按需阻止它。进一步来讲,网络规则没法理解流量,所以你不知道流量的流向,而且仅限于在第3层和第4层上建立规则。最后,它还没法检测到基于网络的威胁或攻击,例如DDoS,DNS,SQL注入以及即便在受信任的IP地址和端口上也可能发生的其余破坏性网络攻击。
所以,咱们须要专用的容器网络安全解决方案,它可为关键应用程序(例如财务或合规性驱动的应用程序)提供所需的安全性。我我的喜欢NeuVector。它具备我曾在Arvato / Bertelsmann进行部署的容器防火墙解决方案,并提供了咱们所需的Layer7可见性和保护。
应该注意的是,任何网络安全解决方案都必须是云原生的,而且能够自动扩展和调整。部署新应用程序或扩展Pod时,你无需检查iptable规则或更新任何内容。也许对于几个节点上的简单应用程序堆栈,你能够手动进行管理,可是对于任何企业而言,部署安全不能减慢CI / CD流水线的速度。
除了安全性和可见性以外,我还发现拥有链接和数据包级容器网络工具备助于在测试和staging期间调试应用程序。借助Kubernetes网络,除非您能看到流量,不然您将永远没法真正肯定全部数据包的去向以及将哪些Pod路由到其中。
如今已经介绍了Kubernetes网络和CNI,始终会出现一个大问题:应该选择哪一种CNI解决方案?我将尝试提供一些有关如何作出此决定的建议。
每一个项目的第一件事是尽量详细地定义你须要首先解决的问题。你也许想知道要部署哪一种应用程序以及它们将产生什么样的负载。你可能会问本身的一些问题:
个人应用程序:
网络是否繁忙?
是否对延迟敏感?
是单体架构吗?
仍是微服务架构服务?
须要在多个网络上吗?
这是一个十分重要的问题,由于你须要事先肯定好。若是你如今选择一种解决方案,之后再进行切换,则须要从新设置网络并从新部署全部容器。除非你已经拥有Multus之类的东西而且可使用多个网络,不然这将意味着您的服务会停机。在大多数状况下,若是你有计划的维护时段,那么事情会没那么严重,可是随着应用程序的不断迭代,零停机时间变得更加剧要!
这一状况在本地安装中十分常见,实际上,若是你只想将经过专用网络和公用网络的流量分开,那么这须要你设置多个网络或者有智能的路由。
影响你作决定的另外一件事是,你须要一些特定的功能,在某些CNI中可用,而其余CNI中不可用。例如,你想使用Weave或但愿经过ipvs进行更为成熟的负载均衡。
若是你的应用程序对延迟敏感或网络繁忙,那么你须要避免使用任何overlay网络。Overlay在性能上并不划算,规模上也是如此。这这种状况下,提升网络性能的惟一方法是避免overlay并改用路由之类的网络实用程序。寻找网络性能时,你有几种选择,例如:
Ipvlan:它有良好的性能,但须要注意,你不能在同一主机上同时使用macv{tap,lan}。
Calico:这个CNI不是对用户最友好的,但于vxlan相比,它能够为你提供更好的性能,而且能够进行扩展而无需担忧。
Kube-Router:它经过使用BGP和路由,以及支持LVS/IPVS,来提供更好的性能(这与Calico相似)。但Calico比它更为成熟。
云提供商解决方案:一些云提供商提供了本身的网络解决方案,这些方案的好坏须要根据具体状况来肯定,这里没法一律而论。值得一提的是,Rancher的一个开源项目Submariner。它支持多个Kubernetes集群之间的跨集群网络链接,而且建立了必要的隧道和路径,能为部署在须要相互通讯的多个Kubernetes集群中的微服务提供网络链接。
在这样的状况下,推荐使用canal或带有vxlan的flannel,由于它们十分容易且有效。可是正如我以前所提到的,vxlan速度很慢,随着应用程序的不断发展,它将耗费大量资源。可是对于刚刚起步的项目而言,这绝对是最简单的方法。
这其实是作出决定而不是根本不作出决定的问题。若是你没有特定的功能要求,则能够从Flannel和vxlan开始。若是您已部署到生产环境,稍后须要一些工做以进行迁移,可是从长远来看,作出错误的决定总比彻底不作出决定要好。
有了全部这些信息,我但愿您对Kubernetes网络的工做方式有一些相关的背景和更好的了解。
原文连接:
https://dzone.com/articles/how-to-understand-and-setup-kubernetes-networking