路线图

Ingress 实战:从 Service 到七层路由

星辉 2026-07-02 阅读 6 min 1,137 字 路线图
Ingress 实战:从 Service 到七层路由 封面

概述#

在前面的章节中,我们已经学习了 Service——它是 Kubernetes 集群内部的"内线电话",负责把 Pod 的端口暴露给集群内的其他服务。但当你的应用需要对外提供服务时,Service 就显得不够用了:

  • NodePort 需要在每个节点上开放端口,端口范围受限(30000-32767),且需要对外暴露节点 IP
  • LoadBalancer 虽然能正常工作,但每个 Service 都要创建一个云负载均衡器,成本高且管理复杂

Ingress 就是来解决这个问题的:它是 Kubernetes 的七层(HTTP/HTTPS)统一入口,一个 Ingress 就能把集群内多个服务暴露到同一个域名或 IP 下,按 Host 和 Path 做路由转发。

类比一下:

  • Service 是"内线电话"——集群内部服务之间打电话,直接拨分机号(ClusterIP:Port)
  • Ingress 是"前台总机"——外部用户打公司总机号码,前台根据你要找的人(域名+路径)把电话转接到对应的分机

2026 现状:Ingress API 本身已进入维护模式,社区主推的继任者是 Gateway API(v1.0 已 GA,表达能力更强、角色划分更清晰、原生支持更多协议)。存量集群 Ingress 仍在大量使用,作为入门与生产的基础依然值得掌握;新项目可评估直接上 Gateway API。


Ingress vs Service:四层还是七层?#

要理解 Ingress 和 Service 的区别,核心是搞清楚网络层级

对比项ServiceIngress
网络层级L4(传输层:TCP/UDP)L7(应用层:HTTP/HTTPS)
路由依据IP + PortHost(域名) + Path(路径) + Header
暴露范围集群内部(ClusterIP)或节点级(NodePort)集群外部(通过 Ingress Controller)
TLS 终止不支持(需要应用自己处理)支持(在 Ingress Controller 层终止 TLS)
典型使用场景微服务间内部调用对外提供 HTTP/HTTPS 服务

Service 的工作方式#

Service 工作在四层,它只关心"IP + 端口",不解析 HTTP 协议内容:

text
外部请求 → LoadBalancer/NodePort → Service (iptables/IPVS) → Pod

Service 能做到的路由非常有限:

  • label selector 选择后端 Pod
  • 支持简单的会话保持(基于客户端 IP 的哈希)
  • 支持 TCP/UDP 流量(不关心上层协议)

Ingress 的工作方式#

Ingress 工作在七层,它能解析 HTTP 请求的内容:

text
外部请求 → Ingress Controller (LoadBalancer) → Ingress 规则匹配 → Service → Pod

