一个真实的需求场景你有没有遇到这种情况写了个 Spring Boot 应用打成镜像在 Kubernetes 里跑起来了Pod 名字天天变IP 三天两头换——想从另一个服务调用它总不能硬编码 Pod IP 吧这就是 Service 需要解决的问题。还有你的老板让你把四个微服务都暴露到公网用同一个域名按路径分流还要加 HTTPS。要是每个服务分别配 LoadBalancer一个月光负载均衡器账单就能让你吃土。所以今天聊聊 Kubernetes 网络里最核心的两个概念Service四层和Ingress七层。我用的环境是Kubernetes v1.32所有命令在 Linux 和 MacOS 上已验证。阅读本文你将学会什么时候用 ClusterIP / NodePort / LoadBalancer别拍脑袋选怎么用 Ingress 实现域名路径路由、HTTPS 终止排除那些让你半夜被叫醒的诡异网络故障四层 ServicePod 的“固定电话”Service 的本质是什么简单说Service 就是给一组动态变化的 Pod 提供一个固定的访问入口。Kubernetes 的网络模型规定每个 Pod 都有自己的集群内 IP但这些 IP 会随着 Pod 重启而变化。Service 通过标签选择器找到对应的 Pod然后把这组 Pod 的 IP 列表放到 Endpoints或 EndpointSlice里。kube-proxy 监听这些变化在 iptables 或 IPVS 里灌转发规则。把 Service 想象成一个“总机号码”。前台挂了后台还能换人接电话——这就是服务发现。Service 在数据平面是四层负载均衡TCP/UDP over IP不关心 HTTP 路径、Host 头这些东西。要实现七层路由需要 Ingress。Type ClusterIP默认类型apiVersion: v1 kind: Service metadata: name: myapp-svc spec: selector: app: myapp ports: - port: 80 # Service 的访问端口 targetPort: 8080 # Pod 容器实际监听的端口这是默认类型只能集群内部访问分配一个虚拟 IPClusterIP比如10.96.100.100。集群内的 Pod 可以通过myapp-svc.default.svc.cluster.local或者缩写myapp-svc访问到这个服务。在同一个 namespace 下直接写 Service 名字就够了不用带后缀。Type NodePortapiVersion: v1 kind: Service metadata: name: myapp-nodeport spec: type: NodePort selector: app: myapp ports: - port: 80 targetPort: 8080 nodePort: 30080 # 可选不指定的话自动分配 30000-32768每个 Node 上都打开nodePort如 30080外部访问任一节点 IP:30080就能到达服务。NodePort Service 内部会自动创建一个 ClusterIP路由路径是外部 → NodeIP:NodePort → ClusterIP → Pod。Type LoadBalancerapiVersion: v1 kind: Service metadata: name: myapp-lb annotations: # 云厂商特有的注解比如 AWS、GCP、腾讯云各自不同 service.beta.kubernetes.io/aws-load-balancer-type: nlb spec: type: LoadBalancer selector: app: myapp ports: - port: 80 targetPort: 8080 externalTrafficPolicy: Local # 保留客户端真实 IP后面会细说云环境下会自动创建一个外网负载均衡器分配一个公网 IP 或者内网 IP。LoadBalancer 底层还是依赖 NodePort流量路径是外部负载均衡器 → NodePort → ClusterIP → Pod。不同云服务商的 LoadBalancer 行为有差异比如有的支持直接路由到 Pod绕过 NodePort有的仅走 NodePort。在迁移集群时一定要先测一下我被这个坑过两回。Service 类型选择速查表场景推荐类型原因集群内服务互相调用微服务ClusterIP内部稳定访问不外露调试 / 临时对外测试NodePort简单不依赖云 LB正式产环境对外 Web 服务LoadBalancer Ingress可扩展支持高级路由UDP 或非 HTTP 协议LoadBalancerIngress 不支持非 HTTP 协议外部流量策略——一个很多人忽视的关键参数这是我踩过的坑。默认externalTrafficPolicy: Cluster时外部请求经过 NodePort 进入集群后如果转发到另一个节点上的 Podkube-proxy 会做 SNAT——把源 IP 改成当前节点 IP。后端 Pod 收到的全是节点 IP拿不到真实客户端 IP。如果用 Local 模式流量只会转发到本节点上有相应 Pod 的情况否则丢包但能保留源 IP。那么怎么取舍需要客户端真实 IP比如审计、限流、根据 IP 做策略用Local。追求流量尽可能均匀分摊到所有 Pod用Cluster默认。七层 IngressWeb 流量的“智能路由器”Ingress 和 Ingress Controller 的关系别把 Ingress 和 Ingress Controller 搞混——这是我刚入坑时最迷糊的地方。Ingress 资源是一个 YAML 配置文件描述了路由规则比如域名api.example.com的请求转发到 Service A路径/app/*的请求转发到 Service B。但 Ingress 本身不干活它只是个“配置文件”。Ingress Controller才是真正干活的软件。它运行在集群里监听 Ingress 资源的变化然后动态配置底层的反向代理通常是 Nginx、Traefik、HAProxy 等把路由规则变成真实流量转发。再白话一点Ingress 写“我想怎样”Controller 去做“实际怎样”。你必须先在集群中部署一个 Ingress Controller只创建 Ingress 资源没有任何效果。社区里目前约 70% 的生产环境使用 NGINX Ingress Controller基于开源 Nginx 构建是最主流的选择。顺便一提Ingress Controller 转发流量时通常不会经过后端的 Servicekube-proxy而是直接从 Endpoints 拿到 Pod IP 列表直接转发。这样做可以绕过一次 NAT性能更好也支持更多七层高级特性比如基于 Cookie 的会话保持、URL 重写等。Ingress YAML 核心结构apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: app-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / # 路径重写 nginx.ingress.kubernetes.io/proxy-body-size: 10m spec: ingressClassName: nginx # 用哪个 Ingress 控制器处理 tls: - hosts: - myapp.example.com secretName: myapp-tls # 证书 Secret提前创建好 rules: - host: myapp.example.com http: paths: - path: / pathType: Prefix # 前缀匹配 backend: service: name: myapp-svc port: number: 80 - path: /api pathType: Exact # 精确匹配 backend: service: name: myapi-svc port: number: 8080pathType 的区别很多人栽坑我用三句话讲清楚pathType匹配规则示例path 设为/Exact完全相等区分大小写/✅、/foo❌Prefix基于/分隔的路径前缀匹配区分大小写/匹配所有路径/foo/匹配/foo/barImplementationSpecific匹配规则取决于 Ingress Controller 的实现Nginx 默认走Prefix一个典型坑设置path: /myapp但忘了写pathType校验失败Ingress 控制器直接忽略这条规则。v1.22 之后pathType是必填字段。我在升级老集群时狠狠吃过这个亏查了两小时才发现。安装 NGINX Ingress Controller我用 Helm 装最省心# 添加 repo helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update # 安装LoadBalancer 类型云环境自动分配公网 IP helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx --create-namespace # 如果本地测试用 Minikube用 NodePort 模式 helm install ingress-nginx ingress-nginx/ingress-nginx \ --namespace ingress-nginx --create-namespace \ --set controller.service.typeNodePort安装完成后检查kubectl get pods -n ingress-nginx # 预期输出ingress-nginx-controller-xxx Running kubectl get svc -n ingress-nginx # 预期输出ingress-nginx-controller LoadBalancer 10.x.x.x pending/公网IP... kubectl get ingress # 查看 Ingress 资源的状态如果公网 IP 一直pending有两个可能一是你用的自建集群没有云 LB需要改用 NodePort二是云账号欠费了LB 创建会失败Event 日志里有明确报错。Ingress Controller Pod 启动后访问它的外部 IP 再加上你配置的 Host 路径就能验证规则是否生效。IngressClass多控制器共存如果集群里同时有 nginx-ingress 和 traefik怎么区分哪个 Ingress 由谁处理IngressClass资源解决了这个问题。先定义 ClassapiVersion: networking.k8s.io/v1 kind: IngressClass metadata: name: nginx spec: controller: k8s.io/ingress-nginx然后在 Ingress 里用spec.ingressClassName: nginx指定即可。不同 Ingress Controller 实现各有侧重Nginx 功能全面最普及Traefik 对微服务和 Let‘s Encrypt 自动续期支持友好HAProxy 的性能强悍。按需选用目前我自己的生产环境多数场景还是 Nginx。顺便提一句NGINX Ingress Controller 社区版ingress-nginx官方已宣布将于 2026 年左右停止维护但 Ingress API 本身资源定义依然保留控制器层面未来会有更多替代方案。完整实战从 Deployment 到 Ingress来跑一个完整的小项目。我选择部署一个简单的 Nginx Web 服务让外部可以通过域名访问。步骤 1部署 DeploymentapiVersion: apps/v1 kind: Deployment metadata: name: nginx-demo spec: replicas: 2 selector: matchLabels: app: nginx-demo template: metadata: labels: app: nginx-demo spec: containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80 resources: requests: memory: 64Mi cpu: 100m limits: memory: 128Mi cpu: 200mkubectl apply -f nginx-deploy.yaml步骤 2创建 ServiceClusterIPapiVersion: v1 kind: Service metadata: name: nginx-svc spec: selector: app: nginx-demo ports: - port: 80 targetPort: 80kubectl apply -f nginx-svc.yaml kubectl get endpoints nginx-svc # 预期输出两个 Pod IP 在 ENDPOINTS 列步骤 3创建 Ingress 资源apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress spec: ingressClassName: nginx rules: - host: myapp.example.com http: paths: - path: / pathType: Prefix backend: service: name: nginx-svc port: number: 80kubectl apply -f nginx-ingress.yaml kubectl get ingress # ADDRESS 列会显示 Ingress Controller 的 IP步骤 4验证在本地机器上测试# 假设 Ingress Controller 的 IP 是 192.168.1.100 curl -H Host: myapp.example.com http://192.168.1.100/ # 预期输出 Welcome to nginx!或者在本机/etc/hosts里加一行192.168.1.100 myapp.example.com然后直接curl http://myapp.example.com/。如果返回 404八成是 Ingress Controller 和 Service 连通性有问题检查一下 Service Endpoints 和 Ingress 里的 Service 名字是否写对大小写、namespace 都对吗。我在这上面的摔跤次数两只手数不过来。生产环境避坑指南我踩过的 5 个坑坑 1Ingress 后端 Service 误用 NodePort/LoadBalancer 类型Ingress 引用后端 Service 时那个 Service 必须是ClusterIP 类型。如果 Service 是 NodePort 或 LoadBalancerIngress 控制器会识别不出来或出现意外行为。我最开始把 Ingress 理解成“在 Service 外面再包一层”于是直接把 LoadBalancer Service 放上去当后端结果日志疯狂报错。后来才明白 Ingress Controller 直接调 Endpoints API绕过 Service所以后端 Service 只用 ClusterIP 就够了。坑 2pod 响应慢导致 504 Gateway Timeout默认 nginx-ingress 的 proxy-read-timeout 是 60 秒。如果后端接口处理时间超过这个值就会返回 504。解决方案——针对单个 Ingress 加 annotationmetadata: annotations: nginx.ingress.kubernetes.io/proxy-read-timeout: 300 nginx.ingress.kubernetes.io/proxy-send-timeout: 300或者全局修改 ConfigMap 里的proxy-read-timeout但要注意会对整个集群的所有 Route 生效。如果只需要某个特定的长连接端点多配一些用 annotation 的收益更大。坑 3节点安全组放坏了外部死活访问不了云上 Kubernetes 通常限制 NodePort 端口范围30000-32768。如果安全组没放通这个区间外网流量进不来。检查 Ingress Controller Service 的 NodePort 端口再确认安全组入方向是否放行了该端口。坑 4Ingress 404——路径没匹配上404 通常意味着 Ingress 规则没匹配到请求。常见原因host 头不匹配包括大小写、FQDN 结尾等细节pathType 写错比如用 Exact 但访问了子路径路径规则里漏写了结尾/先用kubectl describe ingress name查看 Ingress 状态。如果Address字段为空说明 Ingress Controller 没识别到该资源。再通过kubectl logs -n ingress-nginx看 Ingress Controller Pod 的访问日志确认实际访问的 host 和 path。坑 5Ingress 控制器内存持续增长当 Ingress 资源数量很大比如上千条 rule时Nginx Ingress Controller 会频繁 reload Nginx 配置重载时流量会有短暂抖动的效应。社区版本里可以通过 ConfigMap 里开启reload-on-change: false来降低配置刷新频率吗这部分场景我没有实践过大规模但社区经验是在成千上万条规则时需要对 deployment 做资源限制memory request/limit 同时上调以免 OOMKilled并在监控上观察重载频率。建议先压测后再上线。故障排查速查表现象可能原因排查命令Service ClusterIP 不通端口配置错 / 标签不匹配kubectl describe svc,kubectl get endpointsNodePort 访问失败节点安全组未放通端口telnet NodeIP NodePortIngress 返回 404host 或 path 匹配失败kubectl describe ingress,kubectl logs -n ingress-nginxIngress 返回 502后端 Pod 挂了或未就绪kubectl get pods,kubectl get endpointsIngress 返回 504后端超时增加 timeout annotation检查后端业务响应时间LB IP 一直 Pending云账号欠费 / 子网 IP 不足 / RBAC 权限不足kubectl describe service, 检查 Event外部访问 Ingress 有 4 秒延迟CLB 回环问题常见于 IPVS 模式 云内网负载均衡器流量误走本地 dummy 网卡导致回环排查 IPVS 模式和集群内访问逻辑社区方案是关闭或调整 kube-proxy 的 strictARP 参数通用排查技巧先用kubectl get event | grep -E Service|Ingress看最近一小时的事件。用kubectl logs -n namespace pod-name看 Ingress Controller 的日志。绕开 Ingress直接访问 Service ClusterIP 或 NodePort确认后端是否正常。Gateway API下一代选择与未来趋势你可能会问Gateway API 是什么和 Ingress 有啥关系现状Kubernetes 官方已宣布Ingress API 冻结frozen不再添加新功能未来的重点是 Gateway API。Gateway API 在设计上更关注跨 namespace 安全访问、分离基础设施所有权和路由配置等细粒度角色管理以及支持更多协议gRPC、TCP、UDP 等和更复杂的流量策略。迁移建议现有老项目继续用 Ingress 完全没问题不会突然不能用。新项目如果对多租户隔离、复杂流量控制有要求优先考虑 Gateway API。一个混合策略部分应用继续 Ingress简单新上的业务直接用 Gateway API。聊聊吧以上就是我围绕 Service 和 Ingress 在生产环境的一点心得有一些教训到今天还记得。你遇到过什么诡异的 Kubernetes 网络问题评论区分享你的“踩坑”故事——也许下一篇文章就帮你排查掉