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 只能在集群内部访问,最直接的验证方式是启动一个临时 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 访问问题。七、关键参数速查
| 字段 | 作用 | 示例 |
|---|---|---|
| type | Service 类型 | ClusterIP |
| selector | 匹配后端 Pod 标签 | app: web |
| port | Service 暴露端口 | 80 |
| targetPort | 容器监听端口 | 80 或 http |
| name | 多端口时必填且唯一 | http / metrics |
| clusterIP | 虚拟 IP,None 表示 Headless | 10.96.143.22 |
掌握以上内容后,ClusterIP 的创建、访问、解析与端口映射就形成了完整闭环。后续的 NodePort、LoadBalancer 与 Ingress,本质上都是在这个稳定 VIP 之上叠加不同层次的入口能力。