Ingress 能做到的路由非常灵活:

  • Host 路由:api.example.com → api-service,web.example.com → web-service
  • Path 路由:/api/* → api-service,/admin/* → admin-service
  • Header 路由(部分 Controller 支持):X-Version: v2 → canary-service
  • TLS 终止:在 Ingress Controller 层解密 HTTPS,后端 Pod 只处理 HTTP
  • 流量控制:限流、超时、重试(取决于 Controller 实现)

什么时候用 Service,什么时候用 Ingress?#

用 Service

  • 集群内部服务间调用(如 backend 访问 database)
  • 非 HTTP 协议(如 gRPC、MySQL、Redis)
  • 需要四层负载均衡的场景

用 Ingress

  • 对外提供 HTTP/HTTPS 服务
  • 需要基于域名或路径的路由
  • 需要集中管理 TLS 证书
  • 需要七层流量控制(限流、认证、重写)

Ingress Controller:规则的"执行者"#

重要概念:Ingress 只是一个声明式资源配置,它定义了"流量应该怎么路由",但它自己不做任何转发。真正处理流量的是 Ingress Controller

类比:Ingress 是"路由表",Ingress Controller 是"前台总机接线员"——路由表告诉接线员怎么转接,接线员真正执行转接动作。

架构关系#

text
外部流量
LoadBalancer / 主机 IP
Ingress Controller(作为 Pod 运行在集群内)
    ↓ 读取 Ingress 资源的定义
根据规则转发
Service(ClusterIP)
Pod

主流 Ingress Controller 对比#

Controller特点适用场景
NGINX Ingress Controller最成熟、文档最全、社区最大绝大多数场景的首选
Traefik自动服务发现、美观的 Dashboard动态环境、需要可视化
HAProxy Ingress性能优秀、配置灵活高并发、需要精细化控制
Istio Gateway服务网格集成、L7 策略强大已使用 Istio 的环境
AWS ALB Ingress直接使用 AWS ALBAWS EKS 环境、需要 AWS 原生集成

安装 NGINX Ingress Controller#

生产环境推荐使用 NGINX Ingress Controller(以下简称 NIC),安装方式:

bash
# 添加 Helm 仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# 安装(创建 namespace ingress-nginx)
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace

# 验证安装
kubectl get pods -n ingress-nginx
# NAME                                        READY   STATUS
# ingress-nginx-controller-xxxx   1/1     Running
# ingress-nginx-admission-webhook-xxxx   1/1     Running

安装后会自动创建一个 LoadBalancer 类型的 Service(如果是云环境),或者一个 NodePort 类型的 Service(如果是裸金属):

bash
kubectl get svc -n ingress-nginx
# NAME                       TYPE           EXTERNAL-IP
# ingress-nginx-controller  LoadBalancer   203.0.113.10

这个 EXTERNAL-IP 就是你的 Ingress 的入口地址,把域名(如 app.example.com)解析到这个 IP 即可。

Ingress Class#

从 Kubernetes 1.18 开始,Ingress 支持 ingressClassName 字段,用于指定使用哪个 Ingress Controller(当集群内有多个 Controller 时):

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
spec:
  ingressClassName: nginx   # 指定使用 NGINX Ingress Controller
  rules:
  - host: app.example.com
    http:
      # ... 路由规则

如果集群内只有一种 Controller,可以不写这个字段,Controller 会处理所有 Ingress。


路由规则:Host 匹配 + Path 匹配#

Ingress 的路由规则定义在 spec.rules 中,按 Host 和 Path 两级匹配

基础示例:单域名多路径路由#

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  namespace: production
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com    # 匹配的域名
    http:
      paths:
      - path: /api           # 匹配路径(前缀匹配)
        pathType: Prefix
        backend:
          service:
            name: api-service    # 转发到这个 Service
            port:
              number: 80
      - path: /              # 默认路径
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80

关键点

  • pathType: Prefix 表示前缀匹配:/api/users 会匹配 /api
  • pathType: Exact 表示精确匹配:只匹配 /api,不匹配 /api/users
  • 匹配顺序:NGINX 按规则在 YAML 中的顺序匹配,把最具体的路径放前面/api 在前,/ 在后)

Host 匹配:多域名路由#

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com       # 第一个域名
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80
  - host: web.example.com       # 第二个域名
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

Path 重写#

有时候后端服务期望的路径和 Ingress 暴露的路径不一致(如 Ingress 用 /api/ 路由,但后端服务根路径就是 /):

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-example
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /   # 把匹配到的 path 替换为 /
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80

效果:外部请求 app.example.com/api/users → Ingress Controller 把路径重写为 /users → 转发给 api-service


TLS 证书配置#

Ingress 支持在 Controller 层终止 TLS(解密 HTTPS 请求,转发 HTTP 给后端 Pod),这样后端应用不需要自己处理证书。

方式一:手动创建 TLS Secret#

第一步:准备证书文件(tls.crttls.key

bash
# 假设你已经有证书文件
ls my-cert/
# tls.crt    (证书文件,包含公钥)
# tls.key    (私钥文件)

第二步:创建 tls 类型的 Secret

bash
kubectl create secret tls app-tls-secret \
  --cert=tls.crt \
  --key=tls.key \
  --namespace production

或者写 YAML:

yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-tls-secret
  namespace: production
type: kubernetes.io/tls    # 关键:类型是 tls
data:
  tls.crt: <base64 编码的证书>
  tls.key: <base64 编码的私钥>

注意:生产环境不要直接把证书写进 Git。推荐用 cert-manager 自动申请和续期 Let's Encrypt 证书(进阶内容,本章不展开)。

第三步:在 Ingress 中引用这个 Secret

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example
spec:
  ingressClassName: nginx
  tls:                      # TLS 配置块
  - hosts:
    - app.example.com      # 这个域名的 HTTPS 请求
    secretName: app-tls-secret   # 使用这个 Secret 中的证书
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

方式二:使用 cert-manager 自动管理证书(推荐生产环境)#

cert-manager 是 Kubernetes 的证书管理控制器,能自动:

  • 从 Let's Encrypt 申请免费证书
  • 在证书到期前自动续期
  • 把证书保存为 Kubernetes Secret
yaml
# 1. 创建 ClusterIssuer(Let's Encrypt 生产环境)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
    - http01:
        ingress:
          class: nginx    # 用 NGINX Ingress 做验证

---
# 2. 在 Ingress 中声明使用这个 Issuer
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auto-tls-example
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod   # 关键注解
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls-auto   # cert-manager 会自动创建这个 Secret
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

实战:一个 Ingress 路由三个 Service#

这是最常用的实战场景:你有多个服务,但只想暴露一个公网入口,通过域名路径区分流量。

场景定义#

域名路径转发目标
api.example.com/api-svc:8080
web.example.com/web-svc:3000
api.example.com/adminadmin-svc:9090

第一步:准备后端 Service(假设你已经有对应的 Deployment)#

yaml
# api-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: api-svc
  namespace: production
spec:
  selector:
    app: api
  ports:
  - port: 80
    targetPort: 8080
---
# web-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-svc
  namespace: production
spec:
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 3000
---
# admin-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: admin-svc
  namespace: production
spec:
  selector:
    app: admin
  ports:
  - port: 80
    targetPort: 9090

第二步:创建 Ingress 规则#

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: unified-entry-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /   # 路径重写(如需要)
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    - web.example.com
    secretName: unified-tls-secret     # 两个域名的证书都放这里
  rules:
  # 规则一:api.example.com → api-svc
  - host: api.example.com
    http:
      paths:
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: admin-svc
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-svc
            port:
              number: 80

  # 规则二:web.example.com → web-svc
  - host: web.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

关键点

  • /admin 路径要放在 / 前面,否则 /admin/xxx 会被 / 规则匹配到 api-svc
  • 如果 admin-svc 期望的路径就是 /admin,需要加 rewrite-target: / 注解把 /admin 前缀去掉再转发

第三步:验证#

bash
# 查看 Ingress 状态
kubectl get ingress -n production
# NAME                     CLASS   HOSTS                              ADDRESS         PORTS   AGE
# unified-entry-ingress   nginx   api.example.com,web.example.com   203.0.113.10   80,443   5m

# 测试 HTTP(会自动跳转到 HTTPS,如果配置了 TLS)
curl -L http://api.example.com/health

# 测试 HTTPS
curl https://api.example.com/api/users

# 测试路径路由
curl https://web.example.com/
curl https://api.example.com/admin/dashboard

小结#

本章我们学习了 Kubernetes 的七层流量入口 Ingress

  1. Ingress vs Service:Service 是四层内部暴露(像内线电话),Ingress 是七层外部统一入口(像前台总机),支持基于域名和路径的路由。

  2. Ingress Controller 是执行者:Ingress 只是路由规则的声明,真正处理流量的是 Controller(最常用的是 NGINX Ingress Controller)。安装 Controller 后,它会自动读取集群内所有 Ingress 资源并生成对应的 NGINX 配置。

  3. 路由规则:通过 host 字段匹配域名,通过 path + pathType 匹配路径。pathType: Prefix 是最常用的配置。

  4. TLS 证书:在 Ingress 的 tls 字段中引用一个 tls 类型的 Secret,Controller 会在流量进入时终止 TLS,再把解密后的 HTTP 请求转发给后端 Service。生产环境推荐用 cert-manager 自动管理证书。

  5. 多服务统一入口:一个 Ingress 资源可以通过多个 rules 把不同域名和路径路由到不同 Service,这是 Ingress 最核心的使用场景。

下一步:Ingress 解决的是"流量怎么进入集群"的问题。下一章我们将深入学习 Kubernetes 的网络模型——Pod 之间是怎么通信的、CNI 插件怎么选、DNS 是怎么解析的,以及如何使用 NetworkPolicy 做网络隔离。


实战要点

  • 新手常犯的错误:创建了 Ingress 但忘了安装 Ingress Controller → 规则不生效
  • 路径匹配顺序很重要:/api 要写在 / 前面,否则会被默认规则覆盖
  • TLS 证书的 Common Name(CN)必须和 Ingress 规则中的 host 匹配,否则浏览器会报证书不匹配错误
  • 生产环境务必配置 readinessProbe(就绪探针),避免 Ingress Controller 把流量转发到还未启动完成的 Pod