kubernetes,简称K8s,是用8代替8个字符"ubernete"而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。
传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。
新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进行迁移。
容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间成一对一关系也使容器有更大优势,使用容器可以在build或release 的阶段,为应用创建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,这使得从研发到测试、生产能提供一致环境。类似地,容器比虚机轻量、更"透明",这更便于监控和管理。
Kubernetes网络一直是一个非常复杂的主题。本文将介绍Kubernetes实际如何创建网络以及如何为Kubernetes集群设置网络。
许多Kubernetes部署指南中包含了在K8S部署中部署Kubernetes网络CNI的说明。但是如果你的K8S集群已经运行,并且尚未部署任何网络,那么部署网络就像在K8S上运行其提供的配置文件一样简单(对于大多数网络和基本用例而言)。例如,要部署flannel:
这样,从网络的角度来看,K8S已经可以使用。为了测试一切是否正常,我们创建了两个Pod。
这将创建两个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路由到其中。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。