写在最前

1. 前置条件

  1. Kubernetes 构建指南:二进制部署 v1.21.10

2. 部署流程

2.1 下载安装

我的版本比较低是1.21.x,要注意你的kubernetes版本是否对应上否则会安装失败,ingress-nginx镜像源下载不了我换成国内的了 my-ingress-nginx-v1.3.1.yaml

https://github.com/kubernetes/ingress-nginx

# 下载
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.1/deploy/static/provider/cloud/deploy.yaml

# 将 externalTrafficPolicy: Local 改成 Cluster 允许所有节点都能访问
346   externalTrafficPolicy: Local

# 留意是不是LoadBalancer,因为要搭配metallb或openELB来使用
365   type: LoadBalancer

可以看到metalLB或者openELB提供的IP已经被ingress-nginx识别到了

image-nbbc.png

2.2 配置优化

3. 维护页面

如需临时进入维护状态只需要将~/hello中的hello给删掉即可维护完毕再加回hello,即可在不影响原服务容器运行的前提下,阻止外部流量访问前端服务,同时向用户展示维护提示页。

kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: xxxxxxx
  namespace: xxxxxxx
  annotations:
    kubernetes.io/ingress.class: nginx
    kubesphere.io/creator: tanqidi
    nginx.ingress.kubernetes.io/server-snippet: >-
      location ~/hello { default_type text/html; return 200 '<!DOCTYPE html><html
      lang="zh-CN"><head><meta charset="UTF-8"/><meta name="viewport"
      content="width=device-width,initial-scale=1"/><title>系统维护中</title><style>body{margin:0;background:#f0f4f8;color:#2c3e50;font-family:"Helvetica
      Neue",Helvetica,Arial,sans-serif;display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;text-align:center;}svg{width:72px;height:72px;margin-bottom:24px;stroke:url(#grad);stroke-width:1.8;fill:none;stroke-linecap:round;stroke-linejoin:round;}h1{font-weight:700;font-size:2.8rem;margin:0
      0 12px;}p{margin:0 0
      28px;font-size:1.2rem;line-height:1.5;color:#34495e;}a{color:#2980b9;font-weight:600;text-decoration:none;box-shadow:inset
      0 -2px 0 #2980b9;transition:box-shadow 0.3s,color
      0.3s;}a:hover{box-shadow:none;color:#1c5980;}</style></head><body><svg
      xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24
      24"><defs><linearGradient id="grad" x1="0" y1="0" x2="1" y2="1"><stop
      offset="0%" stop-color="#3498db"/><stop offset="100%"
      stop-color="#2980b9"/></linearGradient></defs><circle cx="12" cy="12"
      r="9"/><path d="M12 8v4l3
      3"/></svg><h1>系统维护中</h1><p>我们正在努力升级服务,请稍后再访问。感谢您的理解与支持!</p><a href="#"
      onclick="location.reload()">刷新页面</a></body></html>'; }

image-pWBg.png

4. 功能变更

4.1 启用server-snippet

https://github.com/kubernetes/ingress-nginx/issues/13003?utm_source=chatgpt.com

编辑configmap加入如下配置

kind: ConfigMap
apiVersion: v1
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.13.0
data:
  allow-snippet-annotations: 'true'
  annotations-risk-level: Critical

同时ingress-nginx-controller启动参数加入--enable-annotation-validation=false

为什么 ingress-nginx 默认禁止 snippet 注解,但很多实际业务场景又确实离不开它。


🔒 为什么默认禁止 snippet 注解?

  1. 安全风险太大

    • configuration-snippetserver-snippetlocation-snippet 允许你把 任意 NGINX 配置片段 注入到 Ingress Controller 的 NGINX 配置里。

    • 这意味着开发人员或者业务方只要能创建 Ingress,就能在 NGINX 里写出任意指令,甚至可能影响整个集群的其他应用。

    • 举例:一个人加一段

      location /hack {
        proxy_pass http://malicious-service;
      }
      

      就可能绕过认证或数据隔离。

  2. CVE 漏洞历史

    • 社区里出现过多次漏洞(比如 2024、2025 年的 CVE-2025-1974),核心点就是通过 snippet 插入危险配置,从而绕过 Admission 校验。

    • 为了防御这些“风险注解”,从 1.12.0 开始 Admission Webhook 默认拦截,要求管理员显式放行。

  3. 多租户场景尤其危险

    • 在很多 K8s 集群里,一个团队一个 namespace。

    • 如果默认允许 snippet,等于把 NGINX 控制权交给了租户,这对运维是不可接受的。


🏗️ 为什么实际业务确实需要?

  1. 标准 annotation 覆盖不了所有需求

    • nginx.ingress.kubernetes.io/* 提供了几十种常见功能(rewrite、timeout、auth 等),但远远不够。

    • 业务方经常需要用到一些 小众但关键的 NGINX 功能,比如:

      • 自定义 header

      • 特殊 rewrite 规则

      • 缓存 / 限流 / Lua 脚本

    • 这些功能官方 annotation 没有覆盖,snippet 就成了唯一出口。

  2. 迁移历史遗留配置

    • 很多团队早期在 VM 或裸机里直接写了 NGINX 配置。

    • 上 K8s 后,最简单的方式就是直接贴进 snippet,而不是花很久改造成 annotation。

  3. 调试 / 应急手段

    • 出现紧急问题时,直接在 snippet 里写几行配置,比等 upstream 提供新的 annotation 快多了。


✅ 社区给的折中方案

  • 默认禁用:保证安全。

  • 集群管理员决定是否启用:通过

    allow-snippet-annotations: "true"
    annotations-risk-level: "Critical"
    

    或者关闭 Admission 校验。

  • 未来方向:社区建议把常用的 snippet 功能,逐步收敛为官方 annotation,这样既安全又可控。


📌 总结:

  • 默认禁止 👉 为了安全(防止越权 / 漏洞)。

  • 实际需要 👉 因为 annotation 功能有限,业务确实要灵活性。

  • 折中做法 👉 管理员显式开启,并通过 risk-level 控制,确保只有“知道后果的人”能用。