在Kubernetes中,Service是用于将运行在一组Pod上的应用程序公开为网络服务的抽象概念。Service不但为这组Pod提供统一的DNS名称,还让Pod之间实现了负载均衡。本文介绍Kubernetes Service的原理、注意事项,以及Service类型选型建议。
基本概念
Service类型
名称 | 描述 | 适用场景 | 计费说明 |
默认的服务类型。ClusterIP分配给服务的是一个只能在集群内部访问的虚拟IP。 | 只需要在集群内部进行服务间的通信,不需要将服务暴露给集群外部。 例如,集群中部署的前端应用Pod需要访问同一集群中部署的后端数据库,后端数据库可以作为ClusterIP运行。 | 不计费。 | |
NodePort会在集群中的节点上开放端口,从而允许从集群外部通过 | 需要临时或低流量的应用时,需要从外网暴露一个端口。 例如,在测试环境中,当您部署调试一个Web应用服务时,可以使用NodePort运行。相较于LoadBalancer模式,不提供跨节点负载均衡能力,流量只会发送到一个节点并很容易达到资源瓶颈。 | 不计费。若需要实现公网访问,需要为节点绑定EIP。关于EIP的计费说明,请参见计费概述。 | |
LoadBalancer类型基于NodePort增加了一个外部负载均衡器,使外部流量能够平滑地分发到集群中的多个Pod上。Service会自动提供一个外部IP,客户端可通过此IP访问服务。该服务既支持在OSI模型的第四层(传输层)处理TCP/UDP类型的流量,也可以扩展至第七层(应用层),进行HTTP/HTTPS流量管理。 | 在公共云上运行应用且需要提供一个稳定的、易于管理的对外入口。 例如,生产环境中需要从互联网访问的公共服务,需要承受大量的外部流量并保证高可用性,例如Web应用、API服务等。 | 负载均衡实例将产生费用请参见 | |
ExternalName | ExternalName类型的Service会在集群中将一个内部服务名称映射到一个外部域名。这种映射使得集群内的Pod可以通过Service Name来访问外部域名。 | 集群需要访问暴露在公共域名下的服务。 例如,当您的应用Pod需要访问外部的数据库域名时,可以使用ExternalName将域名映射到集群内部的Service Name上,使得集群内部可以直接通过Service Name进行访问。 | 不计费。 |
Headless Service | Headless Service指没有虚拟IP的服务。访问后端Pod时,服务的DNS查询会直接返回Pod的IP地址列表,而不是单一的服务IP。Headless Service可以直接发现并连接到特定的Pod。 | 应用需要直接与后端的具体Pod进行通信(而不是通过一个代理或负载均衡器)。 例如,当您部署了有状态应用ClickHouse数据库服务,可以使用Headless Service,使得应用Pod可以直接访问每个ClickHouse Pod,并且均衡地读取数据或针对性地写入数据,提升数据处理的效率。 | 不计费。 |
Service原理
ClusterIP
创建与分配
当您在ACK集群中创建一个ClusterIP类型的Service时,集群控制面会从预定义的Service网段为该Service分配一个虚拟IP地址,这个地址被称为ClusterIP。ClusterIP只能在集群内访问,与后端Pod的IP地址网段是隔离的。
流量转发
在集群内访问ClusterIP时,该流量会被kube-proxy捕获。kube-proxy使用iptables(或者使用IPVS)规则,使用轮询调度的方式将流量转发到Service后端的一个Pod中。
服务发现
创建ClusterIP时,CoreDNS服务中会注册一个对应的DNS记录。该DNS记录允许在集群内部通过服务的名字来解析和访问服务,格式为
服务名.命名空间.svc.cluster.local:端口
,例如nginx.default.svc.cluster.local:80
Pod标签和端点跟踪
每个Service都由一组标签选择器(Label Selector)定义,决定哪些Pod属于该Service的后端。
集群控制面会实时监控Pod的变动。当匹配Service标签选择器的Pod发生添加、更新或删除等操作时,控制面将更新Endpoint。
NodePort
创建与分配
当创建NodePort类型的Service时,除了生成一个ClusterIP来允许内部通信之外,集群还会为此Service在节点上开放一个端口,称为NodePort。此端口是在指定的端口范围(默认是30000-32767)中自动选择的。您也可以手动指定特定的端口。
流量转发
kube-proxy组件负责在每个节点上监听NodePort端口。当一个外部请求到达任意节点的NodePort时,kube-proxy负责将这个流量路由到对应的ClusterIP上,然后通过ClusterIP进一步路由到后端Pod中。
外部访问
通过节点的IP地址加上静态端口(NodePort)来访问,格式为
<NodeIP>:<NodePort>
,作为外部的访问地址。
LoadBalancer
创建与分配
当创建一个
LoadBalancer
类型的Service且未指定具体的负载均衡器时,集群控制面会自动与负载均衡服务进行交互,新建负载均衡器实例用于处理该Service的流量。更多信息,请参见通过使用已有负载均衡的服务暴露应用和通过使用自动创建负载均衡的服务公开应用。流量转发
当外部流量到达负载均衡实例的外部IP时,负载均衡实例会根据负载均衡策略将流量路由到节点上的端口,每个节点上的kube-proxy组件接收到流量后,基于iptables或IPVS规则将流量重定向到后端Pod。
配置路由和健康检查
负载均衡器自动配置监听Service YAML声明的端口,并将流量转发到集群中符合选择器条件的Pod上。同时,负载均衡器会配置健康检查机制,以确保流量只路由到健康的Pod。
外部流量策略Local和Cluster介绍
在集群中,当服务类型为LoadBalancer或NodePort时,您才可以设置外部流量策略externalTrafficPolicy
,来控制从外部网络到服务的流量路由。此策略有两种模式:Local和Cluster。不同网络插件的外部流量策略功能不同。以下介绍Terway-Eniip和Flannel网络插件的外部流量策略功能对比。
登录容器服务管理控制台,在集群列表页面单击目标集群的名称,在基本信息页签下集群信息区域可以查看集群的网络模式。
Flannel网络插件
Flannel网络插件下,流量经由节点的NodePort转发到Pod中。
Local:流量只转发给本机的Pod,即流量仅在同一个节点的Pod中进行转发。
Cluster: 流量可以转发到集群中其他节点上的Pod。
Local和Cluster两种外部流量策略详细的区别如下所示。
类别 | Local | Cluster |
负载均衡后端挂载行为 | 仅Pod所在的节点会挂载到负载均衡后端。 | 所有集群内的节点都将挂载到负载均衡的后端。 |
负载均衡配额 | 负载均衡配额消耗较少。关于负载均衡配额的详细介绍,请参见配额限制。 | 集群内所有节点都挂载到负载均衡后端,会大量消耗负载均衡配额。关于负载均衡配额的详细介绍,请参见配额限制。 |
访问负载均衡地址 | 仅Pod所在节点可以访问负载均衡地址。 | 集群内任意节点均可访问负载均衡地址。 |
Pod负载均衡 | 默认Pod之间负载不均衡。 如果您想要实现Pod之间负载均衡,需要指定策略为wrr,即为Service添加Annotation | 默认Pod之间负载均衡。 |
保留来源IP | 支持。 | 不支持。 |
会话保持 | 支持。 | 不支持。 |
适用场景 | 对需要保留客户端原始IP地址的应用程序,例如基于原始IP地址的日志记录。 | 当需要保证服务的高可用性,并且对源IP保存不敏感时,例如大型Web应用集群。 |
Terway-Eniip网络插件
Terway-Eniip网络插件下,无论是Local还是Cluster,流量直接转发到Pod中。
Local和Cluster两种外部流量策略详细的区别如下表所示。
比较项 | Local | Cluster |
负载均衡后端挂载行为 | Pod直接挂载到负载均衡后端。 | |
负载均衡配额 | 仅挂载业务Pod,负载均衡配额消耗较少。关于负载均衡配额的详细介绍,请参见配额限制。 | |
访问负载均衡地址 | 仅Pod所在节点可以访问负载均衡地址。 | 集群内任意节点均可访问负载均衡地址。 |
Pod负载均衡 | 默认Pod之间负载均衡。 | |
保留来源IP | 支持。 | |
会话保持 | 支持。 |
注意事项
在使用Service的负载均衡功能之前,建议您了解相关注意事项。详细信息,请参见Service的负载均衡配置注意事项。