Service、DNS、EndpointSlice 与 port-forward

Pod IP 会变,Service 给它一个稳定电话号码

Pod 被重建后,名字和 IP 都可能变化。如果客户端直接记住 Pod IP,系统稍微滚动一次就断线。

Service 提供稳定的虚拟 IP、DNS 名称和端口,并通过 label selector 持续找到合适的 Pod。可以把它理解成公司总机:员工座位会变,但总机号码不变。

本项目每个号池创建两个 ClusterIP Service:

Service端口后端
cpa8317runtime Pod 中的 CPA 容器
cpa-manager18317同一 runtime Pod 中的 cpa-manager 容器

两个 Service 使用相同 Pod selector,但转发到不同端口。

Service 的三组端口概念

典型配置如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 8317
      targetPort: 8317
      protocol: TCP
  selector:
    app.kubernetes.io/component: runtime
    subrelay.example.com/pool: demo-pool

常见字段含义:

字段含义
portService 对客户端提供的端口
targetPort后端 Pod 实际接收流量的端口
nodePortNodePort/LoadBalancer 类型可使用的节点端口

本项目使用 ClusterIP,因此没有 nodePortporttargetPort 数值相同只是设计选择,并非 Kubernetes 要求。

ClusterIP 的边界

ClusterIP 一般只在集群网络内可达。它不会自动创建公网 IP,也不会开放宿主机端口。

这正是 Internal 模式需要的安全边界:

  • 集群内组件可以通过 Service 访问;
  • 管理员可以临时 port-forward;
  • 互联网不能直接访问它;
  • 生产外部流量必须经过共享 Gateway。

“Service 已经有 ClusterIP”不等于“我的浏览器一定能直接打开”。先确认客户端到底在集群内还是集群外。

集群 DNS 名称怎样组成

同 Namespace 中可以用短名称访问:

1
http://cpa:8317

跨 Namespace 常用完整名称:

1
<service>.<namespace>.svc:<port>

本项目给 CPA 生成的 Mihomo 地址是:

1
http://mihomo-gateway.subpool-gateway.svc:18000

可进一步写成集群域名全名:

1
mihomo-gateway.subpool-gateway.svc.cluster.local

cluster.local 是常见默认值,但实际集群域可能不同,所以应用配置常使用到 .svc 为止的名称,让搜索域补齐剩余部分。

Service 如何找到 Pod

Service controller 根据 selector 匹配 Pod,并维护 EndpointSlice。EndpointSlice 里记录真实后端地址、端口和 Ready 状态。

链路如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Service selector
匹配带标签的 Pod
EndpointSlice 记录 Pod IP 和 ready condition
集群网络规则把 Service 流量送到后端

Service 本身存在,并不能证明后端可用。应继续检查 EndpointSlice:

1
2
3
kubectl -n subpool-demo-pool get service cpa
kubectl -n subpool-demo-pool get endpointslice \
  -l kubernetes.io/service-name=cpa

若 EndpointSlice 没有 Endpoint,常见原因是 selector 不匹配、Pod 未 Ready 或 Pod 根本未创建。

本项目为什么检查 Mihomo EndpointSlice

Operator 的 ProxyGatewayReady 不只检查 mihomo-gateway Service 是否存在,还要求它至少有一个 Ready Endpoint。

这是很重要的差别:

1
2
Service 存在:有一个电话号码
Ready Endpoint 存在:至少有人能接电话

Operator 会在 subpool-gateway Namespace 中查找带有:

1
kubernetes.io/service-name=mihomo-gateway

标签的 EndpointSlice,然后检查 endpoint condition。没有 Ready Endpoint 时,ProxyGatewayReady=False

它仍没有深入验证每个上游代理或真实模型请求。这属于更高层业务健康,而非 Kubernetes Service 健康。

Pod readiness 如何影响 Service

Pod readinessProbe 成功后,Pod 才通常被视为 Ready。EndpointSlice controller 会把这个结果投影到 Endpoint condition。

因此一条常见故障链是:

1
2
3
4
5
6
应用启动失败
  → readinessProbe 失败
  → Pod NotReady
  → Endpoint 不 Ready
  → Service 没有可用后端
  → 上游调用失败

排查时不要只盯着 Service。Service 更像路由入口,真正提供响应的是后端 Pod 中的进程。

port-forward 在做什么

开发时使用:

1
kubectl -n subpool-demo-pool port-forward service/cpa 8317:8317

它让本机的 127.0.0.1:8317 临时转发到 Service 选中的后端端口。流量通道由 kubectl 与集群 API 通路维持。

它的特征是:

  • 命令运行期间才有效;
  • 终端退出或网络断开即停止;
  • 访问权限依赖 kubeconfig 和 RBAC;
  • 适合开发、诊断和 break-glass;
  • 不适合作为生产服务入口。

port-forward 成功不能证明 Gateway、DNS 和 TLS 都已配置,因为它绕过了生产外部入口链路。

两个 Service 指向同一个 Pod会不会冲突

不会。两个 Service 可以选中同一个 Pod,并把流量送往不同端口:

1
2
3
Service cpa:8317          ─┐
                           ├─> Pod runtime-0
Service cpa-manager:18317 ─┘

因为 CPA 和 cpa-manager 共享 Pod IP,但监听不同端口,所以流量能被准确送到对应进程。

NetworkPolicy 也明确允许 8317 和 18317 入站。不过允许端口不等于允许所有外部访问;是否能到达 Pod 还取决于网络路径、Service 类型和 Gateway 配置。

Service、Gateway 与 HTTPRoute 的分工

Gateway 模式的完整入站链路是:

1
2
3
4
5
6
7
客户端
  → DNS
  → Shared Envoy Gateway
  → HTTPRoute
  → cpa ClusterIP Service
  → EndpointSlice
  → runtime Pod:8317

Service 负责稳定连接后端 Pod,HTTPRoute 负责按照 hostname 等 HTTP 规则把共享 Gateway 的流量送到某个 Service。它们不是互相替代关系。

常见误区

有 Service 就一定能访问

不一定。继续检查 selector、EndpointSlice、Pod Ready 和 NetworkPolicy。

containerPort 就是对外开放端口

不是。containerPort 主要是声明容器端口;集群稳定访问依赖 Service,外部访问还需要 Gateway、LoadBalancer、Ingress 或 port-forward。

ClusterIP 可以直接从个人电脑访问

通常不可以,除非电脑本身接入了集群网络。开发场景使用 port-forward。

port-forward 是轻量生产入口

不是。它依赖一个持续运行的客户端进程,没有正式入口应有的高可用、证书、域名和流量治理能力。

有界排查清单

1
2
3
4
5
6
kubectl -n subpool-demo-pool get service cpa -o yaml
kubectl -n subpool-demo-pool get pod -o wide --show-labels
kubectl -n subpool-demo-pool get endpointslice \
  -l kubernetes.io/service-name=cpa -o yaml
kubectl -n subpool-demo-pool describe pod runtime-0
kubectl -n subpool-demo-pool get networkpolicy

把路径按“入口对象 → selector → EndpointSlice → Pod readiness → 应用端口”逐段验证,通常比反复重启 Pod 更快找到根因。

使用 Hugo 构建
主题 StackJimmy 设计