Service 是 Kubernetes 的核心资源类型之一,通常被看作微服务的一种实现。它事实上是一种抽象:通过规则定义出由多个 Pod 对象组合而成的逻辑集合,以及访问这组 Pod 的策略。Service 关联 Pod 资源的规则要借助标签选择器完成


Service 对象的 IP 地址(可称为 ClusterIP 或 ServiceIP)是虚拟 IP 地址,由 Kubernetes 系统在 Service 对象创建时在专用网络(Service Network)地址中自动分配或由用户手动指定,并且在 Service 对象的生命周期中保持不变。Service 基于端口过滤到达其 IP 地址的客户端请求,并根据定义将请求转发至其后端的 Pod 对象的相应端口之上,因此这种代理机制也称为“端口代理”或四层代理,工作于 TCP/IP 协议栈的传输层


Service 并不直接连接至 Pod 对象,它们之间还有一个中间层——Endpoints 资源对象,该资源对象是一个由 IP 地址和端口组成的列表,这些 IP 地址和端口则来自由 Service 的标签选择器匹配到的 Pod 对象


一个 Service 对象对应于工作节点内核之中的一组 iptables 或/和 ipvs 规则,这些规则能够将到达 Service 对象的 ClusterIP 的流量调度转发至相应 Endpoint 对象指向的 IP 地址和端口之上内核中的 iptables 或 ipvs 规则的作用域仅为其所在工作节点的一个主机,因而生效于集群范围内的 Service 对象就需要在每个工作节点上都生成相关规则,从而确保任一节点上发往该 Service 对象请求的流量都能被正确转发。


每个工作节点的 kube-proxy 组件通过 API Server 持续监控着各 Service 及其关联的 Pod 对象,并将 Service 对象的创建或变动实时反映至当前工作节点上相应的 iptables 或 ipvs 规则上


Service 对象的 ClusterIP 事实上是用于生成 iptables 或 ipvs 规则时使用的 IP 地址,它仅用于实现 Kubernetes 集群网络内部通信,且仅能够以规则中定义的转发服务的请求作为目标地址予以响应,这也是它之所以被称作虚拟 IP 的原因之一。kube-proxy 把请求代理至相应端点的方式有 3 种:userspace、iptables 和 ipvs


userspace 代理模型,kube-proxy 负责跟踪 API Server 上 Service 和 Endpoints 对象的变动(创建或移除),并据此调整 Service 资源的定义。对于每个 Service 对象,它会随机打开一个本地端口(运行于用户空间的 kube-proxy 进程负责监听),任何到达此代理端口的连接请求都将被代理至当前 Service 资源后端的各 Pod 对象,至于哪个 Pod 对象会被选中则取决于当前 Service 资源的调度方式,默认调度算法是轮询(round-robin)。


iptables 代理模型,客户端发来请求将直接由相关的 iptables 规则进行目标地址转换(DNAT)后根据算法调度并转发至集群内的 Pod 对象之上,而无须再经由 kube-proxy 进程进行处理。


ipvs 代理模型,kube-proxy 跟踪 API Server 上 Service 和 Endpoints 对象的变动,并据此来调用 netlink 接口创建或变更 ipvs(NAT)规则,它与 iptables 规则的不同之处仅在于客户端请求流量的调度功能由 ipvs 实现,余下的其他功能仍由 iptables 完成。


ipvs 代理模型中 Service 的服务发现和负载均衡功能均基于内核中的 ipvs 规则实现。类似于 iptables,ipvs 也构建于内核中的 netfilter 之上,但它使用 hash 表作为底层数据结构且工作于内核空间,因此具有流量转发速度快、规则同步性能好的特性,适用于存在大量 Service 资源且对性能要求较高的场景。ipvs 代理模型支持 rr、lc、dh、sh、sed 和 nq 等多种调度算法。


Service 资源都可统一根据其工作逻辑分为 ClusterIP、NodePort、LoadBalancer 和 ExternalName 这 4 种类型。


通过将 Service 映射至由 externalName 字段的内容指定的主机名来暴露服务,此主机名需要被 DNS 服务解析至 CNAME 类型的记录中。此种类型不是定义由 Kubernetes 集群提供的服务,而是把集群外部的某服务以 DNS CNAME 记录的方式映射到集群内,从而让集群内的 Pod 资源能够访问外部服务的一种实现方式,这种类型的 Service 没有 ClusterIP 和 NodePort,没有标签选择器用于选择 Pod 资源,也不会有 Endpoints 存在


若需要将 Service 资源发布至集群外部,应该将其配置为 NodePort 或 Load-Balancer 类型,而若要把外部的服务发布于集群内部供 Pod 对象使用,则需要定义一个 ExternalName 类型的 Service 资源