在 Kubernetes 中,Service(服务) 是核心组件之一,它的核心作用是解决 Pod 的 "动态性问题" ------ 由于 Pod 会因重启、扩缩容、节点故障等原因重建,其 IP 地址会频繁变化,直接访问 Pod IP 极不稳定。而 Service 通过提供一个固定的访问入口,自动关联后端 Pod 并实现负载均衡,让客户端(如其他 Pod、外部服务)能稳定访问服务。
1 为什么需要 Service?
假设部署了 3 个 Nginx Pod(通过 Deployment 创建,标签app: nginx
),用于提供 Web 服务。此时存在两个关键问题:
- Pod IP 不稳定:如果某个 Pod 故障重建,新 Pod 的 IP 会变,客户端无法感知这种变化。
- 缺乏负载均衡:客户端需要手动分发请求到不同 Pod,无法自动实现流量分摊。
Service 正是为解决这两个问题而生:
- 提供一个固定的 ClusterIP(集群内 IP)或端口,客户端只需访问这个固定地址。
- 自动通过标签选择器关联后端 Pod,将请求转发到健康的 Pod,并实现简单的负载均衡(默认轮询)。
2 Service 的核心功能
简单说,Service 就是 Pod 的 "稳定访问层",核心功能有 3 个:
- 固定访问入口:为一组 Pod 提供固定的 IP(ClusterIP)和端口,屏蔽 Pod IP 的动态变化。
- 自动负载均衡:将请求分发到后端健康的 Pod(默认轮询策略,部分类型支持会话保持)。
- 服务发现:通过 K8s 内置 DNS(如 CoreDNS),让集群内其他 Pod 可通过 "Service 名称" 访问服务(无需记 IP)。
3 Service 的核心属性(必懂)
定义 Service 时,关键是要明确 "关联哪些 Pod""用什么方式访问",核心属性如下:
属性名 | 作用 | 示例值 |
---|---|---|
spec.selector |
标签选择器(核心!用于匹配后端 Pod,Service 只转发请求到带这些标签的 Pod) | app: nginx (匹配标签app=nginx 的 Pod) |
spec.ports |
端口映射规则(定义 Service 的端口与 Pod 端口的映射关系) | 见下文详解 |
spec.type |
Service 类型(决定访问方式,如集群内访问、外部访问等,核心!) | ClusterIP (默认)、NodePort 等 |
spec.sessionAffinity |
会话亲和性(是否将同一客户端的请求转发到同一个 Pod,默认None ) |
ClientIP (按客户端 IP 绑定) |
重点:ports
端口映射规则
Service 的端口映射是 "客户端访问 Service 的端口"→"Service 转发到 Pod 的端口",每个端口规则包含 3 个关键参数:
port
:Service 自身暴露的端口(客户端访问时用的端口)。targetPort
:后端 Pod 上的端口(Pod 内容器实际监听的端口,默认和port
相同)。protocol
:协议(TCP/UDP,默认 TCP)。
示例:若 Pod 的 Nginx 监听 80 端口,Service 定义port: 8080
、targetPort: 80
,则客户端访问 Service 的 8080 端口,会被转发到 Pod 的 80 端口。
4 Service 的 4 种类型
Service 的类型决定了 "如何访问服务",不同类型对应不同场景,必须掌握:
4.1 ClusterIP(默认类型):集群内访问
- 特点:仅在集群内部暴露服务,分配一个集群内唯一的虚拟 IP(ClusterIP),只能被集群内的 Pod 访问。
- 适用场景:集群内部服务间通信(如前端 Pod 访问后端 API Pod)。
示例:创建 ClusterIP 类型的 Service
先部署 3 个 Nginx Pod(通过 Deployment):
yaml
# deployment-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
spec:
replicas: 3 # 3个副本
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx # Pod标签,用于Service关联
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80 # Pod内Nginx监听80端口
创建 Service,关联上述 Pod:
yaml
# service-nginx-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service # Service名称(集群内可通过此名称访问)
spec:
type: ClusterIP # 类型(默认,可省略)
selector:
app: nginx # 匹配标签app=nginx的Pod
ports:
- port: 8080 # Service暴露的端口
targetPort: 80 # 转发到Pod的80端口
操作与验证:
bash
# 创建Deployment和Service
kubectl apply -f deployment-nginx.yaml
kubectl apply -f service-nginx-clusterip.yaml
# 查看Service(CLUSTER-IP即为固定访问IP)
kubectl get svc nginx-service
# 输出示例:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-service ClusterIP 10.100.237.182 <none> 8080/TCP 30s
# 查看Service关联的后端Pod(endpoints)
kubectl get endpoints nginx-service
# 输出示例(3个Pod的IP和端口,证明关联成功):
# NAME ENDPOINTS AGE
# nginx-service 10.200.104.38:80,10.200.135.26:80,10.200.166.179:80 1m
# 集群内测试访问:在任意Pod中访问Service的ClusterIP:8080
kubectl run -it pod名 -- bash
# 在test-pod内部执行(访问Service):
curl 10.100.237.182:8080 # 会返回Nginx的默认页面
# 或通过Service名称访问(依赖CoreDNS):
curl nginx-service:8080 # 同样生效(推荐,无需记IP)

