Service与Ingress
Ingress
Ingress 是 Kubernetes 中的一个原生 API 资源对象,用于管理集群外部对集群内部服务的 HTTP 和 HTTPS 访问。它提供了一种声明式的路由规则配置方式,根据主机名(host)、路径(path)等规则,将外部流量路由到不同的后端 Service,从而实现负载均衡、SSL/TLS 终止、基于名称的虚拟主机等功能。
- Ingress 实际上就是七层代理,而 service 是基于 iptables 或 ipvs 实现的四层代理。
核心概念
- Ingress Controller:负责读取 Ingress 中的配置,然后转换成自身的配置(每一次更新 Ingress 的配置 都会在 Ingress Controller 生成相应的转发规则)
- 实际实现路由的组件(如 NGINX、Traefik、HAProxy 等),它监视 Ingress 资源的变化,并配置反向代理(如负载均衡器)来处理外部请求。集群中必须部署至少一个 Ingress Controller,Ingress 才能生效。
- 常见 Ingress Controller:
- NGINX Ingress Controller(最流行,但官方已宣布将于 2026 年 3 月后停止维护)。
- Traefik、HAProxy、Istio 等。
- 云厂商特定:如 GKE 的 Google Cloud Load Balancer、AWS ALB Ingress Controller。
- Ingress 资源:定义路由规则的 YAML 对象,仅描述“应该如何路由”,本身不处理流量。
- IngressClass:用于指定使用哪个 Controller 处理特定的 Ingress 资源,避免冲突。
相比其他暴露服务的方式(如 NodePort 或 LoadBalancer 类型 Service),Ingress 的优势在于:
- 使用单个外部 IP 暴露多个服务,节省资源。
- 支持高级路由(如路径重写、流量拆分)。
- 便于统一管理域名和 TLS 证书。
注意事项与现状(截至 2025 年底):
- Kubernetes 官方已冻结 Ingress API 的开发,不再添加新功能,并推荐迁移到更现代的 Gateway API(更灵活、支持更多协议和高级特性)。
- Ingress 仍被广泛使用,但对于新项目,建议优先考虑 Gateway API。
- 参考官方文档:https://kubernetes.io/docs/concepts/services-networking/ingress/
Ingress 是 Kubernetes 中暴露 HTTP 服务的最常用方式之一,适合大多数 Web 应用场景。如果需要更复杂的流量管理(如服务网格),可结合 Istio 等工具使用。
参考文档:
Ingress 数据流
- 客户端访问 Ingress Controller 的 Service(NodePort / LoadBalancer)
- Ingress Controller 的 Service,会转发到 Ingress Controller 的 Pod
- Ingress Controller Pod 监视 Ingress 资源和后端 Service 的 Endpoints/EndpointSlices。并根据主机名(host)和路径(path)匹配规则,决定转发到哪个后端 Service。
- 最后直接将数据报文发送到后端 Pod 而不再经由后端服务的 Service
- 转发到后端 Pod 大多数主流 Ingress Controller(如 NGINX Ingress Controller、Traefik)会直接将流量发送到后端 Pod 的 IP(通过监视 Endpoints API 获取),而非经过后端 Service 的 ClusterIP(VIP)和 kube-proxy。
- 原因:这样可以绕过 kube-proxy 的 L4 负载均衡,支持更高级的 L7 特性(如基于 cookie 的 session affinity、自定义负载均衡算法、正则路径等)。
- 这不会丢失健康检查或端点更新:Controller 实时监视 Endpoints,避免将流量发送到不健康的或已终止的 Pod。
- 官方 NGINX Ingress 文档明确说明:“The Ingress-Nginx Controller does not use Services to route traffic to the pods. Instead it uses the Endpoints API in order to bypass kube-proxy…”
- Traefik 类似:“Traefik automatically requests endpoint information… will connect directly to the endpoints (pods)"。
- 这种设计减少了不必要的跳转(少一次 NAT 和 kube-proxy 处理),提升了性能,尤其在高流量场景下。
Ingress 语法
apiVersion: networking.k8s.io/v1 # 资源所属的API群组和版本,k8s1.19 后 ingress 才为稳定版v1
kind: Ingress # 资源类型标识符
metadata: # 元数据
name <string> # 资源名称
annotations: # 资源注解
xxx
namespace <string> # 名称空间
spec:
ingressClassName <string> # ingress类名称,用于指定适配的控制器
rules <[]Object> # Ingress规则列表
- host <string> # 可选字段,虚拟主机的FQDN,支持“*”前缀通配;如未指定host,则只能使用IP进行访问
http <Object>
paths <[]Object> # 虚拟主机PATH定义的列表,由path和backend组成;每个路径都有一个由 serviceName 和 servicePort 定义的关联后端。
- path <string> # 流量匹配的HTTP PATH,必须以/开头
pathType <string> # 必选字段,支持Exact、Prefix和ImplementationSpecific
backend <Object> # 匹配到的流量转发到的目标后端
resource <Object> # 引用的同一名称空间下的资源,与service互斥
service <object> # 关联的后端Service对象
name <string> # 后端Service的名称
port <object> # 后端Service上的端口对象
name <string> # 端口名称
number <integer> # 端口号
tls <[]Object> # TLS配置,用于指定上rules中定义的哪些host需要工作HTTPS模式
- hosts <[]string> # 使用同一组证书的主机名称列表
secretName <string> # 保存于数字证书和私钥信息的secret资源名称
defaultBackend <Object> # 默认backend的定义,可嵌套字段及使用格式跟rules字段中的相同
resource <Object>
service <Object>.spec.rules[].host
| host | host 头部 | 匹配与否? |
|---|---|---|
*.foo.com |
bar.foo.com |
基于相同的后缀匹配 |
*.foo.com |
baz.bar.foo.com |
不匹配,通配符仅覆盖了一个 DNS 标签 |
*.foo.com |
foo.com |
不匹配,通配符仅覆盖了一个 DNS 标签 |
.spec.rules[].http.paths[].pathType
在 Kubernetes Ingress(API 版本 networking.k8s.io/v1)中,每个路径(path)必须显式指定 pathType,否则资源验证会失败。自 Kubernetes 1.18 引入该字段以来,支持以下 三种 类型:
| pathType | 描述 | 匹配行为示例(假设 path: /foo) |
|---|---|---|
| Exact | 精确匹配 URL 路径,大小写敏感。必须完全一致,不考虑尾部斜杠差异。 | 匹配:/foo不匹配: /foo/、/FOO、/foo/bar |
| Prefix | 前缀匹配,按 / 分割路径逐元素匹配,大小写敏感。尾部斜杠被忽略,不支持子字符串匹配。 |
匹配:/foo、/foo/、/foo/bar、/foo/bar/baz不匹配: /foobar、/foo/barbaz |
| ImplementationSpecific | 匹配行为由具体的 IngressClass(Controller)决定。可视为 Prefix/Exact 的变体,或自定义(如支持正则)。许多 Controller 默认等同于 Prefix。 | 取决于 Controller(如 NGINX 可结合注解支持正则匹配) |
匹配优先级规则
- 最长路径优先(例如
/foo/bar优先于/foo)。 - 长度相同时,Exact 优先于 Prefix。
- ImplementationSpecific 的优先级取决于具体实现。
Ingress YAML 示例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1 # 示例注解,根据 Controller 不同而变
spec:
rules:
- host: example.com
http:
paths:
- path: /app1
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
- path: /app2
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80
tls: # 可选:TLS 配置
- hosts:
- example.com
secretName: example-tls-secretTraefik
部署
# 添加官方 Traefik Helm repo
helm repo add traefik https://traefik.github.io/charts
helm repo update
# 创建专用 namespace(推荐)
kubectl create namespace traefik
# 拉取 chart(为后续升级提速)
helm pull traefik/traefik --version 35.2.0
# 导出并修改 values 文件
helm show values traefik/traefik --version 35.2.0 > values-traefik-35.2.0.yaml
# 安装/升级
helm upgrade --install traefik traefik/traefik \
--version 35.2.0 \
--namespace traefik \
-f values-traefik-35.2.0.yamlService
Endpoints
Endpoints 资源代表了 Service 后端实际运行的 Pod 的网络地址(IP 地址和端口)。当一个 Service 被创建时,Kubernetes 会根据 Service 的选择器(selector)来查找匹配的 Pod,并将这些 Pod 的 IP 和端口信息填充到 Endpoints 对象中。它是 手动管理服务后端 的方式之一,但在大多数情况下,EndpointSlice 资源和 Endpoint 控制器会自动创建和管理它。
apiVersion: v1
kind: Endpoints
metadata:
name: my-service # Endpoints对象的名称通常与它关联的Service名称相同
subsets:
- addresses: # 匹配的后端Pod的IP地址列表
- ip: "10.244.0.4"
- ip: "10.244.0.5"
ports: # 匹配的后端Pod的端口列表
- port: 8080
name: http
protocol: TCPEndpointSlice
EndpointSlice 是一种更具可扩展性和效率的 Endpoints 替代品。它旨在解决在拥有大量 Pod 后端的 Service 中,单个 Endpoints 对象变得非常大而导致的性能问题。每个 EndpointSlice 对象通常只包含少量的 Endpoint(最多约 100 个),这意味着对于一个大型 Service,可能会有多个 EndpointSlice 对象,每个对象包含一部分后端信息。这使得网络传输和客户端(如 kube-proxy)处理更新时更加高效。
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: my-service-abcxyz # 自动生成的名称,通常包含Service名称
labels:
kubernetes.io/service-name: my-service # 关联的Service名称
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 8080
endpoints: # 包含的具体端点列表
- addresses: # 后端Pod的IP地址
- "10.244.0.6"
conditions: # 端点的状态信息
ready: true
serving: true
hostname: pod-name-a
- addresses:
- "10.244.0.7"
conditions:
ready: false # 示例:这个Pod尚未准备好接收流量
serving: true
hostname: pod-name-bEndpoints 与 EndpointSlice 的区别
K8s(Kubernetes)中的 Endpoints 和 EndpointSlice 都是用来跟踪 Service 对应后端 Pods 网络地址信息的对象,但 EndpointSlice 是为了解决大规模集群中 Endpoints 对象的扩展性问题而引入的。
| 特性 | Endpoints | EndpointSlice |
|---|---|---|
| 引入时间 | 早期(v1 API) | v1.17 引入,v1.21 默认启用 |
| 结构 | 单个对象,包含所有后端 Pod 地址和端口的完整列表。 | 分片 的对象,每个对象只包含一部分后端 Pod 地址和端口。 |
| 可扩展性 | 差:当 Service 后端 Pod 数量巨大时(如数千个),单个 Endpoints 对象会变得非常大,导致: 1. etcd 压力:对象更新、存储和监控(watch)消耗大量资源。 2. 网络延迟:大型对象在网络传输和 API Server 与客户端之间同步时效率低下。 | 好:将大型 Service 的 Endpoint 信息分割成多个较小的 Slice,显著减少单个对象的大小,从而: 1. 降低 etcd 压力:更新只影响必要的 Slice。 2. 提高性能:减少网络开销和处理时间。 |
| 主要用途 | 早期和小型集群。 | 推荐用于大规模集群,是 Kube-proxy、Ingress Controller 等组件获取 Service 后端信息的首选方式。 |
| 控制器 | 由 Endpoint Controller 维护。 | 由 EndpointSlice Controller 维护。 |
Endpoints (传统方式)
-
格式举例 (简化):
{ "apiVersion": "v1", "kind": "Endpoints", "metadata": { "name": "my-service" }, "subsets": [ { "addresses": [ {"ip": "10.0.0.1"}, {"ip": "10.0.0.2"}, // ... 几千个 IP ], "ports": [ {"port": 8080} ] } ] } -
问题所在: 想象一个 Service 有 3000 个 Pod 后端。任何一个 Pod 的状态变化(例如重启、IP 变化)都会导致这个包含 3000 个地址的 巨大 Endpoints 对象被 完全替换,给 API Server、etcd 和所有监视它的组件(如 Kube-proxy)带来巨大的负担。
EndpointSlice (现代方式)
-
设计理念: 分而治之。一个 Service 的后端地址不再存储在一个对象中,而是分散存储在多个 EndpointSlice 对象中。
-
分片规则: 每个 EndpointSlice 默认最多存储大约 100 个 Endpoints (可以配置)。如果一个 Service 有 3000 个 Pod,它将会有大约 30 个 EndpointSlice 对象。
-
格式举例 (简化):
// EndpointSlice 1 of 30 for 'my-service' { "apiVersion": "discovery.k8s.io/v1", "kind": "EndpointSlice", "metadata": { "name": "my-service-abcde", "labels": { "kubernetes.io/service-name": "my-service" } }, "addressType": "IPv4", "endpoints": [ {"addresses": ["10.0.0.1"], "targetRef": ...}, {"addresses": ["10.0.0.2"], "targetRef": ...}, // ... 最多约 100 个 endpoints ], "ports": [ {"port": 8080} ] } -
优势: 当 Pod 状态发生变化时,只需要更新或替换包含该 Pod 的 小型 EndpointSlice 对象,而不是整个 Service 的 Endpoints 列表。这极大地提高了大规模集群的性能和可扩展性。
总结:EndpointSlice 是对 Endpoints 机制的优化升级。
对于集群内需要获取 Service 后端地址信息的组件(如 Kube-proxy),它们现在主要通过监视 EndpointSlice 对象来获取信息,这让 Kubernetes 在处理拥有大量后端 Pod 的 Service 时更高效、更具弹性。