想象你经营着一家拥有几十间客房的五星级酒店。每个部门——厨房、洗衣房、健身房——都在各自的“客房”(Pod)里工作。麻烦的是,这些部门经常搬家:厨房从 301 搬到 305,洗衣房从 502 搬到 501。如果客人只能靠房号找人,早就迷路了。于是酒店装了两套“指路系统”:第一套是总机(Service),给每个部门分配一个永不变的短号,不管它搬到哪里,拨短号永远能找到;第二套是大堂礼宾员(Ingress),客人甚至不用记短号,只需说一句“我要去健身房”,礼宾员就把他带到正确的地方。Kubernetes(K8s)中的 Service 和 Ingress,正是云原生世界里的这两套系统。本文用这个酒店故事,讲清楚 ClusterIP、NodePort、LoadBalancer 三种“电话线路”的区别,以及 Ingress 如何根据域名和路径把流量精确送到对应的服务。

岗位关联

学完本文,你将掌握 K8s 服务暴露与流量分发的完整链路,能够在真实集群中按场景选型 Service 与 Ingress——这是云原生运维、微服务面试与容器平台实战的高频核心技能。

目录
  1. 可视化演示
  2. 1. Service核心原理:给部门装一台永不换号的“总机”
  3. 2. ClusterIP内部访问:只限酒店内部拨打的内线短号
  4. 3. NodePort端口暴露:每个楼层的公用外线电话
  5. 4. LoadBalancer云负载:自带秘书应答的直线电话
  6. 5. Ingress路由规则:大堂礼宾员的“访客分流手册”
  7. 6. TLS安全终结:礼宾员代拆加密挂号信
  8. 7. 控制器选型对比:老牌礼宾员与智能礼宾员的较量
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示三种Service类型、Ingress路由分发与kube-proxy流量转发,支持流量强度调节。

本节配有交互动效(进入视口后自动加载,约 3KB)。

三种Service类型对比 紫色ClusterIP仅集群内部访问,默认Service类型 绿色NodePort开放节点端口,支持外部访问 ClusterIP < NodePort < LoadBalancer 三种类型递进暴露服务到外部

1. Service核心原理:给部门装一台永不换号的“总机”

酒店开张第一天,每个部门都在抱怨:厨房今天在 301 洗碗,明天可能就搬到 305 烘焙,客人打电话永远找不到人。于是酒店装了一台总机,给每个部门发一个永久短号——“拨 0 找厨房,拨 1 找洗衣房”。部门怎么搬,短号不变,总机负责把电话转接到他们现在住的房间。这就是 Service 的本质:用固定的“号码”屏蔽背后不断流动的“房间”。

在 K8s 集群里,Pod 就像频繁搬家的部门:每次重建 IP 都会变,微服务之间如果直连 Pod IP,代码里就得到处改地址。Service 就是那台总机——一个稳定的“服务名 + 虚拟 IP”。它自己不跑业务进程,只负责“声明”:我代表哪个服务,我的流量该转给谁。正因为这样,Pod 无论怎么扩缩容、怎么重建,调用方都只认 Service 这一个短号。

Service 怎么知道流量该转给谁?靠两样东西:标签选择器(label selector)和 Endpoint。选择器相当于招聘条件,比如“要所有 app 标签等于 web 的 Pod”,符合条件的 Pod 被收进 Endpoint 这份动态通讯录。kube-proxy 监听这份通讯录的变化,把发往 Service 虚拟 IP 的流量,通过 iptables 或 IPVS 规则平均分给名单上的 Pod——这就是最基础的负载均衡。

理解了总机,就理解了 Service 的精髓:它是一层“代理 + 通讯录”,把易变的 Pod 地址挡在身后,让调用方永远只记一个稳定的短号。接下来三节,我们看三种“号码”的差别:内线短号、外线公用号、专属直线。

S={p∈P∣labels(p)⊇selector(S)}\displaystyle S = \{ p \in P \mid \text{labels}(p) \supseteq \text{selector}(S) \}
这个公式表达了 Service 选择后端 Pod 的规则:从集群所有 Pod 中,挑出标签完全覆盖 Service 选择器要求的那些,组成后端集合。
  1. 候选 Pod 全集P 是集群中所有 Pod 的集合,每个 Pod 身上都贴着一组标签(label),相当于部门的属性铭牌。
    P={p1,p2,…,pn}\displaystyle P = \{p_1, p_2, \ldots, p_n\}
  2. 标签匹配条件只有当 Pod 的标签集合包含 Service 选择器要求的全部标签时,才会被选中,多贴标签不碍事,少贴一个就不行。
    labels(p)⊇selector(S)\displaystyle \text{labels}(p) \supseteq \text{selector}(S)
  3. 得到后端集合S 就是该 Service 最终代理的所有后端 Pod,这份名单由 Endpoint 对象动态维护,Pod 增删时会自动刷新。
    S={p∈P∣labels(p)⊇selector(S)}\displaystyle S = \{p \in P \mid \text{labels}(p) \supseteq \text{selector}(S)\}

