Ingress NGINX Controller 自定义错误页面完整指南:基于自定义 default-backend 的 Custom Errors 实战
2026/9/13 14:49:42 网站建设 项目流程

Ingress NGINX Controller 自定义错误页面完整指南:基于自定义 default-backend 的 Custom Errors 实战

【免费下载链接】ingress-nginxIngress NGINX Controller for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/in/ingress-nginx

导读

本文基于 Ingress NGINX Controller 仓库中的官方示例 custom-errors README,系统讲解如何用自定义 default-backend 服务渲染自定义错误页面:包括 Helm Chart 与手动部署两种方式、custom-http-errors配置的底层原理、curl 验证方法,以及用 503 维护页面对整集群做计划内停机。读完本文,你将掌握从部署、配置到源码级验证的完整闭环,并可直接复用仓库提供的三份 YAML 清单完成落地。


一、方案原理:错误码如何被"劫持"到自定义后端

默认情况下,当 Ingress 后端返回 4xx/5xx 错误时,NGINX 会返回一个简单的错误页。Ingress NGINX Controller 提供custom-http-errors配置,可让指定错误码不再由 NGINX 直接渲染,而是转发给自定义的 default-backend 服务,由该服务根据请求的Accept头返回 HTML、JSON 等自定义响应。

从 NGINX 配置模板 rootfs/etc/nginx/template/nginx.tmpl 可以看到其底层实现:

  • 全局 http 层(第 493-502 行):当设置了CustomHTTPErrors且未禁用DisableProxyInterceptErrors时,开启proxy_intercept_errors on;,并为每个错误码生成error_page {{ $errCode }} = @custom_upstream-default-backend_{{ $errCode }};,将错误响应内部重定向到 default-backend 上游;
  • location 层(第 1399-1405 行):如果某个 Ingress 通过注解单独指定了错误码,则在该 location 内同样开启proxy_intercept_errors on;并生成error_page {{ $errCode }} = @custom_{{ $location.DefaultBackendUpstreamName }}_{{ $errCode }};,实现按 Ingress 粒度的错误页覆盖。

也就是说,这套机制同时支持"全局错误页"和"单条 Ingress 的错误页覆盖"两种粒度。

二、前置条件:准备一个可用的 Ingress Controller

开始之前,请确保集群中已部署 Ingress NGINX Controller。若尚未部署,请参考官方部署指南完成安装。

仓库的示例资源位于 docs/examples/customization/custom-errors/,共包含三份关键文件,下文将逐一讲解:

文件用途
custom-default-backend.yaml手动部署方式:自定义错误后端(Service + Deployment)
custom-default-backend-error_pages.configMap.yaml自定义 404/503 错误页内容的 ConfigMap
custom-default-backend.helm.values.yamlHelm Chart 部署方式使用的 values 片段

三、方式一:使用 Helm Chart 部署自定义错误页(推荐)

如果控制器是通过 Helm Chart(charts/ingress-nginx)安装的,最省事的方式是复用仓库提供的 values 文件 custom-default-backend.helm.values.yaml,内容如下:

controller: config: custom-http-errors: "404,503" defaultBackend: enabled: true image: registry: registry.k8s.io image: ingress-nginx/custom-error-pages tag: v1.2.9@sha256:203d3020005dbdd735c1ad51f238d8663b9851399b52cc0c9c9e3f7273b6b299 extraVolumes: - name: custom-error-pages configMap: name: custom-error-pages items: - key: "404" path: "404.html" - key: "503" path: "503.html" extraVolumeMounts: - name: custom-error-pages mountPath: /www

要点说明:

  • controller.config.custom-http-errors: "404,503":等价于 ConfigMap 中的custom-http-errors键,告诉控制器哪些错误码要走自定义错误页;
  • defaultBackend.enabled: true:启用 Chart 内置的 default-backend,并替换为registry.k8s.io/ingress-nginx/custom-error-pages:v1.2.9镜像;
  • extraVolumes/extraVolumeMounts:将上面提到的custom-error-pagesConfigMap 挂载到容器/www目录,即自定义错误页的渲染根目录;
  • 别忘了同时创建ConfigMap custom-default-backend-error_pages.configMap.yaml,否则 Volume 挂载会因找不到 ConfigMap 而失败。其内容为:
apiVersion: v1 kind: ConfigMap metadata: name: custom-error-pages data: 404: | <!DOCTYPE html> <html> <head><title>PAGE NOT FOUND</title></head> <body>PAGE NOT FOUND</body> </html> 503: | <!DOCTYPE html> <html> <head><title>CUSTOM SERVICE UNAVAILABLE</title></head> <body>CUSTOM SERVICE UNAVAILABLE</body> </html>

