Service 网络
学习目标
- 理解 Service 的作用和类型
- 掌握 kube-proxy 的工作原理
- 了解 Service 发现和负载均衡机制
核心概念
一句话解释
Service 为一组 Pod 提供稳定的访问入口和负载均衡,解决 Pod IP 不稳定的问题。
为什么需要 Service
问题:Pod IP 不稳定
Pod A (10.1.1.2) → 重启 → Pod A (10.1.1.5)
Pod B (10.1.1.3) → 扩容 → Pod B (10.1.1.6)
→ Pod C (10.1.1.7)
其他服务如何找到这些 Pod?
解决方案:Service
┌─────────────────────────────────────────┐
│ Service │
│ Name: my-service │
│ ClusterIP: 10.96.0.100 │
│ Port: 80 │
└─────────────────────────────────────────┘
↓
┌───────────┼───────────┐
↓ ↓ ↓
┌───────┐ ┌───────┐ ┌───────┐
│ Pod A │ │ Pod B │ │ Pod C │
│10.1.1.2│ │10.1.1.3│ │10.1.1.4│
└───────┘ └───────┘ └───────┘
访问 Service 的 ClusterIP → 自动负载均衡到后端 Pod
Service 类型
| 类型 | 说明 | 使用场景 |
|---|---|---|
| ClusterIP | 集群内部 IP(默认) | Pod 间通信 |
| NodePort | 在每个节点上开放端口 | 开发测试 |
| LoadBalancer | 云厂商负载均衡器 | 生产环境 |
| ExternalName | 映射到外部域名 | 访问外部服务 |
ClusterIP(默认):
┌─────────────────────────────────────────┐
│ 集群内部 │
│ ┌─────────────────────────────────────┐│
│ │ Service ││
│ │ ClusterIP: 10.96.0.100 ││
│ └─────────────────────────────────────┘│
│ ↑ 集群内部可访问 │
│ ↓ 外部无法访问 │
└─────────────────────────────────────────┘
NodePort:
┌─────────────────────────────────────────┐
│ Node │
│ ┌─────────────────────────────────────┐│
│ │ Service ││
│ │ NodePort: 30080 ││
│ └─────────────────────────────────────┘│
│ ↑ 外部通过 NodeIP:30080 访问 │
└─────────────────────────────────────────┘
LoadBalancer:
┌─────────────────────────────────────────┐
│ 云负载均衡器 │
│ Public IP │
└─────────────────────────────────────────┘
↓
┌───────────────┼───────────────┐
↓ ↓ ↓
┌───────┐ ┌───────┐ ┌───────┐
│ Node1 │ │ Node2 │ │ Node3 │
└───────┘ └───────┘ └───────┘
kube-proxy 工作原理
kube-proxy 监听 Service 和 Endpoints 变化:
1. 用户创建 Service
↓
2. kube-proxy 监听到变化
↓
3. 配置 iptables/IPVS 规则
↓
4. 流量按规则转发到 Pod
┌─────────────────────────────────────────────────────┐
│ Node │
│ ┌─────────────────────────────────────────────────┐│
│ │ kube-proxy ││
│ │ ↓ 配置规则 ││
│ │ ┌─────────────────────────────────────────────┐││
│ │ │ iptables / IPVS │││
│ │ │ ClusterIP:10.96.0.100:80 │││
│ │ │ → 10.1.1.2:80 (Pod A) │││
│ │ │ → 10.1.1.3:80 (Pod B) │││
│ │ │ → 10.1.1.4:80 (Pod C) │││
│ │ └─────────────────────────────────────────────┘││
│ └─────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────┘
Service 发现
# 环境变量方式
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: app
image: my-app
env:
- name: BACKEND_SERVICE_HOST
value: "10.96.0.100" # Service ClusterIP
- name: BACKEND_SERVICE_PORT
value: "80"
# DNS 方式(推荐)
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: app
image: my-app
env:
- name: BACKEND_URL
value: "http://my-service.default.svc.cluster.local"
DNS 解析规则:
┌─────────────────────────────────────────────────────┐
│ Service DNS 格式: │
│ <service-name>.<namespace>.svc.cluster.local │
│ │
│ 示例: │
│ my-service → my-service.default.svc.cluster.local │
│ │
│ 同 namespace 可以简化: │
│ my-service(省略后缀) │
└─────────────────────────────────────────────────────┘
Endpoints
# 查看 Service 的 Endpoints
kubectl get endpoints my-service
# 输出示例:
# NAME ENDPOINTS AGE
# my-service 10.1.1.2:80,10.1.1.3:80,10.1.1.4:80 5m
# Endpoints 自动更新:
# - Pod 创建 → 添加到 Endpoints
# - Pod 删除 → 从 Endpoints 移除
# - Pod 就绪 → 添加到 Endpoints
# - Pod 未就绪 → 从 Endpoints 移除
实践练习
练习 1:创建 ClusterIP Service
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
# 应用配置
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# 查看 Service
kubectl get service nginx-service
# 查看 Endpoints
kubectl get endpoints nginx-service
# 测试访问
kubectl run test-pod --image=busybox --rm -it -- wget -qO- http://nginx-service
练习 2:创建 NodePort Service
# nodeport-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30080
type: NodePort
# 应用配置
kubectl apply -f nodeport-service.yaml
# 查看 Service
kubectl get service nginx-nodeport
# 通过 NodePort 访问
curl http://<node-ip>:30080
练习 3:Service 发现
# 创建测试 Pod
kubectl run test-pod --image=busybox --command -- sleep 3600
# 通过 DNS 名称访问 Service
kubectl exec test-pod -- nslookup nginx-service
kubectl exec test-pod -- wget -qO- http://nginx-service
# 查看完整的 DNS 名称
kubectl exec test-pod -- nslookup nginx-service.default.svc.cluster.local
常见误解
1. Service 是一个进程
错误理解:Service 是一个运行的进程
正确理解:Service 是 iptables/IPVS 规则,由 kube-proxy 配置
Service 没有自己的 Pod,只是转发规则
2. ClusterIP 可以从外部访问
错误理解:ClusterIP 可以从集群外部访问
正确理解:ClusterIP 只能在集群内部访问
外部访问需要 NodePort 或 LoadBalancer
小结
| 要点 | 说明 |
|---|---|
| Service | 为 Pod 提供稳定访问入口 |
| 类型 | ClusterIP、NodePort、LoadBalancer、ExternalName |
| kube-proxy | 配置 iptables/IPVS 规则实现转发 |
| 服务发现 | 环境变量或 DNS(推荐) |
| Endpoints | 自动维护后端 Pod 列表 |
练习编辑器
bash
Loading...