1. 从ClusterIP到NodePort:我们为什么需要这个Service类型
写这篇的时候,我翻了翻这个系列前面的内容,从Pod、Deployment一路走过来,大部分人其实已经能用Deployment把应用跑起来了。但接下来会遇到一个特别尴尬的问题:我启动的服务,我自己都访问不到。
为什么?因为Kubernetes里Pod的IP是内网地址,而且Pod天生就是“短命鬼”——它可能被重建、被调度到别的节点,IP随之变化。你不可能把IP写死到配置文件里,也不该自己维护一个服务发现机制。这就是Service存在的意义:它给一组Pod提供一个稳定的访问入口。
Service有多种类型,ClusterIP、NodePort、LoadBalancer、ExternalName。ClusterIP是默认的,它只在集群内部网络有效,你在集群外面根本没辙。那问题来了:集群外面的人怎么访问?比如说你在浏览器里访问一个Web应用,或者让外部系统调用你的API。
NodePort这个类型,就是从“集群内部能访问”跨越到“集群外部也能访问”的第一道门槛。它的做法很直白:在每个节点上开一个端口,然后把发到这个端口的流量转发给后端的Pod。
我把三类Service类型常被误解的地方先放到这儿:
- ClusterIP不是不能配,而是默认只能在集群内部用;
- NodePort不是替代ClusterIP,而是在ClusterIP基础上加了“节点端口”这个入口;
- LoadBalancer是云厂商的事,NodePort的转发逻辑它底层也在用。
这个系列本来就是一个K8s入门到实战的连续教程,这一篇的核心就是把NodePort这个Service类型讲透。你不需要有任何云厂商背景,也不需要理解太深的网络原理,但读完这篇,你应该能自己写一个NodePort的YAML、部署上去、从外部访问成功,并且知道出问题时从哪儿排查。
2. NodePort的工作原理:一次流量的完整旅程
2.1 从用户浏览器到Pod,中间发生了什么
假设我已经在集群里部署了一个Web服务,给这个服务配置了NodePort类型的Service,指定的nodePort是30080。现在有一个用户,在浏览器里输入http://192.168.1.10:30080来访问我的应用,其中192.168.1.10是集群中某个节点的IP。
这一整个请求链路,从外到内大概是这样的:
浏览器发起请求,目标地址是节点IP:30080。请求先到达节点上的网络接口,也就是那个节点的物理网卡。
然后进入了节点内核的iptables规则或者IPVS规则,这些规则是kube-proxy组件提前设置好的。流量在这一步被拦截,匹配到Service对应的规则,目标端口会被改写,比如改写成ClusterIP的80端口。
接着流量走向ClusterIP,实际上被转发到某一个后端Pod的IP和端口上。这一步会经过负载均衡策略,常见的是随机或者轮询。
最后到达Pod里运行的容器,容器里的进程处理请求并返回响应。响应沿着同样的路径返回到用户浏览器。
整个链路里,用户感知的只是一个IP:端口,他根本不知道集群里有哪个Pod在处理。这就是Service做了一层抽象的价值。
2.2 NodePort与ClusterIP的关系
很多人以为NodePort是一个单独的Service类型,跟ClusterIP是“二选一”的关系。这是个误区。
在Kubernetes里,当你创建一个Service,Type指定为NodePort时,系统会自动分配一个ClusterIP。也就是说,NodePort类型的Service,内部访问用的ClusterIP同样存在,外部访问用的是节点IP加nodePort端口。
换个说法,NodePort是ClusterIP的超集,它在ClusterIP的基础上,额外在每个节点上开了一个端口做流量接入。
所以ClusterIP的DNS解析、集群内部Pod之间的服务发现功能,在NodePort类型的Service上一样都好用。你完全可以在集群内部用service-name.namespace.svc.cluster.local去访问这个Service,同时外部又能通过节点IP访问。
2.3 kube-proxy在其中的角色:iptables与IPVS
这一步是Kubernetes网络里的核心机制。每个节点上都运行着一个叫kube-proxy的组件,它的职责是监听API Server上Service和Endpoint的变化,然后把这些变化同步到节点本地的转发规则里。
kube-proxy有几种工作模式,老版本的默认是iptables模式,新版本很多环境配置的是IPVS模式。iptables模式用的是Linux内核的iptables规则链,它会把Service的相关信息翻译成一条条链规则,比如KUBE-SVC-XXXX、KUBE-SEP-XXXX这些链。
IPVS模式则把负载均衡工作交给内核的IPVS模块,它本质上是一个内核态的四层负载均衡器,通过调度算法把流量分发到后端的Pod。在性能上,IPVS模式在Service数量多的时候比iptables模式表现更好,因为它用的是hash表,规则查找速度更快。
但不管用哪种模式,从用户角度来看,效果是一样的:发往节点IP:NodePort的流量,最终都会被转发到某一个后端Pod上。
提示:iptables模式在Service数量达到几千上万个时,可能会出现明显的性能问题。如果你在生产环境里,Service数量很多,建议确认一下kube-proxy用的模式。可以用
kubectl get cm kube-proxy -n kube-system -o yaml看一下配置,或者检查节点上的kube-proxy启动参数。
3. 动手实践:创建第一个NodePort类型的Service
3.1 准备一个后端应用
在创建Service之前,至少得先有一个能跑的应用。我这里用一个最简化的Deployment来做示例,后端镜像选择轻量的Web服务器,比如Nginx。
你可以先新建一个YAML文件:
apiVersion: apps/v1 kind: Deployment metadata: name: webapp labels: app: webapp spec: replicas: 2 selector: matchLabels: app: webapp template: metadata: labels: app: webapp spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80部署它:
kubectl apply -f deployment.yaml再确认两个Pod都处于Running状态:
kubectl get pods -l app=webapp3.2 编写NodePort类型的Service YAML
接下来是重头戏,写一个Service,类型指定为NodePort。
apiVersion: v1 kind: Service metadata: name: webapp-service spec: type: NodePort selector: app: webapp ports: - port: 80 targetPort: 80 nodePort: 30080三个关键字段得拆开讲:
port:Service本身的端口,也就是ClusterIP上监听的端口。其他Pod通过ClusterIP访问这个Service时,用的就是这个端口。targetPort:流量最终要转发到的容器端口。在我们的例子里,Nginx监听在80端口,所以targetPort也是80。nodePort:每个节点上暴露给外部流量的端口。这个字段是可选的,如果不写,Kubernetes会自动从配置的范围内分配一个。
另外注意selector,它决定了这个Service会关联哪些Pod。我们给Deployment里的Pod打了app: webapp这个标签,Service的selector必须跟它匹配,才能把Pod挂到Service后面。
应用这个Service:
kubectl apply -f service.yaml查看Service:
kubectl get svc webapp-service你会看到类似这样的一行输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE webapp-service NodePort 10.110.80.1 <none> 80:30080/TCP 10s注意看PORT(S)这一列,格式是80:30080/TCP,前面的80是Service端口,后面的30080就是NodePort。集群里每个节点的30080端口现在都被监听起来,等待转发了。
3.3 从外部访问服务
现在从集群外部访问。先拿到节点的IP:
kubectl get nodes -o wide每个节点都会显示一个INTERNAL-IP。选其中一个,用浏览器或者curl访问:
curl http://<节点IP>:30080正常情况下,你会看到Nginx的默认欢迎页内容。如果一切顺利,这一步就算走通了。
如果本地环境用的是kind、minikube这类工具,访问方式会略有不同。比如kind创建的集群,节点实际上是容器,需要先把节点端口映射到宿主机;minikube则可以用minikube service webapp-service直接帮你打开访问入口。网上这类工具的坑很多,后面我会专门讲。
3.4 从集群内部访问NodePort类型的Service
别以为NodePort只给外部用。集群内部的Pod一样可以绕过ClusterIP,直接通过节点IP:nodePort访问Service,它同样能正常转发。
不过这里有个逻辑要搞清楚:如果集群内部访问,建议优先用ClusterIP,因为少一跳转发链路,性能更好。NodePort的存在是为了满足集群外部的访问诉求,它不是内部访问的最佳路径。
4. 深入解析端口范围:为什么你的nodePort会分配失败
4.1 默认端口范围与配置位置
Kubernetes默认的NodePort端口范围是30000到32767。这个范围是写在API Server的启动参数里的,对应的参数是--service-node-port-range。
如果你手动指定nodePort,那么它必须在这个范围内。比如你写29999,创建的时候就会直接报错。
如果你想改这个范围,需要在API Server的启动参数中调整。这牵扯到控制和平面组件的配置,每个发行版的改法不一样,生产环境改它需要谨慎。通用的建议是:不要改,用默认范围就好。30000到32767这个端口段在常规业务里很少被用到,冲突的可能性小,安全上也相对独特。
4.2 跨命名空间的端口冲突
一个很容易踩的坑:同一个集群里,不同命名空间下,两个Service不能使用相同的nodePort。
我举个实际例子。你在namespace-a里创建了一个Service,nodePort指定为30080,一切正常。然后在namespace-b里再创建一个Service,也想用30080,Kubernetes会直接拒绝,报错类似:
The Service "xxx" is invalid: spec.ports[0].nodePort: Invalid value: 30080: provided port is already allocated原因不难理解:nodePort是节点级别的端口,而节点是所有命名空间共享的,同一个端口不可能同时被两个Service占用。所以设计Service时,想清楚端口规划的问题,避免冲突。
如果你不手动指定nodePort,Kubernetes自动分配时也会自动避开已经使用的端口,这块不用太担心。
4.3 NodePort与宿主机的端口冲突
还有一个隐蔽的问题:nodePort会绑定到节点的所有网络接口上。如果节点上某个进程已经占用了30080这个端口,那么kube-proxy在设置转发时会跟现有进程冲突。
不过通常来说,Kubernetes自动分配的nodePort会尽量避免常见端口,手动指定的时候你才需要额外小心。指定之前,先登录节点确认一下端口没被占用:
ss -lntu | grep 30080没有输出,说明端口是空的,可以放心使用。
4.4 小范围集群的端口枯竭问题
如果你管理的集群节点很多,比如上百台,理论上,每个Service的nodePort在所有节点上都会占用一遍。好在端口范围有2768个可用值(32767 - 30000 + 1),一般的业务规模很难用完。只有当你的Service数量极其庞大,或者有人恶意地把nodePort范围改得很小,才可能遇到端口分配枯竭的问题。
如果真的遇到这种极端情况,解决方案有两个方向。一是规划好端口分配,避免不必要的Service都开NodePort;二是考虑把nodePort范围扩大,注意这需要重启API Server,而且必须确保新范围不跟节点上其他服务冲突。
5. 三个端口的爱恨纠缠:port、targetPort与nodePort的边界
5.1 它们分别是谁的端口
这三个端口是Service配置里最容易搞混的东西。每次有新手问我,我都用一个快递的比喻来回答。
- port是快递站的门牌号。别人要找这个服务站,先按这个门牌号来。
- targetPort是最终收货人的房间号。快递到了,得找到具体哪间房。
- nodePort是快递站在每个小区外面设的自提柜。外面的人不用进小区,在自提柜就能取件。
展开到技术细节上:
port是Service暴露在ClusterIP上的端口,是集群内部访问Service时用的端口;targetPort是Pod里容器实际监听流量的端口,转发规则最终会把流量送到这里;nodePort是Service暴露在每个Kubernetes节点上的端口,是集群外部进入流量的入口。
5.2 端口不一致的场景
有一种情况很多人会写错:容器里监听的端口和应用默认端口不一致。
比如你的容器里有这样一个进程:
nginx -g "daemon off; listen 8080;"它监听的是8080端口,但你没有改YAML,targetPort写成了80。那么流量到达容器后,根本不会被这个进程接收到,服务自然不通。
正确的做法是让targetPort跟容器里实际监听的端口保持一致。如果你用的是自制镜像,端口是代码逻辑决定的,先确认清楚了再写。
5.3 服务端口不一致的另一个例子
还有一种场景,集群内部有多个应用互相调用,每个应用的Service约定的端口可以跟Pod的端口不一样。比如你有一个后端服务,它在容器里监听的是5000,但Service的port你可以设置成80。集群内部其他应用调它,用的是service-name:80,转发到Pod时才会改成5000。
从调用方的视角来看,它只关心Service端口,根本不关心Pod内部的端口细节。这就是Service抽象的一层好处。
6. 多节点场景下的NodePort访问方式
6.1 任意节点IP加节点端口都能访问
NodePort特性里有一个常被忽略的点:只要Service创建成功,集群里所有节点的指定端口都会开放,流量都可以被转发。
假设你的集群有三个节点,IP分别是192.168.1.10、192.168.1.11、192.168.1.12。那么192.168.1.10:30080、192.168.1.11:30080、192.168.1.12:30080这三个地址,全部都能访问这个Service。
这一点有实际意义:你不必关心用户当前访问的是哪个节点,任意入口都会转发到同一个Service后端。即使某个节点挂了,用其他节点的IP加端口访问,依然可以通。
但这同时带来一个安全和管理上的问题:每个节点都暴露了端口,相当于攻击面增大了。管控网络策略时,需要把这一整段端口都考虑进去。
6.2 为什么同一Service在不同节点上表现会有差异
在某些特殊情况下,你会发现访问节点A不通,但访问节点B是通的。常见的原因有几种:
- 节点A上的kube-proxy崩溃了,规则没有同步上;
- 节点A的网络插件(比如Calico、Flannel)有问题,导致转发链路断裂;
- 节点A的安全组或防火墙拦截了这个端口。
排查这类问题,第一反应是去看节点A上的kube-proxy日志和iptables规则是否完整,而不是怀疑Service本身有问题。
6.3 用externalTrafficPolicy控制访问来源
多节点场景下,有一个字段非常关键:externalTrafficPolicy。它有两个值:Cluster和Local。
默认值是Cluster。意思是流量进入任意节点后,可能被转发到其他节点上的Pod,这个转发过程会引入一次额外的网络跳数,同时会隐藏客户端的真实IP。
当它设置为Local时,流量进入某个节点后,只会被转发到“本节点上”的Pod,不会跨节点转发。好处是访问来源IP可以保留下来,而且转发路径更短,性能稍微好一些。代价是:如果某个节点上没有对应的Pod,流量到达这个节点后会被丢弃。所以Local策略通常需要跟Pod的调度规则配合使用,确保每个节点上都有Pod副本。
什么场景下适合用Local?比如你的应用需要记录用户的真实IP,做日志分析或风控;或者你对转发性能比较敏感。反之,如果你的Pod副本数很少,调度得比较集中,用Local反而可能造成大量节点上访问不通。
注意:externalTrafficPolicy这个字段只在NodePort和LoadBalancer类型的Service上生效。它不是一个日常随手改的字段,但排查问题时一定要想到它。
7. 会话保持:把用户请求固定到同一个Pod
7.1 为什么需要会话保持
对于无状态应用来说,请求被转发到哪个Pod都无所谓。但对于有状态应用,比如Session登录、WebSocket长连接、临时文件上传这类场景,用户的前后多次请求最好落在同一个Pod上,否则会出问题。
举个例子,用户在登录接口写入了一些状态到Pod A的内存里,下一步操作被转发到了Pod B,Pod B没这个状态,直接返回未登录。这是典型的会话失败。
NodePort类型的Service可以用一个字段解决这个问题:sessionAffinity。
7.2 配置sessionAffinity
把Service的YAML加一行:
spec: sessionAffinity: ClientIP含义很直接:来自同一个客户端IP的请求,会由负载均衡器固定在同一个后端Pod上。
展开看一下完整示例:
apiVersion: v1 kind: Service metadata: name: webapp-service spec: type: NodePort selector: app: webapp sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 10800 ports: - port: 80 targetPort: 80 nodePort: 30080timeoutSeconds字段控制的是会话保持的有效期,默认是10800秒,也就是3小时。超过这个时间后,来自这个IP的新请求可能会被转发到其他Pod。
这个配置本身很简单,但追求高可用的时候要权衡:sessionAffinity是Service层面的,如果Pod重启了,IP还在,但Pod内部的内存状态可能已经没了,会话还是会断。所以它只能作为辅助手段,真正的有状态服务还是得靠持久化和独立的状态存储。
7.3 会话保持与负载均衡的矛盾
开启sessionAffinity之后,负载均衡的效果会打折扣。因为同一个IP的流量始终到同一个Pod,相当于这个IP被“粘住”了。在流量大的场景下,某些Pod可能很忙,而其他Pod相对空闲。
没有任何方案是万能的。如果你的业务真的有会话保持需求,优先从应用层面解决,比如把Session放到Redis里,这样Pod层面的故障不会导致会话丢失;如果不是特别需要,建议不要开启这个功能,保持默认的负载均衡能力更省心。
8. NodePort的安全议题:暴露在外的端口如何管控
8.1 每个节点都是入口,每个入口都要管
NodePort直接暴露的是节点IP和端口。在云环境里,这就意味着你的安全组规则需要为每个节点放行NodePort端口段。
很多人在配置安全组时,习惯只放行常用的22、80、443,然后猛然发现自己NodePort的30080端口在外面访问不到。第一反应是Service配置错了,其实大概率是安全组没放行。
排查这种问题时,建议先用另一个节点试试,如果所有节点都不通,优先怀疑安全组;如果只有一个节点不通,优先怀疑那个节点本身的问题。
8.2 NodePort端口段本身的安全建议
30000到32767这个范围,在默认配置下对公网完全开放。如果你的业务只是内部测试,建议安全组里只允许特定来源IP访问这个端口段,不要对全互联网开放。
如果企业有严格的安全规范,不要直接用NodePort上生产环境,而是改用LoadBalancer类型配合云平台的安全策略。LoadBalancer会创建一个云负载均衡器,由它来过滤流量,安全边界更清晰。
8.3 通过Ingress收敛NodePort的暴露面
有一种常见的架构:在NodePort前面再套一层Ingress,或者用一个统一的入口网关。
具体来说,你可以创建一个NodePort只代理Ingress Controller,其他业务统统用Ingress规则来路由。这样集群对外暴露的NodePort端口数量就大大减少,只需要一个入口端口,然后由Ingress根据域名或者路径转发到不同的Service上。
这是我在实际项目中比较推荐的做法。NodePort是基础能力,但直接把几十个Service都开成NodePort暴露出去,既不安全也不优雅。
9. 遇到问题怎么办:NodePort常见故障排查实录
9.1 端口范围校验失败
创建Service时报错,提示端口不在范围内,信息类似:
The Service "webapp-service" is invalid: spec.ports[0].nodePort: Invalid value: 25000: must be between 30000 and 32767这个没什么好说的,把nodePort改成30000以上的值就行。如果要自定义范围,得去改API Server的启动参数。
9.2 从外部访问不通,但集群内访问正常
这是最典型的故障之一。出现这个现象时,请按这个顺序排查:
- 确认Service类型是不是NodePort,不是的话当然不通;
- 确认nodePort在安全组里是否放行;
- 确认节点防火墙,比如firewalld或者ufw,有没有拦截端口;
- 确认kube-proxy状态正常,Pod有没有Running。
如果上面都没问题,试着从另外的节点访问同一个端口,看看是不是只有特定节点有问题。
9.3 所有节点都无法访问,但Service状态正常
这种情况我遇到过不少次。Service的STATUS是正常的,CLUSTER-IP也有了,端口也对了,但就是通不了。
当时排查下来,发现是kube-proxy的Pod挂了。在kube-system命名空间下,kube-proxy是以DaemonSet形式运行的,理论上每个节点都有一个Pod。如果某个节点上的kube-proxy异常退出,那个节点上的转发规则就可能是错的或者缺失的。
查看kube-proxy状态:
kubectl get pods -n kube-system | grep kube-proxy再排查对应的日志:
kubectl logs <kube-proxy-pod> -n kube-system9.4 访问到了,但响应特别慢
NodePort的转发链路本身不会造成明显的性能瓶颈,如果出现响应慢的情况,优先排查后端Pod的负载能力,其次看节点之间的网络延迟。
另外,可以看看Kubernetes节点上的Pod分布情况。如果大部分Pod都集中在某一个节点上,其他节点的流量都发到本地后还要跨节点转发到那个节点,网络开销自然大得多。此时可以用externalTrafficPolicy: Local配合节点亲和性,让每个节点本地的Pod处理本节点的流量,降低跨节点请求。
9.5 NodePort端口被自动重新分配
有人不小心没有指定nodePort,Service创建后拿到一个随机端口,比如31876。后来把Service删了重建,端口变了。这不算故障,但如果你对接了外部的DNS、负载均衡器或者防火墙规则,端口一变,这些配置就可能全都失效。
解决方案就是在YAML里显式指定nodePort。如果首次创建时没有指定,你可能会遇到“字段不可修改”的提示,这时候需要先删除Service,再用包含nodePort字段的YAML重新创建。删除再创建的瞬间会有短暂的服务中断,要规划好时间窗口。
经验:在生产环境,我建议所有需要外部访问的Service都把nodePort固定下来,并形成一份端口登记表,避免重建之后找不到原来的端口。
10. 与Ingress配合:NodePort的高级姿势
10.1 为什么需要Ingress
NodePort解决了外部访问的问题,但随之而来一个新的麻烦:每一个Service都需要一个端口。假设有10个微服务,你就要维护10个端口,每个端口还得配置安全组规则,每个端口可能还得绑定域名,这很快就会变得难以管理。
Ingress就是解决这个问题的组件。它本质上是一个七层路由器,根据域名和URL路径,把外部请求转发到集群内部不同的Service上。
在Ingress的方案里,你只需要把Ingress Controller服务暴露为一个NodePort,其他业务都通过Ingress规则转发。这个架构在中小规模集群中非常实用。
10.2 实际部署Ingress的方案示例
以常用Ingress Controller为例,创建一个NodePort类型的Service来暴露它:
apiVersion: v1 kind: Service metadata: name: ingress-nginx-controller namespace: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 nodePort: 30080 - name: https port: 443 targetPort: 443 nodePort: 30443 selector: app.kubernetes.io/name: ingress-nginx这样,外部入口就收敛到两个端口:30080给HTTP,30443给HTTPS。其他Service不再每个人都暴露NodePort,而是通过Ingress规则进行路由。
10.3 什么情况下可以只用NodePort不用Ingress
如果你的服务就那么两三个,也没有域名的概念,直接用NodePort反而更简单。比如一些内部工具、监控面板、调试接口,NodePort是最轻量的方案。
不要在架构复杂度没有达到一定程度时强行引入Ingress。工具是好工具,但每多一层组件就多了很多排错变量。
11. 版本演进与历史避坑
11.1 kube-proxy模式的变化
早些年,Kubernetes的kube-proxy只有userspace和iptables两种模式。userspace模式是用户态代理,性能较差,后来默认转向iptables。再后来IPVS模式推出,逐渐成为大规模集群的首选。
如果你用的是很老的Kubernetes版本,比如1.10以下,遇到性能问题时可以检查一下kube-proxy的模式。新版本已经默认推荐IPVS模式,除非你手动改成了iptables。
11.2 不要依赖NodePort的端口稳定性
NodePort的端口分配在Kubernetes里有一定的不确定性。如果创建时没有指定端口,一定是自动分配,而且这个自动分配的范围是集群级别的。不同环境里,同一个Service可能拿到完全不同的端口。
所以凡是依赖固定端口的场景,务必显式指定nodePort;凡是写自动化脚本或者对接CI/CD流水线的,也建议先通过kubectl get svc获取当前端口,不要硬编码到脚本里。
11.3 多集群场景下的NodePort冲突
如果你的公司维护了多个Kubernetes集群,每个集群的nodePort范围可能默认一样。在跨集群访问的场景下,比如两个集群通过联邦或者网关互通,就需要确认端口分配情况,避免因为端口相同导致路由冲突。
这种问题通常不会在开发环境中暴露,生产环境规模大了才会遇到。提前在集群建设规划时统一nodePort管理策略,能少踩很多坑。
12. 最后说点实在话
NodePort在我眼里,是Kubernetes网络模型里最“平易近人”的一个入口。它不需要你接触云厂商的负载均衡器上限,不需要额外的收费,一个节点一个端口就能打通内外的流量。但正因为实现简单,它把许多复杂的网络细节藏在了背后,遇到问题时反而容易让人无从下手。
我个人的体会是,想真正理解NodePort,最好的办法不是背概念,而是亲手把一个Service创建出来,然后故意把targetPort写错一次、把nodePort写超范围一次、把安全组不放行一次。每一次报错都能让你对这个机制的印象深一分。把这些坑踩完了,再看生产环境里的各种方案,都能一目了然。
最后分享一个小技巧:排查NodePort问题时,kubectl describe svc <service-name>这个命令的信息量非常大,它会把Port、NodePort、Endpoints、Selector这些关键信息全部展示出来。我在现场排障时,第一件事就是看这个输出,能快速定位80%的问题。