2. ClusterIP内部访问:只限酒店内部拨打的内线短号

总机默认配的是内线短号:在酒店内部任意一部话机都能拨,但出了酒店大门就完全失效。ClusterIP 正是如此——它是集群内部的一个虚拟 IP,只能在集群内访问,外面根本找不到这条路。这也是为什么刚接触 K8s 的人,照着教程创建了一个 Service,却发现浏览器从外面访问不到——因为人家本来就是“内线”。

这是 K8s 的默认 Service 类型,也是微服务之间互相调用的主力。前端 Pod 访问后端服务时,直接在代码里写服务名(如 order-service.default.svc),由 CoreDNS 解析到 ClusterIP。后端扩容到 5 个副本、IP 全部换新,前端代码一行都不用改。就像客人只记“拨 0 找厨房”,从来不需要知道厨房此刻在 301 还是 305。

技术细节上,kube-proxy 通过 watch API 实时监听 Service 与 Endpoint 的变化,在每台节点上写入 iptables 规则(新版集群常用 IPVS),把发往 ClusterIP 的数据包做 DNAT,改写为后端 Pod IP 再转发,并按权重做轮询。ClusterIP 的局限是“只进不出”——外部流量无法直达,于是酒店又推出了外线方案。

内线短号虽然方便,但外面的访客根本打不进来。于是酒店推出“外线电话”方案——这就是 NodePort。

请求→DNATClusterIP:port⇒Podi:targetPort\displaystyle \text{请求} \xrightarrow{\text{DNAT}} \text{ClusterIP}:\text{port} \Rightarrow \text{Pod}_i:\text{targetPort}
请求进入集群后,目标地址被内核从 ClusterIP 改写成某个后端 Pod 的地址,从而完成一次内部负载均衡转发。
  1. 访问入口集群内的客户端用“虚拟 IP + 端口”发起请求,这个地址创建后永远不变。
    ClusterIP:port\displaystyle \text{ClusterIP}:\text{port}
  2. 地址改写kube-proxy 写入的 iptables/IPVS 规则,将数据包目标地址 DNAT 为某个后端 Pod 的 IP 和端口。
    DNAT:ClusterIP→Podi\displaystyle \text{DNAT}: \text{ClusterIP} \to \text{Pod}_i
  3. 最终送达请求经内核转发到 Pod 的 targetPort 上,完成一次负载均衡分发,整个过程对调用方透明。
    Podi:targetPort\displaystyle \text{Pod}_i:\text{targetPort}

3. NodePort端口暴露:每个楼层的公用外线电话

为了让外面的人也能打进酒店,总机在每一层楼都装了一台公用外线电话:客人拨通酒店总机号,再报“楼层分机号”,电话就被接到对应楼层的房间。NodePort 干的就是这件事:在每个节点上开放同一个端口,外部请求无论打到哪台节点,都会被接进集群。

为什么端口必须落在 30000-32767?因为要避开 80、443 等常见端口,防止和节点上运行的其他服务冲突。你可以用“任意节点 IP + nodePort”访问服务,哪怕集群有 10 个节点,这个端口每台节点都开放。而且请求会先在节点上做负载均衡,自动选择健康的后端 Pod,不需要客户端关心具体 Pod 位置。

NodePort 是 ClusterIP 的超集:外部请求先打到 NodePort 端口,再由 iptables 规则转给 ClusterIP 虚拟 IP,最后 DNAT 到 Pod。也就是说,NodePort 内部自动包含了 ClusterIP 的那套机制,二者不是竞争关系而是叠加关系。它的局限也很明显:范围只有 2768 个端口、无法按域名区分流量、直接把节点暴露在公网有安全隐患,因此不太适合做大规模生产环境的统一入口。

公用外线虽然能打进酒店,但号码繁琐、每层质量参差不齐。酒店决定升级:请一位专职秘书在大门口接听所有来电,自动分配到各个楼层。这就是 LoadBalancer。

