K8s 四层代理 Service 全解
结合文档内容,从核心作用、底层组件、三类IP、四大Service类型、Endpoints、CoreDNS、企业实战逐层拆解,搭配完整实验、流程、坑点,零基础也能看懂。
一、先搞懂:为什么必须用 Service?
1. Pod 的三大天生缺陷(痛点)
- Pod IP 不固定
Pod 重建、漂移到其他节点后,IP 会随机变化。如果业务直接写死 Pod IP,服务就会失联。 - 无法统一入口
一个应用通常多副本(多个Pod),客户端没法逐个记所有 Pod IP,需要统一访问入口。 - 集群外默认无法访问 Pod
Pod 网络是集群内部私有网段,外网/集群外主机不能直接连通。
2. Service 核心定位
Service 是 K8s 四层负载均衡 + 固定访问入口,工作在 TCP/UDP 四层(不解析HTTP协议内容)。
核心能力:
- 提供固定虚拟IP(ClusterIP),永不变化;
- 自动关联一组 Pod,实现负载均衡;
- 实时感知 Pod 上下线,自动更新后端地址;
- 配合
kube-proxy实现流量转发; - 结合 CoreDNS 实现服务发现(域名访问)。
3. 核心协作组件(必须理解)
(1)kube-proxy
每个 K8s 节点默认常驻进程,核心职责:
- 通过
watch监听 apiserver,实时感知 Service、Pod 变化; - 在当前节点生成 iptables / IPVS 转发规则;
- 接收访问 Service 的流量,转发到后端正常 Pod。
前文讲过:kube-proxy 支持
iptables(默认)和IPVS两种模式,大规模集群推荐 IPVS。
(2)Endpoints(端点)
Service 不会直接绑定 Pod,而是通过 Endpoints 记录后端所有正常 Pod 的 IP+端口。
- 由 Service 的
selector标签选择器自动维护; - Pod 新增/删除/就绪状态变化,Endpoints 会自动同步;
- 查看命令:
kubectl get ep/kubectl describe ep。
(3)CoreDNS
集群内置 DNS 服务,实现服务域名解析:
集群内所有 Service 都会自动生成域名,无需记 IP。
标准域名格式:
<服务名>.<命名空间>.svc.cluster.local
二、K8s 集群三类网络 IP(重点区分)
集群内存在三套独立网络,互不冲突:
| 网络类型 | 名称 | 特点 | 作用范围 |
|---|---|---|---|
| 节点网络 | Node IP | 物理/虚拟机网卡真实IP,永久固定 | 集群内外均可访问,用于节点通信、NodePort/LoadBalancer |
| Pod 网络 | Pod IP | Pod 内部IP,动态变化 | 仅集群内部节点/Pod 互通 |
| 服务网络 | ClusterIP | Service 虚拟IP,集群内部虚拟地址,不绑定物理网卡 | 仅集群内部访问 |
示例:
- NodeIP:
192.168.1.63(宿主机网卡地址) - PodIP:
10.244.187.76(Calico/Flannel 分配) - ClusterIP:
10.96.0.1(系统默认 kubernetes 服务)
关键:ClusterIP 是纯内核虚拟IP,
ip addr在节点上看不到网卡绑定,只存在于转发规则中。
三、Service 资源清单核心字段详解
执行 kubectl explain service 查看原生字段,挑生产常用字段逐一解释:
1. 基础字段
apiVersion: v1 # Service 属于 core/v1 核心资源
kind: Service # 资源类型
metadata:
name: my-svc # Service 名称
namespace: default# 命名空间
2. spec 核心字段
1)selector 标签选择器
用来匹配后端 Pod,规则和 Deployment/ReplicaSet 完全一致:
- 匹配
labels相符的 Pod; - 匹配成功后,自动把 Pod IP 写入 Endpoints;
- 不写 selector 时,需要手动创建 Endpoints(对接外部服务场景)。
2)ports 端口配置(三层端口必记)
ports:
- port: 80 # ① Service 内部端口(ClusterIP 监听端口,集群内访问用)
targetPort: 80 # ② 后端 Pod/容器的端口(流量最终转发到这里)
nodePort: 30380 # ③ 节点端口(NodePort 类型专用,集群外访问)
protocol: TCP # 协议:TCP/UDP,默认TCP
三者流转关系:
客户端 → NodeIP:nodePort → ClusterIP:port → PodIP:targetPort
3)type Service 类型(四大核心类型)
type: ClusterIP / NodePort / LoadBalancer / ExternalName
四大类型用途、访问范围、使用场景下文逐个实验讲解。
4)sessionAffinity 会话亲和
默认 None:轮询负载均衡;
设置 ClientIP:会话保持,同一客户端IP请求始终转发到同一个Pod。
适用场景:需要会话留存的业务(传统Web会话)。
四、四大 Service 类型 完整实验 + 原理
环境统一前置:
集群:1 Master + 多个 Worker,Calico 网络,镜像已导入;
所有实验基于 Nginx Deployment 多副本演示。
类型一:ClusterIP(默认类型)
1. 作用
仅集群内部访问,分配一个固定 ClusterIP 虚拟地址。
- 只能在集群节点、Pod 内部访问;
- 集群外部(办公电脑、外网)无法直接访问;
- 纯四层负载均衡,是集群内部服务互通标准方案。
2. 实验步骤
步骤1:创建 Nginx Deployment(多副本)
# pod_test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
replicas: 2
selector:
matchLabels:
run: my-nginx
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
# 健康探测(保证就绪Pod才接入Endpoints)
startupProbe:
httpGet: {path: /, port: 80}
initialDelaySeconds: 60
periodSeconds: 5
timeoutSeconds: 10
livenessProbe:
httpGet: {path: /, port: 80}
initialDelaySeconds: 60
periodSeconds: 5
timeoutSeconds: 10
readinessProbe:
httpGet: {path: /, port: 80}
initialDelaySeconds: 60
periodSeconds: 5
timeoutSeconds: 10
执行创建:
kubectl apply -f pod_test.yaml
# 查看Pod及IP
kubectl get pods -o wide -l run=my-nginx
步骤2:创建 ClusterIP 类型 Service
# service_test.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
type: ClusterIP # 默认类型,可省略
selector:
run: my-nginx # 匹配Pod标签
ports:
- port: 80 # Service内部端口
targetPort: 80 # 容器端口
protocol: TCP
kubectl apply -f service_test.yaml
# 查看Service
kubectl get svc
输出示例:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx ClusterIP 10.99.198.177 <none> 80/TCP 5m
步骤3:查看 Endpoints(核心验证)
kubectl get ep my-nginx
kubectl describe svc my-nginx
Endpoints 会列出两个 Pod 的 IP:80,证明 Service 已自动关联后端。
步骤4:访问测试
- 集群节点内访问(Master/Worker 主机)
curl 10.99.198.177:80
正常返回 Nginx 页面。
- Pod 内部跨Pod访问
进入任意 Pod,用 Service IP / 域名访问:
kubectl exec -it <pod-name> -- /bin/bash
curl my-nginx.default.svc.cluster.local
域名解析成功,证明 CoreDNS 正常工作。
3. 关键特性验证:Pod 重建后 IP 变化
# 删除一个Pod,Deployment自动重建新Pod
kubectl delete pod <旧pod名>
kubectl get pods -o wide -l run=my-nginx
👉 现象:新Pod IP 改变,但 ClusterIP 完全不变,访问依旧正常。
这就是 Service 解决 Pod IP 漂移的核心价值。
4. 访问范围总结
✅ 集群节点、Pod 可访问
❌ 集群外物理机/浏览器 无法访问
类型二:NodePort(节点端口)
1. 作用
在 ClusterIP 基础上,在所有节点上开放一个固定端口,实现集群外部访问。
- 端口范围:默认
30000 ~ 32767(系统预留); - 流量路径:
外网客户端 → 任意节点IP:NodePort → ClusterIP → 后端Pod; - 缺点:端口有限、节点IP暴露,适合测试/小型业务,不适合生产高并发。
2. 实验步骤
步骤1:编写 NodePort 类型 Service
# service_nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx-nodeport
spec:
type: NodePort
selector:
run: my-nginx-nodeport
ports:
- port: 80 # Service内部端口
targetPort: 80 # 容器端口
nodePort: 30380 # 手动指定节点端口(可选,不写则自动随机分配)
protocol: TCP
搭配对应 Deployment(前文已有),执行创建:
kubectl apply -f pod_nodeport.yaml
kubectl apply -f service_nodeport.yaml
步骤2:查看 Service
kubectl get svc
输出:
my-nginx-nodeport NodePort 10.100.156.7 <none> 80:30380/TCP
格式 80:30380:port:nodePort。
步骤3 多场景访问测试
- 集群内部:依旧可以用 ClusterIP 访问
curl 10.100.156.7
- 集群外部(办公电脑/浏览器)
使用任意节点公网/内网IP + 30380 端口访问:
# 节点IP:30380
curl 192.168.40.180:30380
浏览器直接打开 http://节点IP:30380 也可正常访问。
3. 流量转发原理(结合 kube-proxy)
节点上查看 IPVS/iptables 规则:
ipvsadm -Ln
可以看到 NodePort 端口对应的转发规则,流量被均衡分发到多个 Pod IP。
4. 优缺点 & 生产建议
✅ 优点:配置简单,快速对外暴露服务
❌ 缺点:
- 端口区间固定,大规模服务容易端口耗尽;
- 依赖节点IP,节点故障则对应入口不可用;
- 四层转发,无七层能力。
👉 生产:测试环境首选,生产前端业务优先用 Ingress。
类型三:ExternalName(外部名称服务)
1. 作用
集群内域名别名,不创建 ClusterIP、不做负载均衡。
核心场景:
- 跨命名空间访问服务;
- 对接集群外部域名/第三方服务。
原理:
把当前 Service 直接映射为另一个完整域名,集群内访问该 Service 等同于访问目标域名。
2. 实验:跨 Namespace 访问
步骤1:创建两个命名空间
kubectl create ns nginx-ns
步骤2:在 nginx-ns 下创建 Nginx Deployment + ClusterIP Service
# server_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: nginx-ns
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
# nginx_svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: nginx-ns
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 80
targetPort: 80
创建并验证:
kubectl apply -f server_nginx.yaml -n nginx-ns
kubectl apply -f nginx_svc.yaml -n nginx-ns
kubectl get svc -n nginx-ns
该服务完整域名:nginx-svc.nginx-ns.svc.cluster.local
步骤3:在 default 命名空间创建 ExternalName 服务
# client_svc.yaml
apiVersion: v1
kind: Service
metadata:
name: client-svc
spec:
type: ExternalName
externalName: nginx-svc.nginx-ns.svc.cluster.local # 目标完整域名
ports:
- port: 80
kubectl apply -f client_svc.yaml
步骤4:测试访问
在 default 命名空间启动 busybox Pod 测试:
kubectl exec -it <busybox-pod> -- sh
# 访问当前Service,等价于跨命名空间访问nginx-svc
wget -q -O - client-svc
# 直接访问原域名对比
wget -q -O - nginx-svc.nginx-ns.svc.cluster.local
两者返回结果完全一致。
3. 补充场景:对接外网域名
举例:集群内统一用 Service 别名访问 baidu.com
apiVersion: v1
kind: Service
metadata:
name: baidu
spec:
type: ExternalName
externalName: www.baidu.com
ports:
- port: 80
集群内直接 curl baidu 即可。
类型四:LoadBalancer(负载均衡器)
1. 作用
在 NodePort 基础上,对接云厂商公有负载均衡(阿里云/腾讯云/AWS 等)。
- 云平台会分配独立公网IP;
- 外部流量 → 云LB → 集群节点 → Pod;
- 仅限公有云 K8s 使用,自建物理集群(无云LB)无法使用。
2. 简要说明
- 自建机房/裸金属 K8s:不支持 LoadBalancer;
- 公有云创建该类型 Service 后,云平台自动分配外网IP;
- 访问方式:外网IP + 服务端口;
- 生产公有云业务常用,结合云LB的健康检查、防火墙能力。
五、高阶实战:手动 Service + Endpoint 对接集群外部服务
场景:K8s 集群内应用访问集群外独立 MySQL(物理机/虚拟机)
核心:Service 不配置 selector,手动创建 Endpoints 指向外部IP。
步骤1:集群外安装 MySQL(示例节点IP:192.168.40.182)
略(安装 mariadb / mysql)。
步骤2:创建无 selector 的 Service
# mysql_service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
type: ClusterIP
ports:
- port: 3306
targetPort: 3306
kubectl apply -f mysql_service.yaml
# 此时 Endpoints 为空
kubectl describe svc mysql
步骤3:手动创建 Endpoints 指向外部MySQL
# mysql_endpoint.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: mysql # 名称必须和 Service 完全一致
subsets:
- addresses:
- ip: 192.168.40.182 # 外部MySQL真实IP
ports:
- port: 3306
kubectl apply -f mysql_endpoint.yaml
步骤4 验证
kubectl describe svc mysql
# Endpoints 已变为 192.168.40.182:3306
集群内 Pod/节点 访问 mysql:3306 即可连通外部数据库。
核心规则:
- Service 和 Endpoints 名称必须完全相同;
- 不写
selector则不会自动管理 Pod,由人工维护 Endpoints;- 常用于对接遗留物理服务、外部中间件。
六、CoreDNS 服务发现 完整验证
1. CoreDNS 作用
集群内置 DNS 组件,所有 Service 自动解析为域名,格式:
<服务名>.<命名空间>.svc.cluster.local
同命名空间可简写服务名,跨命名空间写完整域名。
2. 验证实验
- 查看集群 CoreDNS Pod
kubectl get pods -n kube-system | grep coredns
- 启动测试 dig Pod(DNS解析工具)
# dig.yaml
apiVersion: v1
kind: Pod
metadata:
name: dig
spec:
containers:
- name: dig
image: xianchao/dig
command: ["sleep","3600"]
imagePullPolicy: IfNotPresent
restartPolicy: Always
kubectl apply -f dig.yaml
- 进入 Pod 解析 Service 域名
kubectl exec -it dig -- nslookup my-nginx
# 完整域名解析
nslookup my-nginx.default.svc.cluster.local
解析结果会返回 Service 的 ClusterIP,证明 DNS 服务正常。
七、四大 Service 类型 对比总结
| 类型 | 访问范围 | 核心用途 | 适用场景 | 限制 |
|---|---|---|---|---|
| ClusterIP | 仅集群内部 | 内部服务互通、四层负载 | 微服务内部调用 | 外网无法访问 |
| NodePort | 集群内外均可 | 节点端口暴露服务 | 测试环境、临时对外 | 端口30000-32767,节点单点故障 |
| LoadBalancer | 全网(公网IP) | 云厂商负载均衡 | 公有云生产业务 | 仅云K8s支持 |
| ExternalName | 集群内部 | 域名别名、跨命名/外网对接 | 跨NS访问、对接外部域名 | 无负载均衡,仅域名转发 |
八、生产最佳实践 & 常见坑点
1. 最佳实践
- 内部微服务:统一使用
ClusterIP+ 域名访问; - 测试对外访问:临时用
NodePort,用完及时关闭; - 公有云生产对外:优先
LoadBalancer+ 云厂商能力; - 自建机房生产对外:不使用 NodePort,统一搭配 Ingress(七层网关);
- 对接外部中间件:使用「无selector Service + 手动Endpoints」;
- 跨命名空间调用:优先
ExternalName或直接使用完整域名。
2. 常见故障排查
- 能通 ClusterIP,无法访问 Pod
排查:Pod 就绪探针、防火墙、容器端口是否匹配targetPort。 - NodePort 外网访问超时
排查:节点防火墙/安全组是否放行 30000-32767 端口。 - Service 正常但 Endpoints 为空
排查:selector标签和 Podlabels不匹配。 - 域名解析失败
排查:CoreDNS Pod 是否正常、集群DNS配置。
3. 补充:Service 与 前文知识关联
- Service 依赖 kube-proxy(iptables/IPVS)做转发;
- Service 依赖 Pod 就绪探针,只有
Ready的Pod才会加入 Endpoints; - 配合 Deployment 实现:Pod 漂移/重建后,服务入口始终稳定。当前文件内容过长,豆包只阅读了前 34%。
更多推荐




所有评论(0)