3. ClusterIP Service实战

ClusterIP 是 Kubernetes 中最基础、最常用的 Service 类型。它为一组 Pod 提供一个仅集群内部可达的虚拟 IP(VIP),调用方只需访问这个稳定地址,无需关心后端 Pod 的 IP 变化与副本数量。理解 ClusterIP 的关键在于三点:标签选择器如何绑定后端 Pod、kube-proxy 如何把 VIP 流量转发到 Endpoint、DNS 如何把服务名解析成 VIP。本节围绕一个可复现的示例,完整走通创建、访问、解析、端口映射与多端口配置。

一、准备后端工作负载

Service 本身不运行进程,它依赖标签选择器找到 Pod。先创建一个 Deployment,运行两个副本的 Nginx,并打上 app=web 标签,容器监听 80 端口。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80

应用后确认 Pod 就绪:kubectl get pods -l app=web -o wide。此时每个 Pod 都有自己的 IP,例如 10.244.1.7 与 10.244.2.9。这些 IP 会随重建而变化,因此不能作为稳定访问入口。

二、创建 ClusterIP Service

下面定义一个名为 web-svc 的 ClusterIP Service,选择器与 Deployment 的标签一致,port 是 Service 对外暴露的端口,targetPort 是容器实际监听的端口。

apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP

执行 kubectl apply -f web-svc.yaml 后查看:

kubectl get svc web-svc
NAME      TYPE        CLUSTER-IP     PORT(S)   AGE
web-svc   ClusterIP   10.96.143.22   80/TCP    8s

kubectl get endpoints web-svc
NAME      ENDPOINTS                         AGE
web-svc   10.244.1.7:80,10.244.2.9:80       8s

这里有两个判断依据:CLUSTER-IP 不为 None,说明分配了虚拟 IP;ENDPOINTS 列出了两个 Pod 地址,说明选择器成功匹配。如果 ENDPOINTS 为空,通常是标签不匹配或 Pod 未就绪,应先排查这两点,而不是怀疑 Service 定义本身。

ClusterIP Service 流量与解析路径 集群内客户端 Pod curl web-svc:80 或 curl 10.96.143.22:80 CoreDNS 解析 web-svc → 10.96.143.22 web-svc.default.svc.cluster.local ClusterIP VIP 10.96.143.22:80 kube-proxy 规则转发 Endpoints 列表 10.244.1.7:80 / 10.244.2.9:80 Pod A 10.244.1.7:80 Pod B 10.244.2.9:80

三、集群内访问验证

ClusterIP 只能在集群内部访问,最直接的验证方式是启动一个临时 Pod 发起请求:

kubectl run curl-test --rm -it --image=curlimages/curl -- sh
# 进入容器后执行
curl -s -o /dev/null -w "%{http_code}\n" http://web-svc
curl -s -o /dev/null -w "%{http_code}\n" http://10.96.143.22

预期返回 200。多次请求会看到流量在 Pod A 与 Pod B 之间轮转,这是 kube-proxy 默认的随机/轮询转发效果。若返回超时,先确认 kubectl get endpoints web-svc 是否有地址;若返回 404 或连接被拒,则检查 targetPort 是否与容器实际监听端口一致。

四、DNS 解析验证

Kubernetes 为每个 Service 自动创建 DNS 记录。在同一个命名空间内,直接用服务名即可;跨命名空间需带上命名空间,完整格式为 <service>.<namespace>.svc.cluster.local。

kubectl run dns-test --rm -it --image=busybox:1.36 -- sh
nslookup web-svc
nslookup web-svc.default.svc.cluster.local

解析结果应指向 10.96.143.22。若解析失败,检查 CoreDNS Pod 是否运行、客户端 Pod 的 /etc/resolv.conf 中 nameserver 是否指向 kube-dns 的 ClusterIP。注意:DNS 返回的是 VIP,不是 Pod IP,这是 ClusterIP 与 Headless Service 的重要区别。

五、端口映射:port 与 targetPort 的差异

端口映射是初学者最容易混淆的地方。port 是 Service 暴露的端口,targetPort 是后端容器监听的端口,两者可以不同。例如把 Service 暴露在 8080,转发到容器的 80:

ports:
- name: http
  port: 8080
  targetPort: 80

此时集群内访问 http://web-svc:8080 才能命中,访问 80 会失败。若 targetPort 省略,默认等于 port;若写成字符串,还可以引用容器端口的名称(如 targetPort: http),这在多端口场景下更清晰。

六、多端口配置

当一个 Pod 同时提供 HTTP 与指标端口时,Service 需要声明多个端口,且每个端口必须有唯一的 name。以下示例暴露 80(HTTP)与 9113(指标):

apiVersion: v1
kind: Service
metadata:
  name: web-multi
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
  - name: http
    port: 80
    targetPort: 80
  - name: metrics
    port: 9113
    targetPort: 9113

验证时分别访问两个端口:curl http://web-multi:80 与 curl http://web-multi:9113/metrics。多端口 Service 的 DNS 记录仍然只有一个服务名,端口区分靠调用方指定。若两个端口重名,API Server 会直接拒绝创建。

排查顺序建议:先看 kubectl get endpoints 是否有后端地址,再看 kubectl describe svc 的 Port 与 TargetPort 是否匹配,最后用临时 Pod 验证 DNS 与连通性。这三步能覆盖绝大多数 ClusterIP 访问问题。

七、关键参数速查

字段作用示例
typeService 类型ClusterIP
selector匹配后端 Pod 标签app: web
portService 暴露端口80
targetPort容器监听端口80 或 http
name多端口时必填且唯一http / metrics
clusterIP虚拟 IP,None 表示 Headless10.96.143.22

掌握以上内容后,ClusterIP 的创建、访问、解析与端口映射就形成了完整闭环。后续的 NodePort、LoadBalancer 与 Ingress,本质上都是在这个稳定 VIP 之上叠加不同层次的入口能力。