Skip to content

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使用云厂商负载均衡器外部(云环境)
ExternalNameCNAME 映射到外部域名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 # 完整 FQDN

NodePort

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.local
bash
# 在 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

下一步

04 - ConfigMap 与 Secret