NodeIP:nodePort→iptablesClusterIP:port→DNATPodi:targetPort\displaystyle \text{NodeIP}:\text{nodePort} \xrightarrow{\text{iptables}} \text{ClusterIP}:\text{port} \xrightarrow{\text{DNAT}} \text{Pod}_i:\text{targetPort}
外部流量进入任一节点的 NodePort 端口后,沿“节点端口 → 虚拟 IP → Pod”的链路层层转发,最终到达业务容器。
  1. 节点监听端口每个节点都监听同一个 nodePort,这是外部流量的统一入口,类似每个楼层那部公用电话。
    nodePort∈[30000,32767]\displaystyle \text{nodePort} \in [30000, 32767]
  2. 转发到 ClusterIP请求先被 iptables 规则转到 Service 的虚拟 IP 和端口上,复用 ClusterIP 的分发能力。
    NodeIP:nodePort→ClusterIP:port\displaystyle \text{NodeIP}:\text{nodePort} \to \text{ClusterIP}:\text{port}
  3. 再转给 Pod最后由 ClusterIP 的 DNAT 规则把请求送到具体的后端 Pod,完成整条链路。
    ClusterIP:port→Podi:targetPort\displaystyle \text{ClusterIP}:\text{port} \to \text{Pod}_i:\text{targetPort}

4. LoadBalancer云负载:自带秘书应答的直线电话

LoadBalancer 相当于在酒店门口请了一位专属前台秘书:客人只需记住一个对外直拨号码,秘书接听后根据各层忙碌情况,自动把电话转给某个楼层的公用外线。在云上,这位“秘书”就是云厂商提供的负载均衡器,比如阿里云 SLB、AWS ELB。

当 Service 类型设为 LoadBalancer 时,云平台的负载均衡控制器会自动创建一台真正的负载均衡设备,分配一个公网 IP,并把流量转发到集群所有节点的 NodePort 上。因此 LoadBalancer 是 NodePort 的超集——它完全包含 NodePort 和 ClusterIP 的能力,只是最外层多挂了一个云负载均衡器。用户只访问固定的公网 IP,云 LB 负责健康检查和自动分发。

好处是有统一公网入口、自带健康检查、可配合云防火墙和 DDoS 防护;代价是钱——每建一个 LoadBalancer 通常都要付费。如果你有 30 个微服务都想暴露到公网,每服务配一个 LoadBalancer,云账单会非常难看。所以生产实践中,LoadBalancer 一般只给少量“大门”用,剩下几十个服务统一交给 Ingress 在前端汇聚。

秘书虽然能干,但只会“平均分配电话”,不会问客人“你来干嘛”。真正聪明的分流要交给大堂礼宾员——Ingress。

ExternalIP→云LBNodeIP:nodePort→ClusterIP:port→Podi:targetPort\displaystyle \text{ExternalIP} \xrightarrow{\text{云LB}} \text{NodeIP}:\text{nodePort} \to \text{ClusterIP}:\text{port} \to \text{Pod}_i:\text{targetPort}
一条外部请求完整穿越四层:公网 IP → 云负载均衡器 → 节点端口 → 虚拟 IP → 后端 Pod,每一层都是一次转发。
  1. 云上入口云负载均衡器提供一个公网 IP,所有外部流量先汇聚到秘书这里。
    ExternalIP:LBPort\displaystyle \text{ExternalIP}:\text{LBPort}
  2. 分发到节点云 LB 把流量转发给集群中某个节点的 nodePort 端口,完成跨网络接入。
    NodeIP:nodePort\displaystyle \text{NodeIP}:\text{nodePort}
  3. 逐层下钻随后请求按 NodePort → ClusterIP → Pod 的链路最终送达后端,云 LB 只负责第一跳。
    ClusterIP:port→Podi:targetPort\displaystyle \text{ClusterIP}:\text{port} \to \text{Pod}_i:\text{targetPort}

5. Ingress路由规则:大堂礼宾员的“访客分流手册”

想象酒店大堂站着一位礼宾员,客人进门会主动说:“我要去健身房”或“我要去二楼中餐厅”。礼宾员不看电话号码,只根据“访客目的地”(请求的域名和路径)把他领到正确楼层。Ingress 就是这位礼宾员,工作在 HTTP/HTTPS 第七层,比 Service 的端口转发聪明得多——同样的门口,既能去健身房,也能去餐厅。

技术上,Ingress 是一种 API 资源对象,只写规则、不干活。一条规则由三个要素组成:host(域名)、path(路径)和 backend(后端 Service)。例如:当请求的 host 是 demo.com 且路径以 /api 开头时,转给 api-service;路径以 / 开头时,转给 web-service。多个服务共享一个公网入口,一个 Ingress 就能替代十几个 LoadBalancer。