注意:ConfigMap 中data的键名(404503)对应 HTTP 状态码,通过items映射为404.html503.html写入挂载目录,custom-error-pages 镜像会根据请求状态码在/www下查找同名文件渲染页面。你也可以把键改为其他 400-599 的错误码,只需保持与custom-http-errors列表一致。

四、方式二:手动部署自定义 default-backend

如果不使用 Helm,可按原文档的手动流程操作。

4.1 创建自定义错误后端

使用仓库提供的 custom-default-backend.yaml 创建资源:

$ kubectl create -f custom-default-backend.yaml service "nginx-errors" created deployment.apps "nginx-errors" created

该文件包含一个 Service 和一个 Deployment,二者均名为nginx-errors。核心定义如下:

apiVersion: v1 kind: Service metadata: name: nginx-errors labels: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx spec: selector: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx ports: - port: 80 targetPort: 8080 name: http --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-errors labels: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx spec: containers: - name: nginx-error-server image: registry.k8s.io/ingress-nginx/custom-error-pages:v1.2.9@sha256:203d3020005dbdd735c1ad51f238d8663b9851399b52cc0c9c9e3f7273b6b299 ports: - containerPort: 8080 # Setting the environment variable DEBUG we can see the headers sent # by the ingress controller to the backend in the client response. # env: # - name: DEBUG # value: "true" # Mounting custom error page from configMap # volumeMounts: # - name: custom_error_pages # mountPath: /www # Mounting custom error page from configMap # volumes: # - name: custom_error_pages # configMap: # name: custom_error_pages # items: # - key: "404" # path: "404.html" # - key: "503" # path: "503.html"

几点值得注意:

  • 镜像使用registry.k8s.io/ingress-nginx/custom-error-pages:v1.2.9(含 SHA256 摘要以保证可复现性),该镜像即仓库images/custom-error-pages/目录下构建的官方错误页服务;
  • 调试技巧:取消注释DEBUG=true环境变量,即可在客户端响应中看到 Ingress Controller 转发给后端时携带的请求头,便于排查问题;
  • 自定义页面:取消注释volumeMountsvolumes两段,即可把前面创建的custom-error-pagesConfigMap 挂载到/www,用你自己的 HTML 替换默认错误页。

验证创建结果:

$ kubectl get deploy,svc NAME DESIRED CURRENT READY AGE deployment.apps/nginx-errors 1 1 1 10s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/nginx-errors ClusterIP 10.0.0.12 <none> 80/TCP 10s

此时集群中已有一个名为nginx-errors的 Deployment 和 Service。

4.2 配置 Ingress Controller

按原文档的指引,需要完成以下三步:

  1. 指定默认后端:编辑ingress-nginx-controller的 Deployment,将启动参数--default-backend-service的值设置为新创建的错误后端,格式为namespace/service-name(例如default/nginx-errors);
  2. 声明错误码:编辑ingress-nginx-controller的 ConfigMap,添加键custom-http-errors,值为404,503(多个错误码用逗号分隔,也支持404, 500这类带空格写法,源码解析时会自动去除空白);
  3. 记录 Service 地址:查看 Ingress Controller 的 Service IP,后续 curl 测试会用到:
$ kubectl get svc ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx ClusterIP 10.0.0.13 <none> 80/TCP,443/TCP 10m

说明:示例中ingress-nginxService 类型为ClusterIP,实际环境可能是LoadBalancerNodePort。无论哪种类型,请确保能通过该 Service 访问到 NGINX 后再继续后续步骤。

五、源码级原理:custom-http-errors 的解析与校验

custom-http-errors既可作为ConfigMap 全局配置(本文场景),也可以作为Ingress 注解按规则覆盖。其解析实现在 internal/ingress/annotations/customhttperrors/main.go,关键逻辑如下:

  • 注解名常量custom-http-errors,属于backend组、作用域为location、风险等级Low
  • 校验正则^(?:[4,5]\d{2},?)*$只接受 400-599 之间的错误码,且必须为逗号分隔(如403,503),非法值会直接报错;
  • Parse方法将逗号分隔的字符串按逗号切分、TrimSpace去除空白后逐个strconv.Atoi转为整数,最终返回[]int错误码列表。因此"404, 503""404,503"均合法,而包含非数字(如abc)则解析失败。

对应测试 customhttperrors/main_test.go 验证了:

  • 合法输入400,404,500,502可正常解析;
  • 非法输入400,404,abc,502会返回错误。

此外,internal/ingress/annotations/annotations_test.go 的TestCustomHTTPErrors也覆盖了"404,415"[404, 415]、空字符串 →[]等边界场景。

