zl程序教程

您现在的位置是:首页 >  后端

当前栏目

《Kubernetes网络权威指南》读书笔记 | 找到你并不容易:从集群内访问服务

Kubernetes网络集群服务 指南 访问 找到 读书笔记
2023-09-14 09:09:06 时间

书籍来源:《Kubernetes网络权威指南:基础、原理与实践》

一边学习一边整理读书笔记,并与大家分享,侵权即删,谢谢支持!

附上汇总贴:《Kubernetes网络权威指南》读书笔记 | 汇总_COCOgsta的博客-CSDN博客


Kubernetes里服务(Service)的概念即通常说的微服务(micro-service)。

什么是Kubernetes的Service呢?在Kubernetes中,用户可以为任何Kubernetes资源分配成为Labels(标签)的任意键值。Kubernetes使用Labels将多个相关的Pod组合成一个逻辑单元,称为Service。

Service具有稳定的IP地址和端口,并会在一组匹配的后端Pod之间提供负载均衡,匹配的条件就是Service的Label Selector与Pod的Labels相匹配。

3.5.1 Kubernetes Service详解

Kubernetes的Service代表的是Kubernetes后端服务的入口,它主要包含服务的访问IP(虚IP)和端口,因此工作在L4。

被Service选中的Pod,当它们运行且能对外提供服务后,Kubernetes的Endpoints Controller会生成一个新的Endpoints对象,记录Pod的IP和端口。

Service的访问IP和Endpoints/Pod IP都会在Kubernetes的DNS服务器里存储域名和IP的映射关系,因此用户可以在集群内通过域名的方式访问Service和Pod。Service与Endpoints的关系如图3-16所示。

图3-16 Service与Endpoints的关系

Kubernetes会从集群的可用服务IP池中为每个新创建的服务分配一个稳定的集群内访问IP地址,称为Cluster IP。Kubernetes还会通过添加DNS条目为Cluster IP分配主机名。Cluster IP和主机名在集群内是独一无二的,并且在服务的整个生命周期内不会更改。

用户不用担心服务出现单点故障问题,Kubernetes会尽可能均匀地将流量分布到在多个节点上运行的Pod,因此一个或若干个(但不是所有)节点的服务中断情况不会影响服务的整体可用性。

Kubernetes使用Kube-proxy组件管理各服务与之后端Pod的连接,该组件在每个节点上运行。Kube-proxy落实到主机上就是iptables/IPVS等路由规则。访问服务的IP会被这些路由规则直接DNAT到Pod IP,然后走底层容器网络送到对应的Pod。

一个最简单的Kubernetes Service的定义如下所示:

其中,spec.ClusterIP就是Service的(其中一个)访问IP,俗称虚IP(Virtual IP,即VIP)。如果用户不指定的话,那么Kubernetes Master会自动从一个配置范围内随机分配一个。

该Service的selector是app:nginx,即匹配那些被打上app=nginx标签的Pod。

spec.ports[].port是Service的访问端口,而与之对应的spec.ports[].targetPort是后端Pod的端口,Kubernetes会自动做一次映射(80->8080)。

当Service的后端Pod准备就绪后,Kubernetes会生成一个新的Endpoints对象,而且这个Endpoints对象和Service同名。一个Endpoints的定义如下所示:

用户可以通过以下命令得到这个Endpoints对象:

其中,subsets[].addresses[].ip是后端Pod的IP,subsets[].ports是后端Pod的端口,与Service的targetPort对应。

3.5.2 Service的三个port

先来看一个最简单的Service定义:

Service的几个port的概念很容易混淆,它们分别是port、targetPort和NodePort。

port表示Service暴露的服务端口,也是集群内部客户端访问用的端口。

NodePort是提供给集群外部访问Service入口的一种方式(另一种方式是Load Balancer)。

targetPort是应用程序实际监听Pod内流量的端口,从port和NodePort上到来的数据,最终经过Kube-proxy流入后端Pod的targetPort进入容器。