真正执行规则的是 Ingress Controller——一个运行在集群里、时刻 watch Ingress 资源变化的代理进程,通常是 Nginx 或 Traefik。它把规则翻译成真实的代理配置并热加载,做到“规则一改,秒级生效”。需要注意:Ingress 默认只处理 HTTP/HTTPS,不处理 TCP/UDP;路径重写、限流、跨域等高级能力必须依赖对应 Controller 的注解(annotation)才能实现。

礼宾员不仅指路,有时还要替客人拆封加密的挂号信——这就是 TLS 终结。

f(host,path)=Servicej\displaystyle f(\text{host}, \text{path}) = \text{Service}_j
Ingress 的本质是一个“主机 + 路径 → 后端服务”的映射函数,礼宾员根据访客的“目的地”查手册决定带他去哪。
  1. 主机匹配请求头中的域名 host 决定匹配哪一组规则,类似访客说“我找的是上海这家店”。
    host=demo.com\displaystyle \text{host} = \text{demo.com}
  2. 路径匹配URL 的 path 进一步决定转给哪个后端服务,类似访客补充“我要去健身房”。
    path=/api/users\displaystyle \text{path} = /api/\text{users}
  3. 规则映射二者组合后唯一映射到某个后端 Service,由 Ingress Controller 落地为代理配置并执行转发。
    demo.com+/api  ⇒  api-service\displaystyle \text{demo.com} + /api \;\Rightarrow\; \text{api-service}

6. TLS安全终结:礼宾员代拆加密挂号信

酒店与重要客人通信时要用加密挂号信(HTTPS)。但每个部门都配一套钥匙(证书)太麻烦,于是礼宾员负责在门口统一拆信:客人与酒店之间走加密通道,礼宾员用唯一的“官方印章”(服务器证书)验明正身、拆开信封,再把内容以明信片形式转交给内部部门。内部部门不用管加密,专心干活就行。

这就是 Ingress 的 TLS 终结(TLS termination):所有 HTTPS 请求在入口处统一解密,再以 HTTP 明文转发给后端 Service。证书以 Secret 资源保存在集群中,Ingress 规则里通过 tls 字段声明引用哪个 Secret。证书快过期时,只需替换 Secret 内容,再让 Controller 重新加载即可,无需改动任何 Pod。

好处是集中管理证书、把加解密的 CPU 开销挡在业务 Pod 之外;坏处是“Ingress 到后端”这段是明文。如果后端同样在公网或跨网络,就需要启用 TLS 透传(passthrough)或再加密;如果后端与 Ingress 在同一个集群内网,明文风险通常可以接受。很多生产集群的做法是:边缘 Ingress 终结公网 HTTPS,集群内部再用 mTLS 或网络策略兜底。

实践上,礼宾员的“工作手册”不止一本——主流是 nginx-ingress 和 Traefik,我们比一比哪本更适合你的酒店。

Client↔TLS443Ingress→HTTP明文80Service\displaystyle \text{Client} \xleftrightarrow[\text{TLS}]{443} \text{Ingress} \xrightarrow[\text{HTTP明文}]{80} \text{Service}
加密只在客户端与 Ingress 之间生效,Ingress 到后端 Service 之间是明文 HTTP,这就是“终结”二字的含义。
  1. 加密链路客户端与 Ingress 之间使用 443 端口建立 TLS 加密通道,挂号信在门口还是密封的。
    Client⇔Ingress  (TLS,443)\displaystyle \text{Client} \Leftrightarrow \text{Ingress} \;(\text{TLS}, 443)
  2. 证书校验Ingress 用 Secret 中保存的证书完成握手与身份验证,相当于验明官方印章。
    Certificate=Secrettls-cert\displaystyle \text{Certificate} = \text{Secret}_{\text{tls-cert}}
  3. 明文转发解密后 Ingress 用明文 HTTP 把请求转发给后端 Service,部门收到的是已拆封的明信片。
    Ingress→Service  (HTTP,80)\displaystyle \text{Ingress} \to \text{Service} \;(\text{HTTP}, 80)

7. 控制器选型对比:老牌礼宾员与智能礼宾员的较量

同样是礼宾员,老牌 nginx-ingress 经验丰富:手册厚、规则细、眼神利落,能扛住春运级人流;新秀 Traefik 则是智能机器人:自带雷达(watch 机制),大厅新开一家餐厅,它立刻自动记进手册,不用人工更新。两者服务的是同一套 Ingress 资源标准,风格却截然不同。

