03 - Service:服务发现与负载均衡
为什么需要 Service?
Pod 的 IP 是不固定的——Pod 重建后 IP 会变。 Service 提供:
- 稳定的访问入口(固定的 ClusterIP 和 DNS 名称)
- 负载均衡(将流量分发到后端多个 Pod)
- 服务发现(通过 DNS 名称找到服务)
┌─────────────────────────────────────────────────┐
│ │
│ Client → service-name:port │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Service │ ClusterIP: 10.96.0.100 │
│ │ (web-svc) │ DNS: web-svc.default │
│ └──────┬──────┘ │
│ │ 负载均衡 │
│ ┌──────┼──────┐ │
│ ▼ ▼ ▼ │
│ ┌─────┐┌─────┐┌─────┐ │
│ │Pod 1││Pod 2││Pod 3│ (labels: app=web) │
│ └─────┘└─────┘└─────┘ │
└─────────────────────────────────────────────────┘Service 类型
| 类型 | 说明 | 访问范围 |
|---|---|---|
| ClusterIP | 默认类型,集群内部 IP | 集群内部 |
| NodePort | 在每个节点上开放端口 | 集群外部(通过节点 IP:端口) |
| LoadBalancer | 使用云厂商负载均衡器 | 外部(云环境) |
| ExternalName | CNAME 映射到外部域名 | DNS 别名 |
ClusterIP(默认)
yaml
apiVersion: v1
kind: Service
metadata:
name: web-svc
spec:
type: ClusterIP # 可省略,默认值
selector:
app: web # 选择 labels 匹配的 Pod
ports:
- port: 80 # Service 端口
targetPort: 8080 # Pod 中容器的端口
protocol: TCP集群内部访问方式:
web-svc # 同命名空间
web-svc.default # 跨命名空间(指定 ns)
web-svc.default.svc.cluster.local # 完整 FQDNNodePort
yaml
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 节点端口(30000-32767),不指定则随机访问方式:http://<任意节点IP>:30080
LoadBalancer
yaml
apiVersion: v1
kind: Service
metadata:
name: web-lb
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 8080在阿里云 ACK 上,会自动创建 SLB(Server Load Balancer)。 在 Docker Desktop 上,LoadBalancer 会分配 localhost。
Service 工作原理
Service 通过 Label Selector 关联 Pod:
Service (selector: app=web)
│
├── Pod A (labels: app=web) ✓ 匹配
├── Pod B (labels: app=web) ✓ 匹配
├── Pod C (labels: app=api) ✗ 不匹配
└── Pod D (labels: app=web) ✓ 匹配kube-proxy 在每个节点上维护转发规则(iptables/IPVS),将到达 Service IP 的流量转发到后端 Pod。
DNS 服务发现
K8s 集群内置 CoreDNS,自动为每个 Service 创建 DNS 记录:
<service-name>.<namespace>.svc.cluster.localbash
# 在 Pod 内部测试 DNS 解析
kubectl run test --rm -it --image=busybox -- nslookup web-svc实操练习
bash
# 创建 Deployment
kubectl create deployment web --image=nginx:alpine --replicas=3
# 通过 ClusterIP Service 暴露
kubectl expose deployment web --port=80 --target-port=80
# 查看 Service
kubectl get svc web
# 通过 NodePort 暴露
kubectl expose deployment web --port=80 --target-port=80 \
--type=NodePort --name=web-nodeport
# 端口转发测试
kubectl port-forward svc/web 8080:80