概述
当我们部署了微服务,怎么从浏览器访问它?
在 Kubernetes 中,Pod 的 IP 是临时的、不稳定的 ------重启就变,扩缩容就增减。 因此直接连 Pod 是行不通的,这时候,你需要 Service
Service 有三种常用类型:
- ClusterIP(默认)→ 只在集群内部能访问
- NodePort → 通过每台机器的固定端口暴露
- LoadBalancer → 云厂商给你一个公网 IP
为什么需要 Service
用户服务有 3 个 Pod,IP 分别是:
- 10.244.1.5
- 10.244.2.8
- 10.244.3.2
如果服务硬编码其中一个 IP,一旦那个 Pod 挂了,调用就失败!
Service 的作用:
- 给一组 Pod 提供一个固定的虚拟 IP 和 DNS 名
- 自动做负载均衡,把请求分发给健康的 Pod
- 即使后端 Pod 全换了,Service 地址不变!
功能对比
| 类型 | 谁能访问? | 端口范围 | 是否需要云平台 | 典型用途 |
|---|---|---|---|---|
| ClusterIP | 仅集群内部 | 无(虚拟 IP) | 不需要 | 微服务之间通信 |
| NodePort | 外部 + 内部 | 30000--32767 | 不需要 | 本地开发、测试 |
| LoadBalancer | 外部 + 内部 | 任意(通常 80/443) | 需要(AWS/GCP/Aliyun) | 生产环境公网访问 |
ClusterIP 是基础,NodePort 和 LoadBalancer 都基于它扩展而来
ClusterIP(默认类型)
适用场景
后端 API 之间通信
示例 YAML
yaml
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user # 匹配带此标签的 Pod
ports:
- protocol: TCP
port: 80 # Service 监听端口
targetPort: 3000 # 转发到 Pod 的端口
type: ClusterIP # 默认值,可省略
验证
在集群内启动一个临时调试 Pod:
bash
kubectl run curl-test --image=curlimages/curl -it --rm -- sh
在容器内执行:
bash
curl http://user-service/api/users
成功!但你在自己电脑上 curl http://<任意IP>/api/users 会失败------因为 ClusterIP 不对外。
NodePort
适用场景:
- 本地 Minikube / Kind 测试
- 内网演示系统
- 没有云平台时的临时暴露
示例 YAML
yaml
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user
ports:
- protocol: TCP
port: 80 # Service 内部端口(可选)
targetPort: 3000
nodePort: 31000 # 可选,不写则自动分配
type: NodePort
注意:
nodePort必须在 30000--32767 范围内- 如果不指定,K8s 会自动分配一个
查看分配的端口
bash
kubectl get service user-service
输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
user-service NodePort 10.96.123.45 <none> 80:31000/TCP 10s
如何访问
-
Minikube 用户:
bashminikube ip # 得到如 192.168.49.2 curl http://192.168.49.2:31000/api/users -
Kind 或 Linux 用户:
bashcurl http://localhost:31000/api/users # 或本机 IP curl http://$(hostname -I | awk '{print $1}'):31000/api/users
LoadBalancer(生产标配)
适用场景:
- 正式上线的 Web 应用
- 需要 HTTPS、DDoS 防护等高级功能
示例 YAML
yaml
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
在云平台上的效果
部署后,运行:
bash
kubectl get service user-service
你会看到:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
user-service LoadBalancer 10.96.123.45 203.0.113.25 80:32145/TCP 1m
现在,全世界都可以访问:
http://203.0.113.25/api/users
注意 :在本地 Minikube/Kind 中,EXTERNAL-IP 会卡在 <pending>,因为没有云平台支持。
但 Minikube 提供了模拟命令:
bash
minikube tunnel # 在后台运行,会分配一个虚拟公网 IP
三个服务的关系
外部用户
│
├──(1) LoadBalancer → [云 LB] → Node → Service → Pod
│
└──(2) NodePort → 直接访问 Node:31000 → Service → Pod
↑
│
集群内部服务 → (3) ClusterIP → Service → Pod
- 所有类型最终都通过 ClusterIP 转发到 Pod
- NodePort 和 LoadBalancer 是 ClusterIP 的"外层包装"
最佳实践
text
你想让谁访问这个服务?
│
├─ 只有集群内部其他服务? → 用 ClusterIP(默认)
│
└─ 需要外部访问?
│
├─ 在本地开发/测试? → 用 NodePort
│
└─ 在云上生产环境? → 用 LoadBalancer
说明:不要在生产环境滥用 NodePort!它会暴露高危端口到所有节点。
常见误区
| 误区 | 正确理解 |
|---|---|
| "LoadBalancer 比 NodePort 更快" | 性能接近,LoadBalancer 优势在于公网 IP 和云集成 |
| "ClusterIP 不能被外部访问" | 正确!这是设计原则 |
| "NodePort 可以用 80 端口" | 不行!必须 30000--32767 |
| "Service 直接连到 Pod IP" | 实际通过 iptables/IPVS 规则转发,非直连 |
总结
| 类型 | 核心特点 | 使用命令 |
|---|---|---|
| ClusterIP | 内部通信,安全隔离 | type: ClusterIP(默认) |
| NodePort | 开发测试,简单暴露 | type: NodePort |
| LoadBalancer | 生产公网,云原生 | type: LoadBalancer |
Service 不是"网络设备",而是 K8s 的"流量路由规则", 它让微服务之间的通信变得简单、可靠、可扩展。