nginx-ingress 基于 Nginx 与 OpenResty/ngx_lua,单实例吞吐量高、社区庞大、注解丰富,支持路径重写、限流、CORS、认证等大量高级特性,适合高并发生产环境;代价是修改配置后通常需要 reload,动态性稍弱,部署和排查需要一定的 Nginx 功底。Traefik 用 Go 编写,通过 watch API 自动发现 Service 和 Ingress 变化,配置热更新无需重启,自带可视化 Web 面板,还支持 Consul、Rancher、Docker 等多种后端;代价是内存占用略高、极致性能略逊于 Nginx。

选型建议很直白:追求极致吞吐、团队熟悉 Nginx 语法,选 nginx-ingress;强调快速迭代、自动化运维、可视化可观测,选 Traefik。两者都服从同一个 Ingress API,迁移成本很低,甚至可以在一个集群里同时部署两套 Controller,用不同的 IngressClass 做灰度对比。

无论选哪本手册,礼宾员服务的都是同一套酒店规则。理解 Service 与 Ingress 的层层叠加关系,你就能像配置酒店电话一样,为每个服务搭出最合适的“指路系统”:内部调用用 ClusterIP,临时对外用 NodePort,正式大门用 LoadBalancer,复杂分流交给 Ingress。

Tnginx>Ttraefik,Configtraefik=auto_reload\displaystyle T_{\text{nginx}} > T_{\text{traefik}}, \quad \text{Config}_{\text{traefik}} = \text{auto\_reload}
一句话权衡:Nginx 赢在性能上限,Traefik 赢在配置动态性,二者没有绝对的优劣,只有适不适合你的场景。
  1. 性能维度nginx-ingress 使用静态编译的模块与 Lua 扩展,单实例吞吐量通常高于 Traefik。
    Tnginx>Ttraefik\displaystyle T_{\text{nginx}} > T_{\text{traefik}}
  2. 配置维度Traefik 通过 watch API 自动发现服务变化,配置即改即生效;nginx 需要 reload 加载新配置。
    Configtraefik=auto_reload\displaystyle \text{Config}_{\text{traefik}} = \text{auto\_reload}
  3. 统一标准两者都实现同一个 Ingress 资源规范,规则写法一致,业务迁移成本极低。
    Rule∼Ingress API\displaystyle \text{Rule} \sim \text{Ingress API}

AI 应用场景

场景一:微服务网关统一入口(Ingress 分流)

阶段:服务暴露与流量接入

解决的问题:某电商平台有订单、支付、用户等 30 多个微服务,若每个服务都创建 LoadBalancer,云费用高昂且公网入口混乱。传统做法要为每个服务单独申请公网 IP,管理和安全策略都很痛苦。用 Ingress 统一入口按域名和路径分流:api.example.com/orders 转到 order-service,api.example.com/pay 转到 pay-service,并统一做 TLS 终结管理证书。

具体案例:业务侧把 Ingress 当作一张“流量路由表”,新服务上线只需追加一条规则,Ingress Controller 秒级热更新,无需重启集群;配合 IngressClass 还能在 nginx 与 Traefik 之间平滑切换。

场景二:大促流量洪峰下的 LoadBalancer 弹性入口

阶段:流量分发与弹性伸缩

解决的问题:大促期间外部流量暴涨,Pod 实例频繁扩缩容,Pod IP 不断变化。若客户端直连 Pod 或 NodePort,任何一个节点宕机都会导致入口失效。使用 LoadBalancer 类型 Service 作为入口,云上 SLB/ELB 自动健康检查后端节点端口,配合 HPA 自动扩容 Pod,用户始终访问固定的公网 IP,全程无感知。

具体案例:某 AI 推理服务通过 LoadBalancer 暴露,流量从 100 QPS 涨到 10000 QPS 时,HPA 将 Pod 从 3 个扩容到 30 个,云 LB 自动把请求分发到所有节点,单点故障由健康检查自动摘除。

场景三:集群内域名级服务发现(ClusterIP + CoreDNS)

阶段:微服务间通信

解决的问题:AI 模型服务与特征服务之间需要互相调用,Pod IP 易变导致配置文件频繁失效。通过 Service 提供稳定服务名(如 feature-service.default.svc),CoreDNS 自动解析到 ClusterIP,后端扩容不影响调用方。

具体案例:推荐系统在线服务调用 embedding 服务时,通过 Service 服务名访问;embedding Pod 从 2 副本扩到 10 副本,调用代码零改动,kube-proxy 自动把流量分给新副本。

Python 演示

