13-Ingress 生产实战

Ingress 生产实战

概念引入

文章 09 里你学了一个最简单的 Ingress:按域名+路径把流量分到不同 Service。但生产环境远比这复杂:

复制代码
基础 Ingress(#09)             生产 Ingress(本篇)
─────────────────              ─────────────────
http://app.com → web           https://app.com → web        ← TLS 加密
http://app.com/api → api       /api(/.*) → /$1              ← rewrite 重写
                               同一 Service 按 header 分流    ← 金丝雀灰度
                               每个 IP 每秒最多 10 请求        ← 限流保护

本文将同时展示传统 Ingress 注解方式Gateway API 等效实现,帮你理解两者的联系。
#mermaid-svg-ybMOQy3XgiFdqjMZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ybMOQy3XgiFdqjMZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ybMOQy3XgiFdqjMZ .error-icon{fill:#552222;}#mermaid-svg-ybMOQy3XgiFdqjMZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ybMOQy3XgiFdqjMZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ybMOQy3XgiFdqjMZ .marker.cross{stroke:#333333;}#mermaid-svg-ybMOQy3XgiFdqjMZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ybMOQy3XgiFdqjMZ p{margin:0;}#mermaid-svg-ybMOQy3XgiFdqjMZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ybMOQy3XgiFdqjMZ .cluster-label text{fill:#333;}#mermaid-svg-ybMOQy3XgiFdqjMZ .cluster-label span{color:#333;}#mermaid-svg-ybMOQy3XgiFdqjMZ .cluster-label span p{background-color:transparent;}#mermaid-svg-ybMOQy3XgiFdqjMZ .label text,#mermaid-svg-ybMOQy3XgiFdqjMZ span{fill:#333;color:#333;}#mermaid-svg-ybMOQy3XgiFdqjMZ .node rect,#mermaid-svg-ybMOQy3XgiFdqjMZ .node circle,#mermaid-svg-ybMOQy3XgiFdqjMZ .node ellipse,#mermaid-svg-ybMOQy3XgiFdqjMZ .node polygon,#mermaid-svg-ybMOQy3XgiFdqjMZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ybMOQy3XgiFdqjMZ .rough-node .label text,#mermaid-svg-ybMOQy3XgiFdqjMZ .node .label text,#mermaid-svg-ybMOQy3XgiFdqjMZ .image-shape .label,#mermaid-svg-ybMOQy3XgiFdqjMZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-ybMOQy3XgiFdqjMZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ybMOQy3XgiFdqjMZ .rough-node .label,#mermaid-svg-ybMOQy3XgiFdqjMZ .node .label,#mermaid-svg-ybMOQy3XgiFdqjMZ .image-shape .label,#mermaid-svg-ybMOQy3XgiFdqjMZ .icon-shape .label{text-align:center;}#mermaid-svg-ybMOQy3XgiFdqjMZ .node.clickable{cursor:pointer;}#mermaid-svg-ybMOQy3XgiFdqjMZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ybMOQy3XgiFdqjMZ .arrowheadPath{fill:#333333;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ybMOQy3XgiFdqjMZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ybMOQy3XgiFdqjMZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ybMOQy3XgiFdqjMZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ybMOQy3XgiFdqjMZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ybMOQy3XgiFdqjMZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ybMOQy3XgiFdqjMZ .cluster text{fill:#333;}#mermaid-svg-ybMOQy3XgiFdqjMZ .cluster span{color:#333;}#mermaid-svg-ybMOQy3XgiFdqjMZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ybMOQy3XgiFdqjMZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ybMOQy3XgiFdqjMZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-ybMOQy3XgiFdqjMZ .icon-shape,#mermaid-svg-ybMOQy3XgiFdqjMZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ybMOQy3XgiFdqjMZ .icon-shape p,#mermaid-svg-ybMOQy3XgiFdqjMZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ybMOQy3XgiFdqjMZ .icon-shape .label rect,#mermaid-svg-ybMOQy3XgiFdqjMZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ybMOQy3XgiFdqjMZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ybMOQy3XgiFdqjMZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ybMOQy3XgiFdqjMZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HTTPS
TLS 终止后明文转发
/api 请求重写到 /
header: version=v2

→ 金丝雀版本
客户端
Ingress Controller

(Nginx)
web Service
api Service
canary Service

原理讲解

TLS 终止

TLS 终止在 Ingress 层面完成------客户端到 Ingress 是 HTTPS,Ingress 到后端 Pod 是 HTTP:

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-tls
spec:
  tls:
  - hosts:
    - app.example.com
    secretName: app-tls-secret    # 包含证书和私钥的 Secret
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web
            port:
              number: 80

#mermaid-svg-7u4TDkMgvaOCXDJH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7u4TDkMgvaOCXDJH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7u4TDkMgvaOCXDJH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7u4TDkMgvaOCXDJH .error-icon{fill:#552222;}#mermaid-svg-7u4TDkMgvaOCXDJH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7u4TDkMgvaOCXDJH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7u4TDkMgvaOCXDJH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7u4TDkMgvaOCXDJH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7u4TDkMgvaOCXDJH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7u4TDkMgvaOCXDJH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7u4TDkMgvaOCXDJH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7u4TDkMgvaOCXDJH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7u4TDkMgvaOCXDJH .marker.cross{stroke:#333333;}#mermaid-svg-7u4TDkMgvaOCXDJH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7u4TDkMgvaOCXDJH p{margin:0;}#mermaid-svg-7u4TDkMgvaOCXDJH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7u4TDkMgvaOCXDJH .cluster-label text{fill:#333;}#mermaid-svg-7u4TDkMgvaOCXDJH .cluster-label span{color:#333;}#mermaid-svg-7u4TDkMgvaOCXDJH .cluster-label span p{background-color:transparent;}#mermaid-svg-7u4TDkMgvaOCXDJH .label text,#mermaid-svg-7u4TDkMgvaOCXDJH span{fill:#333;color:#333;}#mermaid-svg-7u4TDkMgvaOCXDJH .node rect,#mermaid-svg-7u4TDkMgvaOCXDJH .node circle,#mermaid-svg-7u4TDkMgvaOCXDJH .node ellipse,#mermaid-svg-7u4TDkMgvaOCXDJH .node polygon,#mermaid-svg-7u4TDkMgvaOCXDJH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7u4TDkMgvaOCXDJH .rough-node .label text,#mermaid-svg-7u4TDkMgvaOCXDJH .node .label text,#mermaid-svg-7u4TDkMgvaOCXDJH .image-shape .label,#mermaid-svg-7u4TDkMgvaOCXDJH .icon-shape .label{text-anchor:middle;}#mermaid-svg-7u4TDkMgvaOCXDJH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7u4TDkMgvaOCXDJH .rough-node .label,#mermaid-svg-7u4TDkMgvaOCXDJH .node .label,#mermaid-svg-7u4TDkMgvaOCXDJH .image-shape .label,#mermaid-svg-7u4TDkMgvaOCXDJH .icon-shape .label{text-align:center;}#mermaid-svg-7u4TDkMgvaOCXDJH .node.clickable{cursor:pointer;}#mermaid-svg-7u4TDkMgvaOCXDJH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7u4TDkMgvaOCXDJH .arrowheadPath{fill:#333333;}#mermaid-svg-7u4TDkMgvaOCXDJH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7u4TDkMgvaOCXDJH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7u4TDkMgvaOCXDJH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7u4TDkMgvaOCXDJH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7u4TDkMgvaOCXDJH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7u4TDkMgvaOCXDJH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7u4TDkMgvaOCXDJH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7u4TDkMgvaOCXDJH .cluster text{fill:#333;}#mermaid-svg-7u4TDkMgvaOCXDJH .cluster span{color:#333;}#mermaid-svg-7u4TDkMgvaOCXDJH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7u4TDkMgvaOCXDJH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7u4TDkMgvaOCXDJH rect.text{fill:none;stroke-width:0;}#mermaid-svg-7u4TDkMgvaOCXDJH .icon-shape,#mermaid-svg-7u4TDkMgvaOCXDJH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7u4TDkMgvaOCXDJH .icon-shape p,#mermaid-svg-7u4TDkMgvaOCXDJH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7u4TDkMgvaOCXDJH .icon-shape .label rect,#mermaid-svg-7u4TDkMgvaOCXDJH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7u4TDkMgvaOCXDJH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7u4TDkMgvaOCXDJH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7u4TDkMgvaOCXDJH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} K8s 集群
公网
🔒 HTTPS
明文 HTTP
浏览器
Ingress

持有 TLS 证书
web Pod

HTTP

证书管理:生产中用 cert-manager 自动申请/续期 Let's Encrypt 证书:

yaml 复制代码
# cert-manager 自动管理证书(注解)
metadata:
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"

Rewrite:路径重写

后端服务通常不关心路由路径------/api/users 对后端来说就是 /users

yaml 复制代码
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - http:
      paths:
      - path: /api(/|$)(.*)    # 捕获组
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-service
            port:
              number: 8080
复制代码
请求路径                    →  到达后端的路径
─────────────────────────────────────────
/api/users                 →  /users
/api/orders/123            →  /orders/123
/                          →  /(不走 rewrite)

Gateway API 等效 :HTTPRoute 通过 filters 实现:

yaml 复制代码
filters:
- type: URLRewrite
  urlRewrite:
    path:
      type: ReplacePrefixMatch
      replacePrefixMatch: /

金丝雀灰度:基于 Header 分流

不切流量到新版本,仅让特定用户(带 header)看到新版本:

yaml 复制代码
# 主 Ingress(稳定版本------所有流量默认走这里)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-stable
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-v1
            port:
              number: 80
---
# 金丝雀 Ingress(紧带特定 header 的请求走 v2)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "x-version"
    nginx.ingress.kubernetes.io/canary-by-header-value: "v2"
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-v2
            port:
              number: 80

#mermaid-svg-b4ty3IL7GqXXgIRo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-b4ty3IL7GqXXgIRo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-b4ty3IL7GqXXgIRo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-b4ty3IL7GqXXgIRo .error-icon{fill:#552222;}#mermaid-svg-b4ty3IL7GqXXgIRo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-b4ty3IL7GqXXgIRo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-b4ty3IL7GqXXgIRo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-b4ty3IL7GqXXgIRo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-b4ty3IL7GqXXgIRo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-b4ty3IL7GqXXgIRo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-b4ty3IL7GqXXgIRo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-b4ty3IL7GqXXgIRo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-b4ty3IL7GqXXgIRo .marker.cross{stroke:#333333;}#mermaid-svg-b4ty3IL7GqXXgIRo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-b4ty3IL7GqXXgIRo p{margin:0;}#mermaid-svg-b4ty3IL7GqXXgIRo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-b4ty3IL7GqXXgIRo .cluster-label text{fill:#333;}#mermaid-svg-b4ty3IL7GqXXgIRo .cluster-label span{color:#333;}#mermaid-svg-b4ty3IL7GqXXgIRo .cluster-label span p{background-color:transparent;}#mermaid-svg-b4ty3IL7GqXXgIRo .label text,#mermaid-svg-b4ty3IL7GqXXgIRo span{fill:#333;color:#333;}#mermaid-svg-b4ty3IL7GqXXgIRo .node rect,#mermaid-svg-b4ty3IL7GqXXgIRo .node circle,#mermaid-svg-b4ty3IL7GqXXgIRo .node ellipse,#mermaid-svg-b4ty3IL7GqXXgIRo .node polygon,#mermaid-svg-b4ty3IL7GqXXgIRo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-b4ty3IL7GqXXgIRo .rough-node .label text,#mermaid-svg-b4ty3IL7GqXXgIRo .node .label text,#mermaid-svg-b4ty3IL7GqXXgIRo .image-shape .label,#mermaid-svg-b4ty3IL7GqXXgIRo .icon-shape .label{text-anchor:middle;}#mermaid-svg-b4ty3IL7GqXXgIRo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-b4ty3IL7GqXXgIRo .rough-node .label,#mermaid-svg-b4ty3IL7GqXXgIRo .node .label,#mermaid-svg-b4ty3IL7GqXXgIRo .image-shape .label,#mermaid-svg-b4ty3IL7GqXXgIRo .icon-shape .label{text-align:center;}#mermaid-svg-b4ty3IL7GqXXgIRo .node.clickable{cursor:pointer;}#mermaid-svg-b4ty3IL7GqXXgIRo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-b4ty3IL7GqXXgIRo .arrowheadPath{fill:#333333;}#mermaid-svg-b4ty3IL7GqXXgIRo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-b4ty3IL7GqXXgIRo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-b4ty3IL7GqXXgIRo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-b4ty3IL7GqXXgIRo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-b4ty3IL7GqXXgIRo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-b4ty3IL7GqXXgIRo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-b4ty3IL7GqXXgIRo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-b4ty3IL7GqXXgIRo .cluster text{fill:#333;}#mermaid-svg-b4ty3IL7GqXXgIRo .cluster span{color:#333;}#mermaid-svg-b4ty3IL7GqXXgIRo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-b4ty3IL7GqXXgIRo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-b4ty3IL7GqXXgIRo rect.text{fill:none;stroke-width:0;}#mermaid-svg-b4ty3IL7GqXXgIRo .icon-shape,#mermaid-svg-b4ty3IL7GqXXgIRo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-b4ty3IL7GqXXgIRo .icon-shape p,#mermaid-svg-b4ty3IL7GqXXgIRo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-b4ty3IL7GqXXgIRo .icon-shape .label rect,#mermaid-svg-b4ty3IL7GqXXgIRo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-b4ty3IL7GqXXgIRo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-b4ty3IL7GqXXgIRo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-b4ty3IL7GqXXgIRo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ✅ 是
❌ 否
请求到达
有 header

x-version: v2?
app-v2 (金丝雀)
app-v1 (稳定版)

Gateway API 等效 :直接在 HTTPRoute 中使用 weight

yaml 复制代码
backendRefs:
- name: app-v1
  port: 80
  weight: 90
- name: app-v2
  port: 80
  weight: 10

限流:保护后端服务

yaml 复制代码
metadata:
  annotations:
    # 每秒每 IP 最多 2 次请求
    nginx.ingress.kubernetes.io/limit-rps: "2"
    # burst = rate × multiplier,设为 1 即 burst=2
    nginx.ingress.kubernetes.io/limit-burst-multiplier: "1"

超过限制后返回 503 Service Temporarily Unavailable

Ingress 注解 vs Gateway API 对照表

功能 Ingress 注解 Gateway API
TLS spec.tls + Secret Gateway listeners.tls + HTTPRoute
Rewrite rewrite-target annotation HTTPRoute filters.URLRewrite
金丝雀(header) canary-by-header annotation HTTPRoute matches.headers
金丝雀(权重) canary-weight annotation HTTPRoute backendRefs.weight
限流 limit-rps annotation 需 Controller 特定扩展

动手实验

配套实验位于 docs/labs/beginner/ingress-production/

步骤 1:部署实验环境

bash 复制代码
cd docs/labs/beginner/ingress-production
bash setup.sh

步骤 2:验证 TLS 终止

bash 复制代码
# 查看 TLS 配置
kubectl describe ingress app-tls

# 用 -k 忽略自签名证书验证
curl -k https://localhost/

步骤 3:验证 Rewrite

bash 复制代码
# 请求 /app/api/hello → 后端收到 /hello(用 -k 跳过自签名证书验证)
curl -k https://localhost/app/api/hello
# 预期输出:API Response

步骤 4:验证金丝雀灰度

bash 复制代码
# 不带 header → v1(稳定版)
curl -k https://localhost/
# 预期输出:Hello from v1

# 带 header → v2(金丝雀版本)
curl -k -H "x-version: v2" https://localhost/
# 预期输出:Hello from v2 (Canary!)

步骤 5:验证限流

bash 复制代码
# 快速发送 20 个请求(限流配置:每秒 2 次,burst=2)
for i in $(seq 1 20); do curl -k -s -o /dev/null -w "%{http_code} " https://localhost/; done
echo ""
# 预期:前几个返回 200,后面的返回 503(限流)

步骤 6:清理

bash 复制代码
bash teardown.sh

自检问题

  1. 基础 Ingress 上配置 TLS 后,流量从客户端到后端的加密范围是什么?

  2. 理解 rewrite-target: /$2$2 是什么意思?如果不加 rewrite 注解,/api/users 的请求到了后端路径是什么?

  3. 应用 你需要发布一个新版本,只想让 QA 团队验证。用什么方式做灰度最合适?为什么?

查看答案

  1. TLS 的加密范围是客户端到 Ingress Controller(边缘终止 / Edge Termination)。Ingress 持有证书,解密 TLS 后以明文 HTTP 转发给后端 Pod。后端 Pod 不需要处理 TLS。这就是"TLS 终止"------加密在 Ingress 这里终止了。如果需要端到端加密(客户端 → Ingress → Pod 全程 HTTPS),可以配置 SSL Passthrough 或让后端也配置 TLS。

  2. $2 是正则表达式的第二个捕获组 。在 path: /api(/|$)(.*) 中,(/|$)$1(匹配 / 或结尾),(.*)$2(匹配路径剩余部分)。例如 /api/users$1 = /$2 = users,rewrite 后变成 /users。如果不加 rewrite 注解,/api/users 到达后端的路径就是 /api/users------后端需要在路由中处理 /api 前缀,不方便。

  3. 基于 header 的金丝雀灰度 最合适。让 QA 团队在浏览器或测试工具中带上特定 header(如 x-team: qa),只有他们的请求路由到新版本,其他用户完全不受影响。这比基于权重的金丝雀更精确------QA 可以反复测试新版本,而不用担心把普通用户随机分流到可能不稳定版本。

📚 本文来自 K8s Guide ------ 开源免费的 Kubernetes 中文学习指南

  • 🗺️ 初学者轨道 + 面试轨道,从零基础到拿 Offer 一站式覆盖
  • 🧪 每篇文章配套 Kind 实验脚本,本地一键运行
  • 🔗 本文源码:docs/beginner/20-gateway-api.md
  • ⭐ 如果对你有帮助,欢迎 Star! github.com/callmebg/k8s-guide
相关推荐
Dawn-bit2 小时前
Linux日志处理三剑客之基础篇:(基础正则+扩展正则)
linux·运维·服务器·正则表达式·云计算·运维开发
暗影凋落2 小时前
docker-image 工具展示更详细镜像层内容
运维·docker·容器
深圳市爱派派智能科技有限公司2 小时前
“进迭时空 RISC-V 集群服务器 CSB1-N10SPK3:10 节点 K3,600 TOPS 绿色算力“
运维·服务器·risc-v·k3·进迭时空·集群服务器
☆凡尘清心☆2 小时前
Linux运维故障排查速查命令清单
linux·运维·服务器
极客先躯2 小时前
高级java每日一道面试题-2026年05月11日-实战篇[Docker]-如何容器化金融产品推荐系统?
java·运维·docker·容器·金融·高级面试·金融产品推荐系统
nvd112 小时前
GCP L4 Passthrough 负载均衡器“假死超时”深度排查复盘
运维·php·负载均衡
qeen872 小时前
【Linux】make/Makefile 自动化工具的介绍
linux·运维·服务器·自动化
朱容zr3331332 小时前
为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?
java·运维·数据库·后端·mysql·面试·性能优化
HXDGCL2 小时前
东莞市华创力科技:专业环形导轨工厂,助力自动化产线升级
运维·科技·自动化