聊Kubernetes的流量负载,几乎每个刚接触K8s的人都会被Service和Ingress卡住。我不止一次在群里看到有人问:“我已经建了Service,为什么外部还是访问不了?”或者“Ingress到底算不算Service的一种?”这些问题背后,其实是还没理清K8s里流量分层的设计思路。Service解决的是集群内部的服务发现和负载均衡,Ingress解决的是集群外部HTTP(S)流量的统一入口和路由转发。二者功能上有关联,但定位完全不同。这篇文章我就从这两层模型出发,把原理、配置、排障和实际运维中容易踩的坑一次讲清楚。无论你是刚入门K8s的开发,还是在准备CKA,又或者正想把业务从裸机搬到K8s上,这篇都能当一份比较完整的参考。
1. 为什么K8s要单独设计一套流量模型
1.1 传统负载均衡在容器环境里为什么失效
在部署在虚拟机或物理机上的传统架构里,服务的IP和端口相对固定,负载均衡器的配置也基本一劳永逸。但容器环境完全不是这个逻辑。Pod在K8s里是被当成“临时资源”来用的,副本销毁、节点故障、水平扩容、滚动更新,都会导致Pod的IP频繁变化。如果还用传统方式,把后端地址写死在负载均衡配置里,那么每次Pod重建后都要手动改配置,完全没法自动化。
用一句生活化的类比来理解:Pod IP就像酒店客人的临时房号,客人退房后再入住可能换房间;Service则像酒店的固定前台总机,不管住客怎么变,你只需要拨打同一个总机号码,前台会帮你转接到当前入住的房间。这就是K8s引入Service的核心原因——为动态变化的Pod提供一套稳定的访问入口。
1.2 Service与Ingress的分层逻辑
想不被绕晕,必须先分清它们所处的协议层。
Service工作在四层,主要管TCP/UDP的流量分发。它通过标签选择器找到一组Pod,再把到达Service的请求均匀转发到这些Pod上。Service本身不关心请求里面是什么路径、什么域名、是不是HTTP,它只关心“把这包数据送到哪个Pod”。
Ingress工作在七层,专门处理HTTP和HTTPS请求。它会根据请求的域名(host)、URL路径(path)、请求方法等七层信息,把流量路由到不同的Service上。也就是说,Ingress做的是“先看请求内容,再决定交给哪个Service”,相当于集群入口处的智能分拣员。
这种分层带来的好处很明显:底层Service负责稳定的四层转发,上层Ingress负责灵活的业务路由。你在同一个Ingress下,可以按域名把流量分给前端service,按路径把流量分给后端service,还可以挂上TLS证书做HTTPS终止,这些都在业务层完成,不需要给每个Service单独暴露公网端口。
1.3 流量负载模型的整体面貌
把两层合起来看,K8s的流量路径大致是:外部请求先到达Ingress Controller,Ingress Controller根据规则转发到对应Service的ClusterIP,Service再经过kube-proxy转发到某个Pod。在某些简单场景下,也可以不走Ingress,直接用NodePort或LoadBalancer类型的Service把流量接入集群。后面第4部分我会专门把这条链路中的每一跳拆开讲。
还要注意一点:Service也承担负载均衡职责。即使没有Ingress,只要Service后面挂了多个Pod,它就会做四层轮询转发。而Ingress除了路由,也可以配合Canary注解做灰度发布。理解了这个模型,你在设计集群网络时就不会再纠结“该用什么暴露服务”的问题。
2. Service:集群内流量分发的核心枢纽
2.1 Service工作原理:Selector机制与Endpoints
Service本身并不是一个运行中的进程,它更像一条规则或者一个转发目标。Service通过spec.selector里的标签选择器,动态圈定一组Pod。K8s的控制面会持续观察这组Pod的变化,并维护一个名叫Endpoints的资源对象,里面记录当前所有匹配Pod的IP和端口。数据面转发时,kube-proxy会读取Service和Endpoints的更新,把发往Service IP的流量改写并转发到具体的Pod IP。
我建议你先学会用命令看这个对应关系,排障时特别有用:
kubectl get svc webapp-svc kubectl get endpoints webapp-svc kubectl describe svc webapp-svc如果Endpoints里的Pod IP列表是空的,说明Service的selector没有匹配到任何Pod,这时候再怎么调转发都白搭。我见过很多新手创建了Service后访问失败,最后定位到的问题是Pod的标签和selector对不上,比如Pod写的是app:webapp,Service写的是app: webapp-v1。排查Service问题第一步永远是看Endpoints。
2.2 三种Service类型的选型对比
Service根据暴露范围不同分成几种类型,项目里最常用的就是ClusterIP、NodePort和LoadBalancer。
| Service类型 | 访问范围 | 实现方式 | 典型场景 |
|---|---|---|---|
| ClusterIP | 集群内部 | 分配虚拟IP,仅集群内可路由 | 服务间调用、Ingress后端 |
| NodePort | 集群外可通过节点IP访问 | 在每个节点开放固定端口,转发到ClusterIP | 临时调试、小规模暴露、裸机集群 |
| LoadBalancer | 集群外通过云负载均衡访问 | 云厂商LB绑定到NodePort或直接转发到Pod | 云环境暴露服务、对接公有云 |
| ExternalName | 集群内外均可 | DNS层CNAME转发 | 把集群外域名映射为集群内访问名 |
ClusterIP是默认类型,也是其他类型的基础。NodePort等于在ClusterIP之上,在每个节点额外开一个端口;LoadBalancer又是在NodePort之上,让云厂商的负载均衡器把公网流量转发到节点端口。很多云上集群的LoadBalancer,底层实际上还是NodePort,只是被云控制器自动串联起来了。
选型时我一般遵循这样的原则:集群内部服务调用用ClusterIP;带公网入口的线上业务,优先考虑Ingress加ClusterIP的组合;如果业务在裸金属环境且没有额外LB设备,就考虑NodePort配合externalTrafficPolicy;只有确实需要云厂商LB能力时(比如自动创建SLB、EIP),才直接创建LoadBalancer类型Service。
2.3 会话保持与转发模式的细节
Service默认是随机或轮询转发,但对需要保持用户会话的应用(比如WebSocket、登录状态),你希望同一个用户IP的请求始终打到同一个Pod上。这时需要配置sessionAffinity:
spec: sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 10800设置成ClientIP后,Service会尽量把来自同一个源IP的请求转发到同一个Pod。不过要注意,如果Pod数量变化或者Pod被重建,会话还是会断。会话保持能缓解问题,但不能完全替代业务侧的状态共享方案,比如Redis保存Session。
kube-proxy的转发模式也值得关注。老版本默认使用iptables模式,每个连接会遍历规则,并发高时CPU开销较大。新版本很多集群默认启用IPVS模式,用hash表的转发逻辑,性能和可靠性都更好。想确认当前模式,可以查看kube-proxy容器的启动参数,或者直接看节点上的ipvs规则:
ipvsadm -L -n如果输出里头没有对应的Service条目,而你的集群用的是iptables模式,就要去查iptables规则。这个细节在排查“Service不通”时非常关键。
2.4 一个完整的Service示例
下面这份YAML是我平时最常用的Web服务暴露方式:
apiVersion: v1 kind: Service metadata: name: webapp-svc spec: type: NodePort selector: app: webapp ports: - port: 80 protocol: TCP targetPort: 8080 nodePort: 30080这里port是Service对外提供服务的端口,targetPort是容器里业务进程监听的端口。请记住这个区别,很多人配置错误都是把两个端口填反了。比如你的容器用8080监听,而Service的port写成8080、targetPort写成80,流量转发过去就找不到进程。
由于Pod可能分布在多个节点上,NodePort会在所有节点上监听同一个端口。所以访问方式是http://任意节点IP:30080,而不是某个特定IP。生产环境中节点数量多了,这个特性反而容易把端口暴露面扩大,需要靠安全组或防火墙控制入口。
2.5 特殊类型的Service:Headless Service
还有一种情况值得单独提一下,就是headless service。配置时把clusterIP设为None,Service就不分配ClusterIP,DNS解析会直接返回后端所有Pod的IP列表。这对有状态应用(如数据库、消息队列)特别有用,因为应用可以自己感知每个Pod的真实地址,做集群成员发现。如果你在跑高可用数据库,或者需要自定义负载均衡策略的服务,headless service通常比普通Service更好使。
3. Ingress:七层入口与统一路由
3.1 先分清Ingress资源和Ingress Controller
新人最常见的误区是以为创建一个Ingress资源后,流量就能自动按规则转发。实际上Ingress只是一份声明式的路由规则,真正干活的是Ingress Controller。Controller通常以Pod的形式运行在集群里,它会持续监听Ingress资源的变化,并把这些规则转换成具体的反向代理配置,比如nginx.conf、Envoy路由规则等。
所以使用Ingress的第一步是部署一个Controller。最常用的是ingress-nginx;如果追求性能和可观测性,可以选择基于Envoy实现的Emissary或Kong;云计算平台通常也提供托管型Ingress Controller,比如阿里云、腾讯云都有自己的组件。社区里最主流、文档最全的还是ingress-nginx,下面的例子都以它为准。
部署完成后,还要确保Ingress资源里指定了正确的ingressClassName,否则Controller会无视你的规则。从K8s 1.19开始,推荐用spec.ingressClassName字段指定,而不是旧的annotations写法:
spec: ingressClassName: nginx3.2 host与path路由规则怎么配
一个Ingress可以有多个规则,每条规则可以基于不同域名或路径转发。例如,让同一个公网入口同时处理两个域名:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: multi-host-ingress spec: ingressClassName: nginx rules: - host: shop.example.com http: paths: - pathType: Prefix path: / backend: service: name: shop-svc port: number: 80 - host: blog.example.com http: paths: - pathType: Prefix path: / backend: service: name: blog-svc port: number: 80这里有两个关键概念。pathType为Prefix,表示前缀匹配;为Exact,表示精确匹配。后端service块里不需要写IP,只需要写Service名字和端口,Ingress Controller会自动从服务发现机制里拿到后端地址。如果你需要把/api开头的请求都导到一个网关服务,前端静态资源导到另一个服务,可以用不同的path和同一个host来做。
匹配顺序也需要注意。在ingress-nginx里,路径最长匹配优先。例如同时存在/和/api两个path时,请求/api/users会先匹配到/api那条规则,而不是/. 想验证路由是否生效,可以进到Ingress Controller Pod里查看生成的nginx配置文件:
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- cat /etc/nginx/nginx.conf | grep server_name -A 203.3 HTTPS与TLS证书配置
Ingress最常见的生产用途之一就是帮你在入口层终止HTTPS。你只需要在K8s里创建一个包含证书和私钥的Secret,然后在Ingress里引用即可:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: secure-ingress spec: ingressClassName: nginx tls: - hosts: - shop.example.com secretName: shop-tls-secret rules: - host: shop.example.com http: paths: - pathType: Prefix path: / backend: service: name: shop-svc port: number: 80创建Secret时要注意证书必须用PEM格式。如果是证书链,要把中间证书和站点证书合并到同一个tls.crt里。用cert-manager这个项目的话,可以自动申请和续期证书,写个Certificate资源声明域名,controller会定期检查证书过期时间。我在生产环境里一直用cert-manager+Let's Encrypt,证书续期几乎不用人工介入。
TLS配置还有一个细节:想让HTTP请求自动跳转到HTTPS,一般通过全局配置或者annotation实现,比如nginx.ingress.kubernetes.io/ssl-redirect: "true"。如果某些路径(比如API回调)需要强制HTTP而不是跳转HTTPS,可以单独覆盖这个annotation。
3.4 金丝雀发布:利用Ingress按比例分流
Ingress可以做很实用的灰度发布。以ingress-nginx为例,你可以在主Ingress之外,再创建一个带Canary注解的Ingress。例如让新版本服务接收20%的流量:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: new-app-ingress annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: "20" spec: ingressClassName: nginx rules: - host: shop.example.com http: paths: - pathType: Prefix path: / backend: service: name: shop-svc-new port: number: 80这样流量会按20%比例分到新的Service,剩下80%继续走旧Service。灰度期间如果看到异常率升高,直接把canary注解删掉或者将canary-weight改成0,就能立即把流量收回旧版,不用重新改主Ingress。这个方案比修改Deployment副本数要精细得多,非常适合线上验证新版本。
还可以按请求头分流,比如只有带特定Header的用户才会走新版本,适合内部预发布验证。对应注解是canary-by-header。这些高级功能都是Controller实现的,所以在换Ingress Controller时,同一套annotation不一定通用,迁移前要重点检查。
3.5 Ingress版本与兼容性注意点
Ingress API从networking.k8s.io/v1beta1演进到networking.k8s.io/v1,字段有一些变化。如果是新集群,直接用v1;老集群在用v1beta1的话,建议尽早迁移。最明显的变化是backend字段写法,老版本是:
backend: serviceName: my-svc servicePort: 80新版本是:
backend: service: name: my-svc port: number: 80升级过程中,很多存量Ingress会报校验错误,最好先用kubectl convert转换再apply。我见过有人直接从网上复制老配置到新集群,结果Ingress创建成功但流量全都404。出现这种情况,第一反应应该检查Ingress API版本和Controller版本是否匹配。
4. 一条请求从外部到Pod的完整链路
4.1 逐层拆解一次HTTP请求
很多人配置都能成功,但要把整个链路说清楚时又含糊了。我在这里把一次从公网访问服务的完整路径拆成六跳:
第一跳,用户在浏览器输入域名,经过DNS解析到负载均衡器或节点IP。如果用了云服务商,这一跳会绑定公网IP。第二跳,流量到达Ingress Controller Pod,它根据Host头(比如shop.example.com)和URL路径找到匹配的Ingress规则。第三跳,Controller根据规则里的backend,把请求转发到对应Service的ClusterIP和端口。第四跳,Service所在的节点上kube-proxy会处理这次转发,根据负载均衡策略,把流量送到某个后端Pod的IP与targetPort。第五跳,Pod里的业务容器(比如Nginx、Java应用)收到请求并处理。第六跳,响应数据按原路径返回。
这里有个常见的认知误区:Ingress Controller转发请求给Service时,是否还会再做一次负载均衡?答案是会。不过这部分行为在不同Controller里实现略有差异。ingress-nginx默认情况下会直接把后端指向Endpoints里的Pod IP,而不是ClusterIP,这样更多是为了保留客户端真实IP并绕过kube-proxy的性能损耗。如果你在Service层面配置了会话保持,这里可能会失效,因为Controller跳过了Service负载均衡逻辑。设计高可用方案时,要清楚这一点:会话保持建议放在Ingress层配置,或者让业务层自己处理Session。
4.2 什么时候只需要Service,什么时候必须加Ingress
对于集群内部服务之间的调用,比如订单服务调用用户服务,直接用ClusterIP类型的Service就够了。请求不经过任何入口,集群内DNS解析到ClusterIP就能互通。
对于需要被外部访问的业务,如果你的需求只是简单暴露一个TCP端口,比如数据库、Redis、MQ,用NodePort或LoadBalancer类型的Service反而最省事。Ingress主要用于HTTP/HTTPS流量,它不支持直接转发MySQL、Redis这类原生TCP长连接(虽然ingress-nginx现在也支持TCP/UDP配置,但配置复杂度明显高,不如直接NodePort)。
对于典型的Web业务,我的建议是:统一使用Ingress作为入口,后端服务全部用ClusterIP,不对外暴露NodePort。这样做的好处有三个:一是入口统一,安全策略和TLS证书只需要管一个地方;二是端口管理简单,不用记住一堆nodePort;三是可以做域名路由、灰度、限流等高级策略。如果你的业务部门多、服务多,这种模式能省很多事。
4.3 云环境下的LoadBalancer与Ingress配合
在公有云上,Ingress Controller本身通常也会配一个LoadBalancer类型的Service来接入流量。也就是说,云厂商负载均衡器监听公网IP,把流量转发到Ingress Controller的Pod,Controller再按规则转到集群内部。如果直接用LoadBalancer类型Service暴露每一个后端服务,那么每有一个服务就要创建一个云负载均衡器,费用高、管理难。
正确做法是尽量把云LB资源收敛到Ingress层。多个域名、多套TLS证书、多条路由规则都挂在同一个LB后面,整体成本会低很多。在云上使用托管K8s时,还要注意Ingress Controller的Service带宽、安全组放通等细节,否则容易出现“Controller部署好了但公网访问不通”的诡异问题。
4.4 时延与性能考量
Ingress多引入了一层转发,时延确实会略高一点。但正常配置下,这个增量通常在几毫秒以内,对绝大多数业务无感。如果发现时延异常高,优先检查后端Pod的负载情况,以及K8s网络插件(比如Calico、Cilium)的转发路径,而不是第一时间怀疑Ingress。另外,性能瓶颈往往出现在TLS握手和连接复用上。可以开启Controller的HTTP/2支持,并调整keep-alive长连接参数,减少频繁握手。对于超高并发场景,还可以考虑把Ingress Controller单独部署到专用节点池,避免和业务Pod争抢资源。
5. 常见问题与排查技巧实录
5.1 Service访问不通,从哪里开始查
我处理过很多Service不通的工单,把排查顺序整理成一套思路,按顺序走基本能定位问题。
先看Service是否正常:
kubectl get svc kubectl describe svc <service-name>重点看Endpoints是否为空。如果为空,说明selector没匹配到Pod;如果不为空,跳下一步。再检查Pod本身是否Ready:
kubectl get pods -l <selector> kubectl logs <pod-name>Pod没Ready的常见原因是镜像拉取失败、启动命令错误、Liveness探针失败等。然后尝试在集群内直接访问ClusterIP:
kubectl run test-pod --image=busybox --rm -it -- wget -O- http://<cluster-ip>:<port>如果集群内能通、集群外不通,问题往往出在NodePort层,比如安全组没放行端口、节点防火墙拦截、或者Service类型不是NodePort/LoadBalancer。如果NodePort通但Ingress不通,问题十有八九在Ingress规则匹配上。
5.2 Ingress规则不生效的检查清单
当你访问域名返回404或者503时,按这个清单逐项排查更有方向:
- Ingress Controller是否运行:查看ingress-nginx命名空间下的Deployment和Pod状态。
- Ingress资源是否关联正确的ingressClassName。
- 域名解析是否指向了Ingress Controller的入口地址(云LB IP或节点IP)。
- 后端Service名称和端口是否与Ingress配置完全一致,少了任何一项都会转发失败。
- 路径匹配是不是被更长的路径规则抢走了,尤其存在/、/api这些混合配置时。
- TLS配置的Secret是否存在,证书过期会导致握手失败。
- 如果配置了rewrite-target,路径重写后的后端Path是否与业务路由匹配。
排查时可以开启Ingress Controller的访问日志,配置到日志系统后,一眼就能看到请求是否成功转发到后端。ingress-nginx还支持在pod级别实时看日志:
kubectl logs -f -n ingress-nginx deploy/ingress-nginx-controller很多404不是Controller没收到请求,而是请求被转发到了错误的后端。日志里会直接显示upstream地址和状态码,比猜配置高效得多。
5.3 kube-proxy与转发链路相关的坑
节点上kube-proxy是Service转发的执行者。它的Pod如果异常,Service依然显示存在,但流量就是不通。检查方法:
kubectl get pods -n kube-system | grep kube-proxy kubectl logs -n kube-system kube-proxy-xxxxxkube-proxy使用iptables或IPVS模式时,规则是异步更新的。在Pod频繁创建删除时,偶尔会出现规则残留。遇到Service时通时不通,可以试着清掉对应的iptables规则或者重启kube-proxy。不过更推荐的还是采用低频率变更Pod的方式,避免短时间大量重建触发底层规则的混沌状态。
另一个坑是节点端口被占用。NodePort默认范围在30000-32767,如果分配的端口已被节点上的进程监听,Service会显示创建成功但外部访问不了。提前查一下端口占用情况,或者直接指定一个冷门端口,能少踩很多坑。
5.4 externalTrafficPolicy:为什么有的节点访问不通
Service的externalTrafficPolicy有Cluster和Local两个选项。默认是Cluster,意思是无论请求落在哪个节点,都会把流量转发到任意节点上的Pod,可能产生额外的一跳,但源IP会被SNAT成节点IP。Local模式则要求流量只转发到本节点上的Pod,保留客户端源IP,但会带来负载不均:某个节点没有对应Pod时,落在它上面的请求会被直接丢弃。
LoadBalancer类型的Service在云环境经常用到Local模式,因为这些LB的健康检查只发给节点端口。如果后端Pod不在这个节点上,健康检查就会失败。所以使用Local模式时,最好配合Pod反亲和性让每个节点都有Pod,或者接受偶尔的流量不均现象。调试时可以配合curl验证源IP:
curl http://<node-ip>:<node-port>/some-route然后看后端业务日志里记录的客户端IP。如果显示的是节点IP而不是真实客户端IP,说明当前externalTrafficPolicy是Cluster,IP被伪装了。要拿到真实IP,要么改成Local,要么在Ingress层开启转发策略。
5.5 多个Ingress Controller共存时的冲突处理
一个项目里可能同时跑着nginx-ingress和traefik,或者同时有内网入口和外网入口。这时必须明确指定每一条Ingress归属于哪个Controller。用ingressClassName就可以做到隔离。如果两条Ingress定义了相同host和path,却属于不同Controller,那么每个Controller各自处理自己的规则,互不影响。但如果规则都指向同一个Controller而出现重复,只有一条会生效,另一条会报冲突或被忽略。
如果希望某个Ingress只处理部分请求,可以用Controller自带的scope限制参数,比如只监听某个命名空间的Ingress资源。这类细节在大规模多团队共享集群时特别重要,否则团队A创建的规则会莫名影响团队B的入口。
5.6 服务治理层面的常见疏漏
除了基础流量不通,我还常看到治理层面的疏漏。第一个是忘记设置Pod的资源requests/limits,导致Pod在流量高峰被节点驱逐,Service后面一直有“重建-启动-被驱逐”的循环。第二个是没给Service配置合适的健康检查,ReadinessProbe失败会让Endpoint被自动摘除,有可能不是Service坏了,是探针配置不合理。第三个是Pod内多容器时只暴露了一个端口,实际业务进程监听的端口和探针不一致,导致服务“看起来挂但实际在跑”。先看容器启动命令确认监听端口,再用kubectl exec进容器本地访问,能快速排除这类问题。
6. 实操心得与后续演进
6.1 我在项目里踩过的几个真实教训
这几年在多个K8s集群里摸爬滚打,有几个踩过的坑现在印象都很深。第一次给别人搭环境,Service创建好了,NodePort也暴露了,但外网就是访问不了。最后排查发现云安全组压根没放行30080端口,而我自己又一直用内网机器测试,所以完全没察觉。因此我后来养成了条件反射:外部访问不通时,第一件事就是检查安全组和防火墙,而不是反复看YAML。
还有一次是Ingress的HTTPS证书过期,用户访问时不报证书过期,而是报连接被重置。原因是部分客户端不展示证书告警,直接中断握手。现在我在生产环境会专门加一套证书过期监控,cert-manager的证书对象自带状态,配合Prometheus的cert-manager指标做告警,非常稳。
另一个教训是关于Ingress路径重写。曾经有个前端项目把静态资源放在/static下,但Controller里rewrite-target配置成了/,导致请求/static/app.js被重写后变成/app.js,全站样式和脚本全丢。这个问题表面看是路由404,实际是路径重写规则没有吃透。现在遇到rewrite配置,我一定会在本地小流量验证后再切全量。
6.2 从Ingress走向Gateway API
如果现在才开始新项目或者新集群,我建议目光可以稍微往Gateway API移一点。Gateway API是K8s社区正在推进的下一代流量管理API,目标是取代Ingress,并为Service Mesh、南北向和东西向流量提供统一标准。它把Ingress里由注解承担的高级能力(如超时、重试、灰度、TLS策略)变成标准字段,可移植性更强。
不过现阶段,Ingress依然是生态和应用范围最广的方案。不要因为追新就盲目重写基础设施,我自己的建议是:小规模新集群可以尝试Gateway API,但现有Ingress存量业务除非有明确痛点,否则维持现状更稳。毕竟基础设施的稳定性比技术指标本身更重要。
6.3 一些避免焦虑的实用建议
最后分享一点个人习惯:接触K8s越久越觉得,网络这块是最容易出现“配置看起来都对,但就是不通”的领域。遇到问题时,别急着怀疑大前提,先把链路拆开,从DNS到Ingress Controller、再到Service、最后到Pod,逐层用curl和kubectl验证。给每个步骤都做一次二分定位,通常比盯着YAML猜测高效得多。生产环境的变更也要坚持“小范围验证再全量”,Ingress的灰度能力不只是给业务用的,运维自己调整路由规则时同样能派上用场。
Kubernetes的Service与Ingress并不复杂,复杂的是应用场景里各种细小的叠加。把这篇里的原理和排查思路理顺后,你会发现集群里的流量负载、对外暴露、灰度发布这些事情,其实都是可以一步一步推理出来的。