python83 行
# -*- coding: utf-8 -*-"""模拟 K8s Service 与 Ingress 的流量分发逻辑""" import itertools  class Pod:    def __init__(self, name, labels, ip):        self.name = name        self.labels = labels        self.ip = ip        self.request_count = 0     def handle(self, path):        self.request_count += 1        return "{} 处理了 {} (累计 {} 次)".format(            self.name, path, self.request_count)  class Service:    def __init__(self, name, selector, port):        self.name = name        self.selector = selector        self.port = port        self.endpoints = []        self.cycler = None     def bind(self, pods):        self.endpoints = [p for p in pods                          if all(p.labels.get(k) == v                                 for k, v in self.selector.items())]        self.cycler = itertools.cycle(self.endpoints)     def dispatch(self, path):        if not self.endpoints:            return "{}: 没有可用后端".format(self.name)        pod = next(self.cycler)        return pod.handle(path)  class Ingress:    def __init__(self):        self.rules = []  # (host, path_prefix, service)     def add_rule(self, host, path_prefix, service):        self.rules.append((host, path_prefix, service))     def route(self, host, path):        for h, prefix, svc in self.rules:            if host == h and path.startswith(prefix):                return "[Ingress] {} -> {}".format(                    svc.name, svc.dispatch(path))        return "[Ingress] 404: 无匹配规则"  def main():    pods = [        Pod("web-v1-1", {"app": "web", "version": "v1"}, "10.0.0.11"),        Pod("web-v1-2", {"app": "web", "version": "v1"}, "10.0.0.12"),        Pod("api-v1-1", {"app": "api", "version": "v1"}, "10.0.0.21"),        Pod("api-v1-2", {"app": "api", "version": "v1"}, "10.0.0.22"),    ]    web_svc = Service("web-service", {"app": "web"}, 80)    api_svc = Service("api-service", {"app": "api"}, 80)    web_svc.bind(pods)    api_svc.bind(pods)     ing = Ingress()    ing.add_rule("demo.com", "/", web_svc)    ing.add_rule("demo.com", "/api", api_svc)     for host, path in [        ("demo.com", "/"),        ("demo.com", "/api/users"),        ("demo.com", "/"),        ("demo.com", "/api/orders"),        ("demo.com", "/other"),    ]:        print(ing.route(host, path))  if __name__ == "__main__":    main()
目的:用纯 Python 模拟 K8s 中 Service 的标签选择与轮询分发、Ingress 的 host + path 路由,帮助你直观理解流量走向。
  1. self.endpoints = [p for p in pods if all(p.labels.get(k) == v for k, v in self.selector.items())]实现 Service 的“标签选择器”:只有标签完全匹配 selector 的 Pod 才会进入后端通讯录,等价于 Endpoint 的生成逻辑。
  2. self.cycler = itertools.cycle(self.endpoints)用 itertools.cycle 制造无限轮询迭代器,模拟 kube-proxy 的默认轮询负载均衡。
  3. pod = next(self.cycler)每次派发请求都取下一个 Pod,让流量在两个后端之间轮流分发,不会总压在一个 Pod 上。
  4. if host == h and path.startswith(prefix)Ingress 路由规则的核心:host 精确匹配 + path 前缀匹配,命中后才把请求交给对应 Service。
  5. ing.add_rule("demo.com", "/api", api_svc)注册一条 Ingress 规则,等价于 YAML 里 host、path、backend 三要素的声明。

常见误区

误区很多初学者以为 ClusterIP、NodePort、LoadBalancer 是三种互斥的选项,选了一个就不能用另一个,就像在菜单上只能点一道主菜,点了“ClusterIP 套餐”就不能再点“NodePort 套餐”。

正解实际上它们是层层叠加的关系:NodePort 内部包含 ClusterIP 的能力,LoadBalancer 内部又包含 NodePort 的能力。就像酒店电话从“内线短号”升级到“楼层外线”再到“专属直线”,都是在前一层基础上加设备。查看一个 LoadBalancer 类型 Service 的 YAML,你会发现它同时带有 clusterIP 和 nodePort 字段——这正是叠加关系的铁证。

为何常见:K8s 官方文档常把三种类型并列展示,表格形式容易让人误以为它们是平级的三个选项;日常使用往往只用其中一种,看不到内部的嵌套链路。

误区看到“创建一个 Ingress 对象”,就以为它是一个正在运行的负载均衡器,像 Nginx 一样自己监听端口、处理请求,apply 完 YAML 就该立即生效。

正解Ingress 只是一份“规则声明”,相当于贴在墙上的访客分流手册——手册自己不会指路。真正干活的是 Ingress Controller,一个独立运行的代理进程,它 watch 到 Ingress 资源后,把规则翻译成 Nginx 或 Traefik 的真实配置并加载。集群里没装 Controller,你创建一百个 Ingress 也不会有任何流量被转发。

