一、为什么需要 Service?
Pod 的动态性: Pod 是 Kubernetes 调度的基本单位。它们可能因为故障、滚动更新、扩缩容等原因随时被创建或销毁。
Pod IP 的不稳定性: 每个 Pod 都有自己的 IP 地址,但当 Pod 重建时,IP 地址会改变。
访问需求: 集群内部的其他应用(前端访问后端)、集群外部用户(访问 Web 应用)需要一种稳定可靠的方式来访问一组提供相同功能的 Pod。
二、Service 是什么?
1.定义
Service 是 Kubernetes 中的一个 API 对象,它定义了一组 Pod 的逻辑集合以及访问这组 Pod 的策略(通常通过标签选择器 selector
)。service主要解决Pod的动态变化,提供统一的访问入口。
2.核心功能
稳定访问端点: 为动态变化的 Pod 集合提供一个虚拟的、稳定的 IP 地址 (ClusterIP) 或 DNS 名称。
负载均衡: 基于iptables或者ipvs,将到达 Service 的请求自动分发到其后端健康的 Pod 上。
服务发现:基于标签管理器关联后端的Pod列表, 让其他应用能够轻松地找到并连接到这组 Pod。
3.endpoints对象
由 Kubernetes 自动创建和管理(通常无需手动操作),与同名的 Service 关联,存储了当前匹配 Service 标签选择器的所有健康 Pod 的 IP:Port 列表,Service 的负载均衡器就是基于这个列表进行流量转发的
三、service类型以及是用场景
1.ClusterIP
1.1 用途
默认类型,为 Service 分配一个集群内部的虚拟 IP (VIP),仅限集群内部的其他 Pod 或 Service 访问,用于后端服务间的内部通信(如前端访问后端 API、数据库访问)。
1.2 示例代码
[root@master-1 service]# cat 01-svc-ClusterIP.yaml
apiVersion: v1
kind: Service
metadata:
name: myweb-service
spec:
# 声明Service的类型,主要有:ClusterIP, NodePort, LoadBalancer.
# ClusterIP:
# k8s集群内部使用的类型,仅供K8S集群内部访问,外部无法访问。默认值。
# NodePort:
# 在ClusterIP基础之上,监听了所有的worker节点的端口号,可供K8s集群外部访问。
# LoadBalancer:
# 适合在公有云上对k8s集群外部暴露应用。
type: ClusterIP
# 声明标签选择器,即该svc资源关联哪些Pod,并将其加入到ep列表
selector:
apps: web
# 配置端口映射
ports:
# 指定Service服务本身的端口号
- port: 8888
# 后端Pod提供服务的端口号
targetPort: 80
[root@master-1 service]# cat nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
#基于标签关联pod,会关联apps=test或者apps=prod的pod
selector:
matchExpressions:
- key: apps
values:
- "test"
- "web"
operator: In
template:
metadata:
#为pod设置了两个标签
labels:
apps: web
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
#部署
[root@master-1 service]# kubectl apply -f .
#查看pod,service,endpoints
[root@master-1 service]# kubectl get pods,svc,endpoints -o wide
1.3 验证结果
如图所示,该Service自动生成了集群内部专用的虚拟IP地址(ClusterIP)和端口。
使用该ClusterIP地址(10.0.0.69:8888)成功访问到了集群内部署的Web业务服务。
2. NodePort
2.1 用途
k8s集群外部访问,NodePort机制在ClusterIP基础上,将服务以<节点IP>:<静态端口>
的形式暴露到集群外部,该端口可自动分配(30000-32767)或手动指定。端口范围可以在api-server中查看。
查看端口范围:
2.2 示例代码
[root@master-1 service]# cat 02-svc-NodePort.yaml
apiVersion: v1
kind: Service
metadata:
name: myweb-nodeport
spec:
# 指定svc的类型为NodePort,也就是在默认的ClusterIP基础之上多监听所有worker节点的端口而已。
type: NodePort
# 基于标签选择器关联Pod
selector:
apps: web
# 配置端口映射
ports:
# 指定Service服务本身的端口号
- port: 8888
# 后端Pod提供服务的端口号
targetPort: 80
# 如果是NodePort类型,可以指定NodePort监听的端口号,若不指定,则随机生成。
nodePort: 30080
#端口范围以上提供了查询方法,可以修改,修改api-server启动时的参数.
#nodePort: 8080
#部署
[root@master-1 service]# kubectl apply -f 02-svc-NodePort.yaml
service/myweb-nodeport created
#查看
[root@master-1 service]# kubectl get pods,svc,endpoints -o wide
2.3 验证结果
如图所示,该Service除了创建集群内部的ClusterIP和端口外,还开放了指定的NodePort端口30080用于外部访问。
通过任意节点IP加NodePort端口(如192.168.91.21:30080)均可成功访问部署的Web业务服务。
通过外部浏览器访问(http://192.168.91.22:30080/),也可以成功访问到web业务。
3.LoadBalance
3.1 用途
在 NodePort
基础上,利用云提供商的基础设施(如 AWS ELB, GCP Load Balancer, Azure LB)自动创建一个外部负载均衡器。该负载均衡器会将外部流量导向 NodePort
Service (进而到 Pod)。通常用于公有云上向公网暴露服务。
3.2 示例代码
#01 创建loadbalancer的service
[root@master-1 service]# cat 03-services-LoadBalance.yaml
kind: Service
apiVersion: v1
metadata:
name: svc-loadbalancer
spec:
# 指定service类型为LoadBalancer,注意,一般用于云环境
type: LoadBalancer
selector:
app: web
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
#02 配置云环境的应用负载均衡器
#添加监听器规则,比如访问负载均衡器的80端口,反向代理到30080端口。
#简而言之,就是访问云环境的应用服务器的哪个端口,把他反向代理到K8S集群的node端口为30080即可。
#03 用户访问应用负载均衡器的端口
#用户直接访问云环境应用服务器的80端口即可,请求会自动转发到云环境nodePort的30080端口。
4.ExternalName
4.1 用途
将 Service 映射到一个外部 DNS 名称 (如 my.database.example.com
)。不创建任何代理或负载均衡。通过访问该 Service 的 DNS 名称,解析到外部服务的 DNS 名称。
4.2 示例代码
[root@master-1 service]# cat 04-svc-ExternalName.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-externalname
spec:
# svc类型
type: ExternalName
# 指定外部域名
externalName: www.baidu.com
[root@master-1 service]# kubectl apply -f 04-svc-ExternalName.yaml
[root@master-1 service]# kubectl get svc svc-externalname
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc-externalname ExternalName <none> www.baidu.com <none> 98s
#启动容器后访问名为"svc-externalname"的svc,请求会被cname到"www.baidu.com"的A记录
5.类型对比
类型 | 访问范围 | 适用场景 | 依赖条件 |
ClusterIP | 仅集群内部 | 微服务间通信 | 无 |
NodePort | 集群外部 | 开发测试/临时暴露 | 节点防火墙开放端口 |
LoadBalancer | 公网访问 | 生产环境云集群 | 云厂商支持 |
ExternalName | 集群内部 | 集成外部服务(如RDS) | DNS 插件 |
四、 Service底层原理
1. Service 工作流程
Endpoint 控制器:监控 Pod 状态,更新 Service 关联的 Endpoints 列表。
kube-proxy:监听 Service/Endpoint 变化,生成代理规则。
流量转发:
iptables 模式:默认,通过 NAT 规则转发(适合小规模集群)。
IPVS 模式:基于哈希表,支持 RR/LC/WRR 等算法,万级服务性能更优。
2.kube-proxy的工作模式
2.1 定义
kube-proxy
是运行在每个 Node 上的网络代理组件,是实现集群内部的服务发现和负载均衡的关键。它监听 API Server 的 Service 和 Endpoint 变化,并配置本机的网络规则将流量路由到正确的后端 Pod。kube-proxy 支持多种工作模式,每种模式都有其特点和适用场景。
2.2 工作模式
01 iptables
模式 (默认)
工作流程:
- kube-proxy 使用
iptables
规则配置 Linux 内核的 netfilter 包过滤框架。 当请求到达 Service 的 ClusterIP:Port 时,
iptables
规则会进行 DNAT (目标地址转换),将目标 IP:Port 修改为随机选择的一个后端 Pod 的 IP:Port。
优点: 效率高,工作在操作系统内核层。
缺点:
- 规则数量庞大(尤其是 Service 和 Pod 很多时),可能影响性能。
- 负载均衡算法单一(默认是随机)。
- 不支持更高级的负载均衡策略(如会话保持、最少连接)。
如果第一个选中的 Pod 无响应,不会自动重试其他 Pod(除非应用层重试)。
02 ipvs
模式 (推荐)
kube-proxy 使用 Linux 内核的 IP Virtual Server
模块,IPVS 是 L4 负载均衡器,专门设计用于高性能负载均衡。
优点:
- 性能最高: 比 iptables 模式具有更低的延迟和更高的吞吐量,尤其在大规模集群中优势明显。
- 支持多种负载均衡算法:
rr
(轮询),lc
(最少连接),dh
(目标地址哈希),sh
(源地址哈希),sed
(最短预期延迟),nq
(永不排队)。 支持会话保持: 通过
sh
(源地址哈希) 算法实现。更高效的数据结构: 规则数量与 Service/Endpoint 数量呈线性关系,而非像 iptables 那样可能是指数关系。
缺点:
- 需要 Linux 内核支持 IPVS 模块 (现代内核通常已支持)。
03 工作模式切换
#修改kube-proxy配置文件
[root@node-1 ~]# cat >/etc/kubernetes/cfg/kube-proxy.yaml<<EOF
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 192.168.91.21
clientConnection:
kubeconfig: /etc/kubernetes/cfg/kube-proxy.kubeconfig
clusterCIDR: 10.0.0.0/24
healthzBindAddress: 192.168.91.21:10256
kind: KubeProxyConfiguration
metricsBindAddress: 192.168.91.21:10249
mode: "ipvs"
EOF
#切换工作模式mode: "ipvs" 或者 mode: "iptables"
#修改完后重启kube-proxy
[root@node-1 bin]# systemctl restart kube-proxy
重启后重新部署web应用,如下图,发现service基于rr轮询的方式分发流量到pod
五、常见问题排查
1.无法通过 Service 访问 Pod
检查 Service
selector
是否与 Podlabels
匹配 。
kubectl describe svc <service-name>
kubectl get pods --show-labels
- 检查 Endpoints 对象是否包含预期的 Pod IP,空的 Endpoints 意味着 selector 不匹配或 Pod 未就绪 (
readinessProbe
失败)。
kubectl get endpoints <service-name>
- 检查 Pod 是否正常运行且监听目标端口
kubectl logs <pod-name>
kubectl exec -it <pod-name> -- netstat -tuln
kubectl exec -it <pod-name> -- ss -tuln
- 检查 Pod 的
readinessProbe
是否配置正确且通过。 - 检查 kube-proxy 是否在所有节点正常运行。
systemctl status kube-proxy
kubectl get pods -n kube-system -l component=kube-proxy
- 检查节点防火墙规则 (如果使用
iptables
/ipvs
模式)。
2.NodePort 无法从外部访问
- 检查 NodePort Service 是否已创建
#看 PORT(S) 列是否有 80:3xxxx/TCP
kubectl get svc -A
确认使用的 Node IP 和 NodePort 正确。
检查节点的防火墙/安全组是否允许外部访问该 NodePort。
检查 kube-proxy 是否在节点上正常运行
六、总结
优先使用 DNS 进行服务发现:避免环境变量的顺序依赖问题。
内部服务使用 ClusterIP
:除非有特殊需求,否则这是最安全、最标准的内部通信方式
外部访问:
- 开发/测试:
NodePort
。 - 公有云生产环境:
LoadBalancer
(通常配合 Ingress Controller 处理 L7 流量)。 - 需要暴露多个 HTTP 服务:使用
Ingress
+ClusterIP
Service。
使用 ipvs
代理模式: 尤其是在大型集群或需要高性能、多种负载均衡算法、会话保持时。
合理使用 Headless Service
: 主要用于 StatefulSets 或需要直接访问所有 Pod IP 的场景。
配置 readinessProbe
: 确保 Service 只将流量路由到真正准备好接收请求的 Pod。
利用 Network Policies: 在 Service 之上实施网络层面的安全控制。
监控: 监控 Service 的 Endpoints 变化、DNS 解析延迟、kube-proxy 状态等。