在配置服务时,可以选择定义port和targetPort的值重新映射其监听端口,这也被称为Service的端口重映射。

3.5.3 你的服务适合哪种发布形式

  1. Cluster IP

Kubernetes Service有几种类型:Cluster IP、Load Balancer和NodePort。其中,Cluster IP是默认类型。一个典型的Cluster IP类型的Service如下:

Cluster IP主要在每个node节点使用iptables,将发向Cluster IP对应端口的数据转发到后端Pod中。针对iptables的更详细分析见后面章节。

  1. Load Balancer

Load Balancer(简称LB)类型的Service需要Cloud Provider的支持。Kubernetes原生支持的Cloud Provider有GCE和AWS,因此和不同云平台的网络方案耦合较大,而且只能在特定的云平台上使用,局限性也较大。

创建Service时,通过配置serviceSpec.loadBalancerSourceRanges字段,可以限制哪些IP地址范围可以访问集群内的服务。Kube-proxy会配置该节点的iptables规则。以拒绝与指定loadBalancerSourceRanges不匹配的所有流量。

一个Load Balancer类型Service的定义如下所示:

查看这个服务的细节:

内部可以使用Cluster-IP加端口来访问该服务。在我们这个例子中就是19.97.121.42:8086。

外部可以使用EXTERNAL-IP加端口来访问该服务,这是一个云供应商提供的负载均衡器IP,在我们这个例子中就是10.13.242.236:8086。

Load Balancer类型Service的原理如图3-17所示。

图3-17 Load Balancer类型Service的原理

  1. NodePort

NodePort类似Service,被称为乞丐版的Load Balancer类型Service。

NodePort为Service在Kubernetes集群的每个节点上分配一个真实的端口,即NodePort。集群内/外部可基于集群内任何一个节点的IP:NodePort的形式访问Service。NodePort默认端口范围是30000-32767,可以修改API Server的--service-node-port-range的参数自行定义。

一个典型的NodePort类型Service如下:

使用kubectl describe service可以看到,虽然Service的类型是NodePort,但是Kubernetes依然为其分配了一个Cluster IP,输出如下:

以上输出的IP字段即该Service的Cluster IP。

NodePort的实现机制是Kube-proxy会创建一个iptables规则,所有访问本地NodePort的网络包都会被直接转发至后端Port。

NodePort是解决服务对外暴露的最简单方法,但NodePort的问题集中体现在性能和可对宿主机端口占用方面。一旦服务多起来,NodePort在每个节点上开启的端口会变得非常庞大且难以维护。

3.5.4 Kubernetes Service发现

Kubernetes Service创建好后,如何使用它,即如何进行服务发现呢?

在Kubernetes中使用域名服务,即假设Service(my-svc)在namespace(my-ns)中,暴露名为http的TCP端口,那么在Kubernetes的DNS服务器中会生成两种记录,分别是A记录:域名(my-svc.my-ns)到Cluster IP的映射和SRV记录,例如_http._tcp.my-svc.my-ns到一个http端口号的映射。

3.5.5 特殊的无头Service

所谓的无头(headless)Service即没有selector的Service。

在任何场景中,都能够定义没有selector的Service:

这个Service没有selector,就不会创建相关的Endpoints对象。可以手动将Service映射到指定的Endpoints:

访问没有selector的Service,与有selector的Service的原理相同。请求将被路由到用户定义的Endpoint(该示例中为1.2.3.4:9376)。

3.5.6 怎么访问本地服务

当访问NodePort或Load Balancer类型Service的流量到达时,流量可能会被转发到其他节点上的Pod。这可能需要额外一跳的网络。如果要避免额外的跃点,则用户可以指定流量必须转到最初接收流量的节点上的Pod。

要指定流量必须转到同一节点上的Pod,可以将serviceSpec.externalTrafficPolicy设置为Local(默认是Cluster):

将externalTrafficPolicy设置为Local时,负载平衡器仅将流量发送到具有属于服务的正常Pod所在的节点。