4.2 NodePort:集群外通过节点端口访问
- 特点:在 ClusterIP 基础上,额外在集群所有节点上开放一个静态端口(NodePort,范围 30000-32767),外部客户端可通过 "任意节点 IP:NodePort" 访问服务。
- 适用场景:需要从集群外部临时访问服务(如开发测试环境)。
示例:创建 NodePort 类型的 Service
yaml
# service-nginx-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
spec:
type: NodePort # 类型为NodePort
selector:
app: nginx
ports:
- port: 8080 # Service内部端口
targetPort: 80 # 转发到Pod的端口
nodePort: 30080 # 节点开放的端口(可选,不指定则自动分配)
操作与验证:
bash
kubectl apply -f service-nginx-nodeport.yaml
# 查看Service(PORT(S)显示8080:30080/TCP,30080即节点端口)
kubectl get svc nginx-nodeport
# 输出示例:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-nodeport NodePort 10.100.134.2 <none> 8080:30080/TCP 20s
# 外部访问:用集群任意节点的IP:30080
# 在本地电脑浏览器输入任意节点的IP:30080:
192.168.121.111:30080 # 会返回Nginx页面(确保节点端口可访问)

4.3 LoadBalancer:云环境外部访问(自动分配负载均衡器)
- 特点:仅在云环境(如 AWS、GCP、阿里云)中生效,云厂商会自动创建一个外部负载均衡器(如 AWS ELB),并将流量转发到 Service 的 NodePort 或 ClusterIP。
- 适用场景:生产环境中需要从公网访问服务(通过云厂商的负载均衡器)。
示例:创建 LoadBalancer 类型的 Service
yaml
# service-nginx-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- port: 80
targetPort: 80
操作与验证:
bash
kubectl apply -f service-nginx-loadbalancer.yaml
# 查看Service(EXTERNAL-IP会显示云厂商分配的负载均衡器IP)
kubectl get svc nginx-loadbalancer
# 输出示例(AWS环境):
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-loadbalancer LoadBalancer 10.96.23.45 a1b2c3d4.elb.amazonaws.com 80:30123/TCP 5m
# 外部访问:直接访问EXTERNAL-IP
curl a1b2c3d4.elb.amazonaws.com # 会转发到后端Nginx Pod
4.4 ExternalName:映射到外部域名
- 特点 :不关联任何 Pod,直接将 Service 名称映射到一个外部域名(如
example.com
),通过 K8s DNS 实现。 - 适用场景:需要将集群内服务访问指向外部服务(如外部数据库、第三方 API)。
示例:创建 ExternalName 类型的 Service
yaml
# service-externalname.yaml
apiVersion: v1
kind: Service
metadata:
name: external-api
spec:
type: ExternalName
externalName: api.example.com # 映射到外部域名
操作与验证:
bash
kubectl apply -f service-externalname.yaml
# 在集群内Pod中访问:通过Service名称会解析到api.example.com
kubectl run -it --rm test-pod --image=busybox:1.35 -- sh
nslookup external-api # 会返回api.example.com的IP
5 特殊的 Service:无头服务(Headless Service)
普通 Service 有 ClusterIP,而无头服务(Headless Service) 没有 ClusterIP,它的作用是提供 Pod 的 DNS 记录列表,让客户端自己决定访问哪个 Pod(适合需要自定义负载均衡或 StatefulSet 的场景)。
定义方式:spec.clusterIP: None
,示例:
yaml
# service-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-headless
spec:
clusterIP: None # 无头服务(无ClusterIP)
selector:
app: nginx
ports:
- port: 80
targetPort: 80
验证:在集群内 Pod 中解析 Service 名称,会返回所有后端 Pod 的 IP:
bash
nslookup nginx-headless # 输出所有关联Pod的A记录(IP)
6 Service 的工作原理(简单理解)
Service 的核心是 "流量转发",K8s 通过两种方式实现(默认 iptables):
- iptables 模式 (默认):
- K8s 在每个节点的 iptables 中添加规则,当请求访问 Service 的 ClusterIP:Port 时,iptables 会将流量转发到后端 Pod 的 IP:Port(随机选择一个,实现轮询负载均衡)。
- IPVS 模式 (高性能,需手动开启):
- 基于 LVS(Linux Virtual Server)实现,支持更多负载均衡策略(如最小连接数),性能优于 iptables,适合大流量场景。
7 常见问题与排错(必看)
- Service 访问不通,提示 "Connection refused" :
- 原因 1:
selector
标签不匹配,Service 未关联到任何 Pod(查看 endpoints:kubectl get endpoints <service-name>
,若为空则标签错误)。 - 原因 2:Pod 的
targetPort
未监听(检查 Pod 内容器是否正常启动,端口是否正确,如kubectl exec <pod-name> -- netstat -tln
)。 - 原因 3:网络策略(NetworkPolicy)禁止了访问,需检查是否有策略限制 Service 到 Pod 的流量。
- 原因 1:
- NodePort 访问不通 :
- 原因 1:节点端口被防火墙拦截(如节点的 firewalld/ufw 未开放 30080 端口)。
- 原因 2:
nodePort
指定的端口不在 30000-32767 范围内(K8s 默认限制,需调整则修改 kube-apiserver 的--service-node-port-range
参数)。
- Service 名称无法解析 :
- 原因:CoreDNS 未正常运行(检查
kubectl get pods -n kube-system | grep coredns
,确保 CoreDNS Pod 正常)。
- 原因:CoreDNS 未正常运行(检查
8 总结
- Service 的核心价值:为动态变化的 Pod 提供固定访问入口,实现负载均衡和服务发现。
- 4 种类型:
- ClusterIP:集群内访问(默认)。
- NodePort:外部通过节点端口访问(测试用)。
- LoadBalancer:云环境外部访问(生产用)。
- ExternalName:映射到外部域名。
- 原因:CoreDNS 未正常运行(检查
kubectl get pods -n kube-system | grep coredns
,确保 CoreDNS Pod 正常)。
8 总结
- Service 的核心价值:为动态变化的 Pod 提供固定访问入口,实现负载均衡和服务发现。
- 4 种类型:
- ClusterIP:集群内访问(默认)。
- NodePort:外部通过节点端口访问(测试用)。
- LoadBalancer:云环境外部访问(生产用)。
- ExternalName:映射到外部域名。
- 关键机制 :通过
selector
标签关联 Pod,依赖 iptables/IPVS 实现流量转发。