为何常见:资源名与实现组件同名(都叫 Ingress),加上 kubectl apply 太容易,让人产生“创建即生效”的错觉。

误区看到 Service 定义里 `port: 8080` 随便填,就以为 `nodePort` 也可以写 8080、8888 这种自己习惯的端口,只要不冲突就行。

正解nodePort 有硬性范围限制:默认必须在 30000-32767 之间,这是 apiserver 预留的段,用于避免与节点上的系统服务端口冲突。超出范围,创建 Service 时 API Server 会直接报错拒绝。即使想通过修改 apiserver 启动参数 --service-node-port-range 扩大范围,也强烈不推荐,因为那会引入大量端口冲突隐患。

为何常见:port 和 targetPort 确实可以随意指定,初学者容易把规则迁移到 nodePort 上,忽视了“节点级端口”的特殊约束。

误区LoadBalancer 能提供公网入口,Ingress 也提供入口,那直接用 LoadBalancer 不就行了?Ingress 看起来多余,还要多学一个概念。

正解一个 LoadBalancer 对应一个公网 IP,按云厂商计费每一个都花钱。几十个微服务如果全部配 LoadBalancer,云账单会指数级膨胀。Ingress 的价值恰恰是“用一个入口汇聚多个服务”,按域名和路径做七层分流,还能统一做 TLS 终结。生产上最经典的组合是:最外层用少量 LoadBalancer 做大门,内层用 Ingress 做精细路由。

为何常见:只在很小的实验集群中接触过单个服务暴露,没有经历过几十个服务入口成本的放大效应,自然看不到 Ingress 的不可替代性。

误区ClusterIP 是集群内部虚拟 IP,所以外部网络永远访问不到它,想从外面访问只能换成 NodePort 或 LoadBalancer。

正解ClusterIP 是“不直接对外暴露”,但仍有间接通道:kubectl proxy 会在本地开一个端口代理到 Service;kubectl port-forward 可以把本地端口转发到集群内;另外 Ingress Controller 本身也是通过 ClusterIP 访问后端 Service 的。它只是没有“公网直连”能力,绝非“绝对不可达”。

为何常见:把“默认不可达”简单理解成“永远不可达”,忽略了 kubectl 管理通道和 Ingress 内部链路的间接访问场景。

面试题

Q1. 在 Kubernetes 中,默认的 Service 类型是哪一个?

单选题 · easy

  • A.它只在集群内部提供稳定的虚拟 IP 访问← 正确答案
  • B.它在每个节点上开放一个固定的端口
  • C.它由云厂商分配一个公网的负载均衡
  • D.它负责七层的 HTTP 域名路由转发

答案:A。默认类型是 ClusterIP,相当于酒店的“内线短号”,只在集群内部提供一个稳定的虚拟 IP 入口。NodePort 解决外部端口访问,LoadBalancer 引入云负载均衡器,而 Ingress 根本不是 Service 类型,而是独立的七层路由资源。

Q2. NodePort 类型 Service 的端口号合法范围是?

单选题 · easy

  • A.1 到 65535 之间的任意端口
  • B.30000 到 32767 之间的保留段← 正确答案
  • C.1024 到 49151 之间的动态段
  • D.仅限 80 与 443 两个常用端口

答案:B。nodePort 默认范围是 30000-32767,这是 APIServer 预留的保留段,目的是避免与节点上系统服务、常用业务端口冲突。范围可通过 --service-node-port-range 参数调整,但生产环境不建议随意扩大。

Q3. 下面哪种 Service 类型是在 NodePort 基础上叠加实现的?

单选题 · mid

  • A.ClusterIP 只在集群内部提供虚拟 IP
  • B.NodePort 在每个节点都开放端口
  • C.LoadBalancer 由云厂商分配公网地址← 正确答案
  • D.Ingress 使用域名和路径进行路由

答案:C。LoadBalancer 是在 NodePort 外层再挂一台云负载均衡器,外部流量先到云 LB 的公网 IP,再转发到节点端口,随后走 NodePort → ClusterIP → Pod 的链路。它完整包含 NodePort 和 ClusterIP 的能力,是三层中的最高层。

Q4. 真正把收到的请求按规则转发给后端服务的组件是?

单选题 · mid

  • A.Ingress 资源只是一组声明规则
  • B.Ingress Controller 才是执行者← 正确答案
  • C.kube-proxy 处理 Service 四层流量
  • D.CoreDNS 负责集群内域名解析