关于错误转发到哪个后端,可结合两个注解的文档说明理解:

  • defaultbackend/main.go 中的default-backend注解(组backend、作用域location、风险Low):该 Service 用于处理 Ingress 规则中配置的 Service没有可用端点时的响应;如果同时设置了default-backendcustom-http-errors注解,错误响应会转发给该注解指定的 Service
  • customhttperrors/main.go 的文档说明:如果 Ingress 上指定了default-backend注解,则custom-http-errors列出的错误码转发到该注解指定的后端;否则转发到全局 default-backend(即--default-backend-service指向的服务)。

补充:仓库还提供了 disableproxyintercepterrors/main.go 中的disable-proxy-intercept-errors注解,用于在设置了custom-http-errors时显式关闭 NGINX 的proxy_intercept_errors,可按需查阅。

六、验证错误页:curl 实战测试

配置完成后,用 cURL 对 Ingress Controller Service 发起请求验证。

场景 1:请求到默认后端,返回自定义 404 页面

$ curl -D- http://10.0.0.13/ HTTP/1.1 404 Not Found Server: nginx/1.13.12 Date: Tue, 12 Jun 2018 19:11:24 GMT Content-Type: */* Transfer-Encoding: chunked Connection: keep-alive <span>The page you're looking for could not be found.</span>

场景 2:携带Accept: application/json,返回 JSON 格式错误体

$ curl -D- -H 'Accept: application/json' http://10.0.0.13/ HTTP/1.1 404 Not Found Server: nginx/1.13.12 Date: Tue, 12 Jun 2018 19:12:36 GMT Content-Type: application/json Transfer-Encoding: chunked Connection: keep-alive Vary: Accept-Encoding { "message": "The page you're looking for could not be found" }

可以看到,custom-error-pages 后端会根据客户端的Accept头协商响应格式(HTML、JSON 等),这正是"自定义错误页"在前后端分离架构下特别有价值的原因——前端可以直接消费结构化错误体。

进一步验证:部署你自己的应用与 Ingress 对象,然后将某个 Deployment 的副本数缩到 0,请求该服务应返回 503,且响应体同样为自定义错误格式。这可以验证"后端无可用端点 → 返回 503 → 自定义错误页接管"的完整链路(default-backend注解的文档正是这么描述的:用于处理配置的 Service 无可用端点时的响应)。

七、进阶玩法:集群级"服务维护中"页面

custom-http-errors还有一个实用场景:为整个集群设置"服务维护中"页面,在计划性维护期间阻止用户访问业务。

实现步骤(按原文档):

  1. 为 503 启用自定义错误页:按前文步骤,在custom-http-errors中加入503,并确保自定义后端能渲染 503 页面;
  2. 停止读取 Ingress 资源:将ingress-nginx-controller的启动参数--watch-namespace-selector设置为一个不存在的命名空间(例如nonexistent-namespace)。这样控制器不会从任何命名空间读取 Ingress 资源,业务流量自然无法被路由;
  3. 强制返回 503:给控制器 ConfigMap 配置location-snippet: return 503;(或在对应 location 中注入该片段),让 NGINX 对所有请求都返回 503 错误码。

由于custom-http-errors已包含 503,所有请求都会命中自定义错误页,客户端将看到统一风格的维护页面,同时 HTTP 状态码保持标准的 503 Service Unavailable,便于监控与客户端识别。

原文档提示:--watch-namespace-selector指向不存在命名空间,本质上是"清空"控制器监听的 Ingress 集合;维护结束后恢复原值即可正常服务。执行维护前建议先在测试环境演练一遍,确认错误页与状态码符合预期。

八、相关资源与进一步阅读

  • 示例资源目录:docs/examples/customization/custom-errors/
  • 手动部署清单:custom-default-backend.yaml
  • Helm values:custom-default-backend.helm.values.yaml
  • 错误页 ConfigMap:custom-default-backend-error_pages.configMap.yaml
  • 默认后端概念:default-backend.md
  • 注解参考(含custom-http-errorsdefault-backenddisable-proxy-intercept-errors):annotations.md
  • ConfigMap 配置项说明:configmap.md
  • 控制器部署文档:deploy/index.md

如需继续深入源码,可阅读 customhttperrors/main.go(解析逻辑)、customhttperrors/main_test.go(解析测试)、defaultbackend/main.go(默认后端注解)、nginx.tmpl(proxy_intercept_errorserror_page的生成逻辑),以及 config.go 中CustomHTTPErrors的默认空切片定义(第 874 行附近)。

【免费下载链接】ingress-nginxIngress NGINX Controller for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/in/ingress-nginx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询