在 Kubernetes 的世界里,Pod 是脆弱的、临时的、会被频繁重建的。每次 Deployment 滚动更新、节点故障、甚至一次简单的扩容,Pod 的 IP 地址都可能发生变化。如果业务系统直接依赖 Pod IP 来通信,那么集群规模的任何风吹草动都会演变成一场连接灾难。今天我们要学习的 Service 与 Ingress,正是 K8s 用来解决”服务如何被发现”和”流量如何被接入”的两大核心抽象。掌握它们,你才算真正理解了一个应用是如何在集群中稳定对外提供服务的。

为什么需要 Service:从 Pod IP 的不稳定性说起
Pod 的 IP 是在调度时才分配的,删除重建后几乎必然改变。如果前端容器写死了后端 Pod 的 IP,那么一旦后端发生重启,前端就会拿到一个失效的地址,导致请求失败。Service 的核心价值在于:它在 Pod 集合之上提供了一层稳定的虚拟 IP(ClusterIP)和稳定的 DNS 名称,无论底层 Pod 如何变化,客户端访问的地址始终不变。
Service 通过 Label Selector 来选择它要代理的 Pod 集合。只要 Pod 携带了匹配的标签,就会被自动纳入 Service 的后端列表。当 Pod 被删除或新增时,Service 对应的 Endpoints 会自动更新,这个过程由控制器持续监听,无需人工干预。
Service 的四种类型
Kubernetes 提供了多种 Service 类型,分别面向不同的暴露场景,理解它们的差异是做好流量接入的前提。
ClusterIP:集群内部通信的默认选择
ClusterIP 是默认类型,它为 Service 分配一个仅在集群内部可达的虚拟 IP。集群内部的其他 Pod 可以通过这个 IP 或 Service 名称访问服务。这是微服务之间互相调用的最常见方式。
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: default
spec:
type: ClusterIP
selector:
app: my-app
ports:
- name: http
port: 80
targetPort: 8080
NodePort:把服务暴露到每个节点端口
NodePort 会在每个节点上开放一个固定端口(默认范围 30000-32767),把流量转发到 Service。它适合测试环境或没有云负载均衡器的场景,但生产环境直接暴露 NodePort 通常不是最佳实践。
apiVersion: v1
kind: Service
metadata:
name: my-app-nodeport
spec:
type: NodePort
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
nodePort: 30080
LoadBalancer:云环境下的一键暴露
LoadBalancer 类型依赖云厂商提供的负载均衡器,会自动创建一个外部 LB 并把流量转发到集群内部。在阿里云、腾讯云、AWS 等环境中,这是暴露服务最简单的方式之一。
apiVersion: v1
kind: Service
metadata:
name: my-app-lb
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
ExternalName:把外部服务映射进集群
ExternalName 不代理任何 Pod,而是为 Service 提供一个 CNAME 记录,把集群内部的 DNS 名称指向外部的域名。它常用于把集群依赖的外部数据库、外部 API 以统一的方式接入内部服务发现体系。
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: db.example.com
实战:创建并验证一个 Service
下面我们通过一个完整的例子,演示如何为一个 Deployment 创建 Service,并验证服务发现是否生效。
先创建一个简单的 Nginx Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-demo
spec:
replicas: 3
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
然后创建对应的 ClusterIP Service,并在集群内用 curl 验证访问是否正常:
kubectl apply -f nginx-demo.yaml
kubectl apply -f nginx-service.yaml
# 查看 Service 与 Endpoints
kubectl get svc nginx-demo -o wide
kubectl get endpoints nginx-demo
# 在集群内部验证服务发现
kubectl run curl-test --image=curlimages/curl --rm -it -- sh -c
'curl -s http://nginx-demo.default.svc.cluster.local'
Ingress:七层路由与流量接入的进阶方案
Service 解决的是四层(TCP/UDP)的稳定访问问题,但现实中的业务往往需要基于域名、路径做七层(HTTP/HTTPS)的精细化路由。例如,api.example.com 转发到 API 服务,web.example.com 转发到前端服务,同一个域名下 /v1 和 /v2 指向不同的后端版本。这些需求靠 Service 无法优雅实现,于是 Ingress 应运而生。
Ingress 本身只是一份路由规则声明,真正干活的是 Ingress Controller(如 Nginx Ingress Controller、Traefik、Kong 等)。下面是一份典型的多路径 Ingress 规则:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: api-v1
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: api-v2
port:
number: 80
这份规则的含义是:当请求到达 api.example.com 且路径以 /v1 开头时,转发到 api-v1 服务;以 /v2 开头时,转发到 api-v2 服务。借助 Ingress,我们可以用极小的成本实现灰度、多版本并行与基于域名的多租户接入。
常见问题
1. 为什么 Service 一直拿不到 Endpoints?
最常见的原因是 Service 的 selector 与 Pod 的 labels 不匹配。请仔细核对两者的大小写、键名和值,任何一个字符的差异都会导致 Endpoints 为空。
2. NodePort 端口冲突怎么办?
如果指定的 nodePort 已被其他 Service 占用,K8s 会直接报错。可以通过 kubectl get svc -A | grep NodePort 查看已占用端口,或干脆不指定 nodePort,让系统自动分配。
3. Ingress 配置了却访问不通?
优先检查 Ingress Controller 是否真的部署并监听了端口,其次确认 DNS 是否把域名解析到了 Ingress 所在节点,最后再看 Ingress 的 backend 服务名与端口是否写错。
总结
Service 与 Ingress 是 Kubernetes 流量管理的两大基石:Service 提供稳定的四层访问入口和内置的服务发现,Ingress 则在 Service 之上提供灵活的七层路由能力。理解它们的类型差异、使用场景与排错思路,是运维好一个 K8s 集群的基本功。今天的实战覆盖了从 Deployment 到 Service 再到 Ingress 的完整链路,建议你亲手在 minikube 或测试集群里跑一遍,加深对”稳定地址”与”路由规则”这两个核心概念的理解。
下期预告:下一讲我们将进入「配置管理——ConfigMap 与 Secret 实战」,学习如何把应用配置与敏感信息从镜像中解耦出来,敬请期待。
















暂无评论内容