答案:B。Ingress 只是一个声明规则的资源对象,像贴在墙上的分流手册;真正干活的是 Ingress Controller(如 nginx-ingress、Traefik)。Controller 监听 Ingress 资源并生成代理配置,按 host/path 把流量转发给后端 Service,没有它 Ingress 不会产生任何效果。

Q5. 关于 Ingress 的路由规则,下列哪些说法是正确的?

多选题 · mid

  • A.可以根据请求的域名 host 进行匹配← 正确答案
  • B.可以根据 URL 的路径前缀进行匹配← 正确答案
  • C.一个规则可以绑定多个后端服务
  • D.规则修改后必须重启整个集群

答案:AB。Ingress 通过 host 与 path 组合定位后端 Service,两者可以单独或同时指定,通配符域名也支持。规则修改后 Controller 会自动热更新代理配置,无需重启集群或节点。每条路由规则最终只指向一个后端 Service。

Q6. kube-proxy 默认基于哪种技术实现 ClusterIP 的流量转发?

单选题 · easy

  • A.iptables 规则链实现内核转发← 正确答案
  • B.域名解析做轮询负载均衡
  • C.应用层代理转发 HTTP 请求
  • D.容器网络插件提供扁平网络

答案:A。kube-proxy 监听 Service 与 Endpoint 变化,把转发规则写入 iptables(或 IPVS),内核按规则对发往 ClusterIP 的数据包做 DNAT,改写为后端 Pod IP 后转发。它不是域名解析组件(那是 CoreDNS 的活),也不是应用层代理。

Q7. 关于 Service 的 Endpoint,以下说法正确的是?

多选题 · mid

  • A.它记录了后端 Pod 的 IP 与端口← 正确答案
  • B.它由 Endpoint Controller 自动维护← 正确答案
  • C.它会在 Pod 增删后自动更新← 正确答案
  • D.它由 Ingress 控制器负责生成

答案:ABC。Endpoint 是 Service 与 Pod 之间的“通讯录”,由 kube-controller-manager 中的 Endpoint Controller 根据标签选择器自动生成与维护。Pod 宕机、扩充副本时列表自动刷新,新 Pod 加入即可被转发。Ingress Controller 负责的是七层路由规则,与 Endpoint 生成无关。

Q8. 外部请求访问 LoadBalancer 类型 Service 的正确链路是?

单选题 · hard

  • A.用户访问云 LB 公网 IP 再转发到节点端口← 正确答案
  • B.用户直接访问 Pod 的容器网络 IP 地址
  • C.用户先访问每个节点的 ClusterIP 虚拟 IP
  • D.用户直接连接 Ingress 控制器的管理端口

答案:A。完整链路是 ExternalIP → 云负载均衡器 → NodeIP:NodePort → ClusterIP:Port → Pod:targetPort。云 LB 负责把公网流量分发到各节点端口,节点内再由 iptables 规则经 ClusterIP 最终 DNAT 到后端 Pod。B 选项 Pod IP 会变且不可直接访问,C 选项 ClusterIP 只在集群内有效。

Q9. 关于 Ingress 的 TLS 终结机制,以下描述正确的是?

单选题 · hard

  • A.证书统一保存在 Secret 中供 Ingress 使用← 正确答案
  • B.后端每个 Pod 都需要单独配置证书
  • C.客户端到后端全程保持加密传输
  • D.TLS 终结只能由云负载均衡器完成

答案:A。Ingress 的 TLS 终结将证书集中放在 Secret 资源里,由 Ingress Controller 完成 HTTPS 握手与解密,再以明文 HTTP 转发给后端 Service。这样后端 Pod 无需管理证书,但注意 Ingress 到后端之间是明文;需要全程加密时应启用 TLS 透传或二次加密。

Q10. 对比 nginx-ingress 与 Traefik,下列哪些说法是正确的?

多选题 · extreme

  • A.nginx-ingress 社区成熟且性能上限更高← 正确答案
  • B.Traefik 通过 watch 实现配置自动热更新← 正确答案
  • C.Traefik 内置了可视化 Web 管理面板← 正确答案
  • D.nginx-ingress 完全不支持注解扩展机制

答案:ABC。nginx-ingress 基于 Nginx 与 OpenResty,单实例吞吐量高、注解丰富但配置改动通常需要 reload;Traefik 通过 watch API 自动发现集群变化并热更新配置,内置 Dashboard 且支持多种后端平台。两者都遵循统一 Ingress 资源标准,nginx-ingress 也支持大量 nginx.ingress.kubernetes.io/* 注解,D 说法错误。